Security · Azure · WAF

Before Flipping the WAF to Prevention: Telling False Positives From Real Attacks

A web application firewall in prevention mode blocks whatever its rules match, including your own customers. Before we turned blocking on across 65+ brand sites, I had to prove which alerts were noise and which were real attacks.

The switch you can't just flip

Our Azure web application firewall had been running in detection mode, which logs what it would have blocked without blocking anything. The goal was prevention mode, where those rules actually stop requests.

The risk is simple: if a rule misfires on normal traffic, prevention mode blocks real customers on 65+ brand sites at once. So before anything changed, someone had to go through the detection logs and answer one question for every noisy rule: is this an attack, or is this us?

That was my part. I did the testing, log analysis, and recommendations. Our network team owned the WAF configuration and made the actual changes, and we planned the rollout environment by environment, from integration through QA to production.

Three buckets, and a rule about evidence

I sorted every finding into one of three buckets, and I held myself to one rule: nothing gets called a false positive without looking at the actual requests behind it. A pattern that looks harmless in a summary can be hiding real attack traffic.

That rule mattered, because an exclusion is a hole in the firewall. Calling something a false positive is a decision to stop inspecting it.

Detection-mode alert
        ↓
Inspect the actual requests behind it
        ↓
  ├─ Confirmed malicious        → keep the rule as is
  ├─ Likely false positive      → only with request-level evidence
  └─ Indeterminate              → keep investigating

Normal traffic that looked suspicious

The detection logs turned up a few issues that would have blocked ordinary visitors the moment blocking was turned on. Everyday things like third-party cookies and perfectly normal files were tripping rules meant for attackers.

None of them were attacks. All of them would have looked like the website was broken to a real customer.

The million-alert pattern

The biggest finding was a group of SQL injection rules firing over a million times in two days across the portfolio. The first theory was search boxes: users typing things that look like SQL.

The data said otherwise. About 99.9% of the matches came from cookies, not search parameters or form fields. Several third-party analytics and accessibility tools store their settings as JSON in cookies, and JSON punctuation can look a lot like the obfuscation tricks attackers use to sneak SQL past a filter.

I decoded the cookie values to confirm they were harmless settings, not payloads. Then I recommended the narrowest fix I could: exclude only those specific cookies, only from the specific SQL injection rules they were tripping, using the WAF's existing exclusion feature. Every other rule keeps inspecting those cookies, and every other cookie keeps getting inspected by those rules.

I'm deliberately not listing the cookie names or exact rules here. Publishing exactly what a firewall doesn't inspect is a map for an attacker.

The one that looked like a false positive and wasn't

On one site, a rule was blocking a lot of traffic, and there was a reasonable theory that a consent-management cookie was triggering it. If that were true, an exclusion would have been the fix.

Instead of trusting the theory, I went through every request where that rule fired over a week: all 2,253 of them. Not one was caused by the cookie alone. The traffic was real bots and scanners probing for restricted files, hunting for credentials and config files, and attempting command injection.

So the recommendation was no exclusion. The rule was doing its job. If we had acted on the plausible explanation, we would have opened a hole for exactly the traffic the firewall exists to stop.

What this reinforced

  • A plausible theory is not evidence. Check the actual requests.
  • An exclusion is a security decision, so keep it as narrow as possible.
  • Volume isn't severity. A million harmless matches can hide a few thousand real attacks.
  • Be precise about roles. Analysis and configuration were different jobs, done by different teams, and the work was better for it.
  • Don't publish the details of your own defenses.

Why this one stuck with me

This project is a big part of why I'm moving toward cloud and application security. The work felt a lot like debugging production: form a model of what should be happening, then follow the evidence to where reality disagrees.