Scanning and Tools

How a WAF Changes What Your Web Scanner Reports

22 September 2026 8 min read

A scan that comes back clean against an internet-facing application does not always mean the application is clean. If a web application firewall sits in front of the target, some fraction of the payloads a scanner sends never reach the code that would have reacted to them. The WAF answers on the application’s behalf, and depending on how it answers, the scanner records the result as “not vulnerable” rather than “not tested.” That distinction rarely shows up in the final report, and it is the main reason an external scan and a scan run from behind the WAF against the same application can produce very different vulnerability counts.

Three WAF behaviours that distort scans: block, throttle, and silent sanitisation

Most WAFs interfere with a scan in one of three ways, and each one produces a different kind of blind spot.

  • Block. The WAF matches a request signature and returns a 403, 406, or 503 with a block page instead of forwarding the request. A default ModSecurity install running the OWASP Core Rule Set at paranoia level 1, for example, blocks once an inbound anomaly score crosses the threshold (5 by default), so a single request carrying a classic ‘ OR ‘1’=’1 string trips the rule before the application ever parses it.
  • Throttle. Past a request-rate threshold, commonly somewhere between 60 and 120 requests per minute per source IP on cloud WAFs, the WAF starts returning 429s or, more subtly, holding connections open for an extra second or two before responding. A scanner running with high concurrency can hit this ceiling within the first few hundred requests of a crawl, long before it reaches the parameters that matter.
  • Silent sanitisation. The WAF strips or re-encodes the dangerous part of the payload, a stray quote, an angle bracket, a null byte, and forwards a defanged request to the real application. The application answers normally, with a 200 status and a normal-looking body, because from its point of view nothing unusual arrived. The scanner sees a completed, uneventful test and marks the check as passed.

The third behaviour is the most dangerous of the three because nothing in the transaction looks like an error: no timeout, no reset, no unusual status code. The application itself generated the response the scanner is reading.

Why blocked payloads read as clean results instead of errors

Scanners decide whether a check passed or failed by comparing the response to an expected signal: an error string for a SQL injection probe, a reflected payload for XSS, an artificial delay for a time-based blind check. When a WAF intercepts the request, the response it hands back rarely contains that signal, so the check is scored as negative. Whether the scanner treats that negative as “no vulnerability” or “test inconclusive” depends entirely on whether it recognizes the response as a block page in the first place.

Many scanners establish a baseline by sending a benign request before the test suite runs, then diff every later response against it. That catches an obvious block page with a fixed template and a distinct content length. It does not catch a WAF that returns a generic 200 page rather than a 403, since some vendors deliberately tune the block response to look unremarkable rather than to announce a block, which limits information leakage to an attacker but also removes the signal a scanner needs to separate “blocked” from “tested and safe.” Boolean-based blind injection checks, which rely on a subtle content difference between a true and a false condition, are especially exposed, because a WAF returning the same generic page for both conditions collapses the diff the check depends on.

Detecting that a WAF is interfering mid-scan

Response fingerprints

Capturing every response header during a scan, not just status codes, turns up vendor tells that are easy to miss in a summary report. A cf-ray header points to Cloudflare, x-sucuri-id to Sucuri, x-iinfo or an incap_ses_ cookie to Imperva, and a Server: AkamaiGHost or x-akamai-transformed-cs to Akamai’s edge. None of these confirm that a specific test was blocked, but a fingerprint that was absent during onboarding and present mid-scan means a WAF or CDN was added, moved in front of the target, or switched into a stricter mode since the last baseline was taken.

Timing patterns

A response time that jumps from roughly 80 milliseconds to over a second, consistently, starting at a specific request count, is a rate-limit or tarpit kicking in rather than the application slowing down under load. It is also worth flagging the opposite pattern: near-identical response times across structurally different endpoints. A real backend rarely answers a static asset and a database-backed search query in the same number of milliseconds; a WAF edge answering both with a cached or templated response often does.

Status code patterns

A spike in 403 or 406 responses concentrated on parameterized requests, while static assets and unparameterized pages return normally, points to a rule matching payload characters rather than a real authorization boundary. A CAPTCHA or JavaScript challenge page returned with a 200 status and the same content length across dozens of distinct URLs is another reliable tell, since scanners that do not execute JavaScript will evaluate the challenge page itself as if it were the target page, and every check against it will read as clean.

Signal Typical source What it tells you
cf-ray header Cloudflare Traffic is passing through Cloudflare’s edge before the origin
incap_ses_ cookie Imperva Imperva has issued a session cookie, indicating active inspection
Uniform 200 + fixed content length JS challenge or CAPTCHA page Requests are being answered by a challenge, not the application
429 concentrated after N requests Rate limiting Scanner concurrency exceeded the WAF’s threshold

