Buzeli
buzeliSoluções Digitais
Security

141 OWASP rules active, zero false positives: configuring OCI WAF for WordPress

Published on March 24, 2026

141 regras OWASP ativas, zero falsos positivos — WAF OCI para WordPress de alto tráfego

The starting point

During the migration of a high-traffic WordPress portal from AWS to OCI, one of the first tasks was recreating the WAF protection that existed on AWS (WebACL with OWASP rules + custom rules). OCI offers a WAF integrated into the Load Balancer at no extra cost in the basic tier — which would save $271/month compared to AWS.

The challenge isn't enabling the WAF. It's enabling all 141 OWASP rules without breaking anything in production.

OWASP rules block patterns. High-traffic WordPress sites generate patterns that look like attacks — analytics cookies, URL parameters with special characters, authentication headers. Without fine-tuning, the false positive rate is high.

OCI WAF architecture

OCI WAF operates in two independent pipelines — understanding this is critical to getting the configuration right:

Request Access Control: rules that ALLOW or BLOCK based on conditions like IP, geo, headers, cookies. Evaluated first.

Request Protection (OWASP): the 141 capabilities that inspect request content for SQLi, XSS, LFI, RFI, and other malicious patterns. Evaluated independently of Access Control.

An ALLOW rule in Access Control does NOT prevent Protection Rules from inspecting the request. The two pipelines are completely independent.

This was the most important discovery in the entire configuration: Access Control ALLOW does not bypass OWASP. For conditional bypass, the condition must be placed on the Protection Rule itself.

The 141 OWASP rules

OCI WAF's OWASP capabilities cover the main attack categories:

942xxx — SQL Injection (SQLi): detection of SQL payloads in args, headers, and cookies.

941xxx — Cross-Site Scripting (XSS): detection of injected scripts anywhere in the request.

930xxx — Local File Inclusion (LFI): detection of path traversal and local file access attempts.

931xxx — Remote File Inclusion (RFI): detection of remote file inclusion via URL in parameters.

All 141 capabilities were activated in BLOCK mode from the start. Then the real work began: identifying and resolving false positives before pointing real traffic at it.

The false positives we found

1. Analytics cookies triggering SQLi rules

The biggest problem was immediate: cookies from analytics tools (Google Analytics, Facebook Pixel, TikTok Ads, and others) contain values with special character patterns — dollar signs, hyphens, number sequences — that OWASP CRS classifies as possible SQL Injection.

A cookie with a value like `-1234-5678.90-` looks, to the 942xxx rules, like an SQLi fragment with numeric operators. The same logic applies to JSON-encoded values in consent tool cookies (Privaci, OneTrust, and similar).

Fix: 42 cookies were added to the exclusion list across all 141 capabilities. This instructs the WAF not to inspect the values of those specific cookies, while maintaining protection on all other fields.

2. The Next.js Image `?url=` parameter

The `/_next/image?url=https://...` endpoint uses a parameter called `url` containing a full URL. The 931xxx (RFI) and 930xxx (LFI) rules detect URLs in parameters as indicative of remote file inclusion — technically correct as a pattern, but a false positive for this legitimate endpoint.

Fix: The `url` argument was excluded from SQLi (942xxx), RFI (931xxx), and LFI (930xxx) rules. Accepted and documented risk: if an attacker sends an SQLi payload specifically in the `url` parameter, the WAF would not block it.

3. Logged-in WordPress users

WordPress administrators and editors carry authentication cookies (`wordpress_logged_in_*` and `wordpress_sec_*`) whose values are base64 hashes containing characters that OWASP rules interpret as potential attacks. Result: logged-in users were being blocked when navigating wp-admin.

The correct solution isn't to exclude the cookies — it's to conditionally bypass the entire OWASP pipeline when the user is authenticated. And here came the subtlest trap in OCI WAF.

The trap: how to conditionally bypass OWASP

The intuitive approach is to create an ALLOW rule in Access Control when the `wordpress_logged_in_*` cookie is present, expecting it to let those requests pass without OWASP inspection. That doesn't work — the pipelines are independent, as explained above.

The correct approach is to add a condition directly on the OWASP Protection Rule, instructing the WAF to only apply the rules when the condition is true (user is not authenticated).

The condition that works:

Copy
!contains(to_string(keys(http.request.cookies)), 'wordpress_logged_in_')

Translation: apply the OWASP rule only when the list of cookie names does NOT contain the `wordpress_logged_in_` prefix. Since the hash suffix of the cookie varies per installation, prefix matching via `contains()` on the concatenated string of cookie names is the only portable approach.

Warning: `http.request.headers.cookie` doesn't work as a string in OCI WAF runtime, even though the API accepts the configuration. Always use `http.request.cookies` (the parsed cookie map) with `keys()` to access cookie names.

Integration with the OKE Load Balancer

In OCI, when the OKE cluster provisions a Load Balancer via the Cloud Controller Manager (CCM), the WAF Policy must be attached to that LB — not to a manually created LB. Attempts to create a separate LB for WAF and put the CCM LB behind it result in unnecessary complexity and routing issues.

Correct flow: Internet → OCI WAF Policy (attached to CCM LB) → OKE Nodes → Pods.

An important detail when using Nginx inside pods behind this LB: `$binary_remote_addr` becomes the Load Balancer IP, not the real client IP. This breaks any IP-based rate limiting.

Nginx fix: add `set_real_ip_from` with the LB subnet CIDRs and `real_ip_header X-Forwarded-For`. Without this, all clients share the same rate limit bucket.

Parity with AWS WAF

After the full configuration, we compared the OCI WAF against the WebACL that existed on AWS. The result was full parity on the protections that mattered:

OWASP Core Rule Set: equivalent on both platforms.

Bypass for authenticated users: implemented via condition on OCI, via custom rule on AWS.

IP Reputation List: absent in OCI free tier, compensated by CrowdSec installed on the WordPress VM — which blocks malicious IPs based on collective intelligence.

The result

141 OWASP rules active in production. Zero false positives for end users. Zero for WordPress editors and administrators. SQLi, XSS, LFI, and RFI blocked. Cost: $0/month (included in OCI Flexible Load Balancer).

The fine-tuning work took about two days. It's an investment worth making: a WAF with aggressive but poorly calibrated rules is worse than no WAF — it blocks legitimate users and erodes trust in the tool.

WAF isn't flipping a switch. It's continuous calibration between protection and usability. Done right, it's invisible to the user and impenetrable to the attacker.