What used to take skill and time now takes a prompt. The controls protecting most applications were built for a world where breaking through took more coordination than an attacker could muster. That assumption is gone, and the fastest way to prove it is to watch an agent take apart the control teams reach for first: the web application firewall (WAF).
We built an agentic bypass generator and pointed it at a major commercial WAF, in scope and under published bug-bounty safe harbor. This is not a payload list. It is an agent that fingerprints the WAF, picks an attack strategy matched to what it finds, mutates, reads the response, and iterates, learning faster than the vendor patches.
Here is what we found.
In one engagement against a leading CDN-WAF, the generator produced 652 reproducible edge evasions across the target's web assets. These were payloads that passed the WAF and were accepted by the origin, at sustained rates of roughly one in four requests. Four independent technique families did most of the work, each reproducible on re-test: charset confusion (UTF-7 inside multipart, ~26%), request smuggling via chunked transfer-encoding (~20%), inspection-buffer overflow through oversized padding (~27% combined), and parameter pollution (~10%). A long tail of protocol-framing evasions across gRPC, HTTP/2, and WebSocket added the rest.
Two details matter more than the headline number. First, a second WAF in the same run was not evaded at all: zero successful evasions across every attempt against it. That is the point. Permeability is specific to the target, and the only way to learn yours is to generate against it, not to read a vendor datasheet. Second, every result above is graded by what it actually achieved. These are edge evasions: the payload beat the WAF and reached origin. They are not claims of executed exploits. We tier every finding as evaded, reflected, or confirmed, and we report the tier we reached rather than flattening everything into "vulnerable." Most tools don't make that distinction. A security team can't afford not to.
| 652 reproducible edge evasions in one engagement | ~25% sustained evasion rate against the target | 4 of 4 top technique families fully reproducible |
Why a generator, not a payload list
A payload list is a snapshot. The moment a vendor patches a technique, the list is wrong and nobody tells you. It is the same trap the WAF vendors are in, pointed the other direction. A human red-teamer runs a better version of the same snapshot: skilled, slow, and gone by next quarter. What no human holds is the full space of mutations a given detector will and will not catch, a space that shifts every time the vendor updates. That search is what the agent runs well, and it's why toppling a modern WAF is now an agentic problem rather than a bigger-list problem.
The generator isn't a list. It's a loop:
- Fingerprint the detector. Before anything else, classify what kind of WAF you're dealing with: regex, ML-driven, or behavioral. The bypass strategy is completely different for each, so this decision shapes everything that follows.
- Select a strategy matched to the model. Regex detectors fall to encoding chains, character substitution, and whitespace manipulation. ML detectors can be fed adversarial inputs that sit just under their confidence threshold. Behavioral systems need patient evasion over time, not a single payload. The agent picks based on what it just fingerprinted. It doesn't run one playbook against everything.
- Mutate and fire.
- Read the response and feed it back. If a mutation moves the needle, the next iteration builds on it instead of starting over. If it doesn't, the strategy shifts.
That fourth step is the whole game. What works against a target is remembered, so the next engagement starts primed, not from zero. A commodity scanner runs the same list every time and learns nothing between runs. The mutations aren't a library of techniques; they're unique operations the agent composes and chains based on what the target reveals. That is what holds up against a WAF whose rules keep changing.
What it keeps finding
Everything below is documented, known territory. None of it is exotic. The point isn't that these techniques are secret. It's that they define the search space the generator explores autonomously, against your specific WAF configuration, continuously. A human knows these techniques exist. The agent finds which one your WAF is vulnerable to today, and which it'll be vulnerable to after the next rule update.
The WAF and the app parse differently
The most reliable bypass class exploits a simple fact: your WAF inspects the request one way, your application reads it another. When they disagree, the attacker wins.
// Duplicate JSON keys — WAF inspects first, app uses last
{"user": "safe", "user": "PAYLOAD"}
// Multipart charset mismatch (CVE-2026-21876, OWASP CRS rule 922110)
// WAF validates only the LAST part; malicious charset hides in the first
[first part] charset=utf-7 -> +ADw-img src=x+AD4- (UTF-7 XSS)
[last part] charset=utf-8 -> benign
// XML namespace redefinition wrapping payload
<root xmlns:a="http://safe">
<a:inject>PAYLOAD</a:inject>
</root>
These are documented and they work. The multipart case is live as of January 2026: CVE-2026-21876 (CVSS 9.3) is exactly this bug in OWASP CRS rule 922110. The rule inspects only the final multipart part, so a UTF-7 payload in the first part sails through while a benign UTF-8 part satisfies the check. It affected every supported CRS version until the fix, which means any WAF built on CRS inherited it. Most stacks stay vulnerable to the broader class because fixing it means coordinating parser behavior between two separate systems, the WAF vendor and the application framework, which almost never happens.
Inspection stops; the app keeps reading
WAFs don't inspect requests indefinitely. For performance, they stop at some byte limit. That cutoff is a handoff: past it, the request reaches the application un-inspected, and the app trusts that inspection happened. The generator locates the limit with a binary search (large request, halve, observe, repeat) to within a couple hundred bytes per endpoint, then places safe content in the inspected window and the payload past it. The exact limit varies by config. The limit always exists. Nobody deep-inspects 50MB POST bodies on every request.
Protocols the WAF passes through
Most WAF coverage assumes HTTP/1.1 or HTTP/2 with JSON or form bodies. Modern applications speak more than that, and the WAF tends to pass the rest through to a backend that assumes it was inspected.
- HTTP/3 0-RTT early data lets a payload arrive before the handshake completes, before the WAF has begun inspecting. It's not a misconfiguration; it's how the protocol works.
- gRPC usually isn't parsed as a first-class protocol. Dropping the leading slash from the :path pseudo-header (the same non-canonical-path technique behind CVE-2026-33186, an authorization bypass in gRPC-Go) breaks routing and authorization assumptions, and the request goes through unexamined.
- GraphQL persisted queries reference a stored query by ID, so the injection never appears in the body the WAF inspects.
These aren't edge cases. They're what your internal microservices, mobile apps, and API gateways speak right now.
Seeds, not signatures
Here's what separates a generator from a scanner. A published CVE is a known quantity: the moment it's disclosed, every WAF vendor writes a signature for it. Fire CVE-2026-21876 as published and a current commercial WAF blocks it; the exact payload is in everyone's ruleset by now. A scanner that ships CVEs is shipping techniques that are dead on arrival.
Our engine doesn't fire CVEs. It uses them as seeds. The agent takes the mechanism behind a disclosed vulnerability, not its payload, and mutates outward into variants the published signature never described. That's why the evasions above reproduce against a patched edge: we're not replaying the known attack, we're occupying the space around it that the patch didn't close. The CVE is the genetic material; what beats the WAF is what the agent grows from it.
What we seed with:
- Charset-validation gaps. CVE-2026-21876 (CVSS 9.3), the OWASP CRS multipart bug above, is a perfect seed. The agent doesn't reproduce the disclosed payload; it generates charset-confusion variants that survive the patched rule. This family was our single most productive evasion class against the target.
- Path-canonicalization gaps. CVE-2026-33186 (CVSS 9.1), an authorization bypass in gRPC-Go via a non-canonical :path, seeds the gRPC framing evasions in the results above. The agent mutates the canonicalization trick into forms the edge passes through.
- Deserialization in modern frameworks. CVE-2025-55182 (React2Shell, CVSS 10.0), pre-auth RCE in React Server Components via Flight-protocol deserialization, seeds a payload class most rulesets weren't written to catch.
- The MCP surface, where there's barely a signature to mutate past. CVE-2026-23744 (CVSS 9.8), a critical RCE in MCPJam Inspector, is the kind of new-infrastructure flaw WAFs have no coverage for yet. Here the agent isn't evading a rule. It's operating where no rule exists.
The honest boundary: these seeds grow into novel evasion variants, new disguises that defeat a current defense, not novel vulnerabilities. Everything here is graded edge-evasion. The newness is in the mutation getting past the WAF, not in discovering a hole nobody knew about.
And that's the part that's specifically agentic. A fuzzer mutates too, but blindly. It perturbs inputs and watches for a crash without ever modeling what it's up against. A human red-teamer models the defender well but can't do it ten thousand times an hour. What the WAF problem actually demands is a loop in between: read an opaque response, infer why the payload failed, pick the next mutation conditioned on that inference, and repeat across a space too large to enumerate and too target-specific to script in advance. That conditioning step (fingerprint the detector, then choose the strategy that beats that detector rather than firing everything) is a decision, not a sweep. Regex detector, reach for encoding. ML detector, push an input under its confidence threshold. Behavioral, slow down.
A scanner runs the same plan regardless of what comes back; the agent's plan is a function of what comes back. That feedback-driven judgment, executed at machine scale, is the thing neither a static tool nor a human can do alone, and it's why generation, not enumeration, is what gets through a modern WAF.
The fix isn't a better WAF
We are not selling a replacement WAF. Every major vendor has the same fundamental problem: the rules are static and the attacker is dynamic. A better rule set is still a rule set, and the agent that took apart this one will take apart that one on its next run.
The only defensible posture is continuous adversarial generation, not a quarterly pentest or a longer payload list. Generation that fingerprints your WAF, picks a strategy matched to its detection model, and learns from its own results so the next run is sharper than the last. The teams that get this right don't have better WAFs. They have a current, generated picture of exactly where their WAF stops working. They regenerate it continuously, because the day they stop, it's already wrong.
The WAF is where we started because it's the control standing between the world and your network. This is the first piece of research in a program built on a single observation: when sophisticated attacks no longer require sophisticated attackers, every static control is on the same clock. We'll keep showing you which one runs out next.