Per-CVE Rule Packs
A per-CVE rule pack lets you stand up a new CVE’s traffic test for your load balancer or WAF in minutes, from a small declarative profile. It generalizes the Security Rule Test Packs from a fixed set of cases to one you author per CVE.
It answers one question: does my rule block this CVE’s request signature and leave benign traffic alone? It does not, and cannot, tell you whether a real target is vulnerable or patched.
What it is and is not
This is a defensive rule-regression harness, not an exploit tool.
- Server leg is a MockForge mock of the guarded route (
cve_pack.py server). MockForge serves a fixed canned response; none of the vulnerable code runs, so a load balancer in front of it sees a realistic origin that is inherently inert. - Client leg sends the rule’s signature — the header and query-parameter
names the rule matches on — with inert marker values. The profile schema
only accepts marker values matching
[A-Za-z0-9_.:-], so a profile cannot carry a command, a template expression, markup, a traversal or any payload, and there is no request-body field at all. - The harness sends only
GET, one correlation token per request, no retries and no redirects, to a loopback target by default.
It never provisions a vulnerable application, executes a payload, or sends a
callback. Reports always mark runtime_patch_evidence as unverified.
The profile
A profile (examples/cve-packs/<cve-id>/profile.json) names the route, the
signature tokens, benign controls, and the expected rule outcome:
{
"schema_version": 1,
"cve": "CVE-2025-29927",
"title": "Next.js middleware authorization bypass via x-middleware-subrequest",
"references": ["https://nextjs.org/blog/cve-2025-29927"],
"route": "/dashboard",
"signature": {
"method": "GET",
"query": {},
"headers": { "x-middleware-subrequest": "middleware:middleware:middleware:middleware:middleware" }
},
"expect": { "blocked_status": 403, "origin": "absent" },
"controls": [
{ "id": "benign", "query": {}, "headers": {}, "expect": { "status": 200, "origin": "seen" } }
]
}
signature.headers/signature.queryare name → marker. Use the exact name the rule keys on; keep the value an inert marker. The repeatedmiddleware:token above is inert (letters and colons only) yet still matches a rule that looks for the chained value.expect.blocked_statusis the 4xx/5xx the rule returns;origin: "absent"asserts the request must not reach the origin.- Each control is benign traffic that should pass through (
200,seen).
Workflow
-
Scaffold a profile from the advisory:
python3 scripts/cve_pack.py new CVE-2025-29927 --output CVE-2025-29927.profile.jsonFill
route, the signature name(s), andexpect.blocked_statusfrom the vendor advisory. Keep values as markers. -
(Optional) run the realistic origin for manual exploration:
python3 scripts/cve_pack.py server CVE-2025-29927.profile.json > mock.json mockforge serve --spec mock.json --http-port 18080 -
Test your load balancer / WAF. Point
--targetat the LB in front of your origin:python3 scripts/cve_pack.py run CVE-2025-29927.profile.json \ --target http://127.0.0.1:8080 --report report.jsonThe harness sends each benign control and the signature request (flanked by a control beacon to corroborate origin reachability), then prints a verdict per case and writes
report.json. It exits non-zero unless every case passes: the signature blocked and not forwarded, and every control allowed and observed at the origin.A non-loopback
--targetrequires--allow-external-target, which affirms you are authorized to send this traffic to that exact host.
Reading the result
For each case the report gives rule_behavior (pass, fail, inconclusive),
the observed status, origin_seen, and the bounded origin_observations. The
run exits 0 only if all cases pass.
passon the signature means the rule returned the expected block status and the request did not reach the origin.failmeans the status did not match, or a “blocked” response still forwarded the request to the origin.inconclusivemeans the evidence could not establish blocking — a network error, missing correlation, or controls that could not corroborate origin reachability (for example an LB that denies everything).
What the harness proves is scenario delivery and rule behavior at the transport layer. It is not a load-balancer byte capture, and it is not proof of CVE protection or remediation.