Scanning from behind the WAF vs allowlisting the scanner: risks of each

There are two honest ways to point a scanner at a protected application, and they answer different questions.

Scanning with the WAF fully in the path measures exposed risk, what an internet-based attacker who has not found a bypass would actually encounter. It is the right test for validating that compensating controls are configured and active. Its weakness is that it systematically under-reports code-level defects, and a team that only ever runs this configuration accumulates an invisible backlog: vulnerabilities that exist in the code but have never been recorded anywhere, because every scan of them came back clean.

Allowlisting the scanner, by IP, header, or both, so its requests bypass WAF inspection measures actual application risk, the defects that exist in the code regardless of what sits in front of it. This is the number that should drive a remediation backlog, since a WAF rule set changes, gets tuned during an incident, or gets disabled temporarily during a migration, and none of those changes touch the underlying code. The risk on this side is operational rather than analytical: an allowlist rule scoped too broadly, for instance permitting the scanner’s IP for all traffic rather than for the specific test window, becomes a standing bypass that anyone who learns or spoofs that IP can use afterward.

Keeping two result sets: exposed risk vs actual application risk

The practical answer is to run both and keep them as separate, comparable data sets rather than merging them into one number. Tag every finding with the scan context it came from, WAF-live or WAF-bypassed, and treat the difference between the two sets as information rather than noise:

  • A finding present only in the bypassed set means the WAF is currently providing compensating coverage. That lowers urgency but does not zero it out, since the control can be disabled, misconfigured, or bypassed by a payload variant later.
  • A finding present in both sets means the WAF is not covering that specific path or payload class at all. Treat it with the same urgency as if no WAF existed, because for that finding, none does.

This correlation is easy to describe and tedious to maintain by hand across dozens of scan targets and quarterly re-scans. Vulnerability management platforms that ingest output from multiple scanner integrations are better positioned for it than a single scanner’s report, because a WAF-induced false negative from one tool can be checked against a positive result from another tool run in the same window instead of being taken at face value. Some platforms, SITEY among them, tag findings automatically by the scan context they were discovered in as part of vulnerability lifecycle tracking, so the exposed-versus-actual distinction persists across re-scans instead of depending on an analyst remembering to reapply it every cycle. Mapping which internet-facing paths sit behind the WAF at all is itself part of ongoing attack surface management, since a new subdomain or API route can go live outside the WAF’s routing rules without anyone updating the inventory.

Coordinating allowlist windows with the network team without leaving a hole open

Getting a temporary bypass approved is usually the easy part. Closing it cleanly afterward is where most of the risk sits, and a few concrete practices keep the window narrow:

  1. Key the allowlist rule to more than a source IP. Pair the IP with a per-run header value, for example X-Scan-Token: <random-value-for-this-job>, so the bypass only works for requests carrying both, not for anything else that later originates from the same address.
  2. Scope the exception to the specific WAF rule groups relevant to the test, injection and XSS signature sets, rather than disabling the WAF for that source entirely. Rate limiting and bot-mitigation rules should keep running even while injection checks are allowlisted.
  3. Put explicit start and end timestamps in the change ticket, and automate the removal through the WAF vendor’s API or a scheduled job rather than relying on someone to remember to revert it manually at the end of the day.
  4. After the window closes, send one known-bad payload from the scanner’s source and confirm it gets blocked again. Log that confirmation as part of the scan record, not as a separate manual step that can be skipped under time pressure.

Whichever team owns the WAF should be the one enforcing the expiry, not the team requesting the scan, since the requester has no incentive to notice if the rule quietly outlives its window. Tooling that manages this as a workflow step, such as SITEY’s approval gates tied to a scan job’s start and end time, expires the allowlist rule when the job finishes instead of leaving the revert to someone’s calendar reminder, and keeps a record of exactly when the exception was live and when it was verified closed.

About SITEY

SITEY is an autonomous vulnerability management platform. It discovers, validates, prioritizes, remediates and re-tests vulnerabilities through an eight-phase automated pipeline, unifying output from 17 integrated scanners. SITEY is self-hosted: it runs in your own infrastructure and your findings are stored there. Outbound connections are limited to licence activation and the optional services you enable, such as an AI provider, CVE enrichment and patch catalogues. Pricing is 599 USD per month or 5,999 USD for a perpetual lifetime license. See pricing or how the platform works.

SITEY closes the loop, not just the report.Discover, validate, fix and verify in your own infrastructure.

See pricing