Security Rule Test Packs (preview)

Test a small set of security rules with safe, fixed HTTP canaries and similar benign requests. The Python standard-library client sends serial GET requests through an explicitly supplied load balancer to a harmless recording origin. It reports the expected and observed status, origin observations, and rule verdict per case. It does not start Next.js, Camel, or any vulnerable application.

Run against an authorized load balancer

Use Python 3.10 or newer. Configure your own load balancer to forward /security-rule-probe and its query string to http://127.0.0.1:18081 on the machine running the script. The script owns that loopback recording origin only for the run. A remote load balancer needs a separately authorized forwarding path to this origin; the script does not create tunnels or discover hosts. Ensure the load balancer preserves both correlation tokens (query and header) and request path. Disable retries, caching and asynchronous forwarding for this dedicated test route.

python3 scripts/security_rule_test_pack.py \
  --pack examples/security-rule-packs/nextjs-camel.json \
  --target http://127.0.0.1:18080 \
  --report security-rule-report.json

The load balancer must already be running; no policy is installed or modified. Configure expected rejections as appropriate for your policy (the example uses 403), then review the JSON pack. status is an exact assertion, not benchmark metadata. The WAFBench verbatim path currently discards expected-status metadata and uses generic 2xx checks; this runner is independent of that path.

--allow-external-target affirms authorization for the exact non-loopback target you supply. Without it only loopback IP literals are accepted. Credentials, paths, queries and fragments in target URLs are rejected. HTTPS uses certificate verification. There are no redirects, retries, callbacks, command payloads, runtime exploits, or automatic probes of discovered hosts. Only the five fixed supported cases are sent, with one benign control before and after each: 15 requests maximum, each with a default two-second socket timeout (maximum five), a 4 KiB response read limit, and a default 0.1-second observation window (0.01–1). The recorder returns fixed JSON, stores correlated headers/path in memory, and is closed on exit. Keep the dedicated route isolated; report headers are test observations, so do not route real user traffic or credentials through it.

Cases and evidence

CaseIntended checkDefault expectation
normal-controlOrdinary GET200, origin seen
nextjs-benignOrdinary client note containing middleware200, origin seen
nextjs-headerSynthetic x-middleware-subrequest marker403, origin absent within window
camel-benignOrdinary beanMethodName query parameter200, origin seen
camel-parameterMixed-case cAmelBeanMethodName=mockforgeCanary query403, origin absent within window
camel-headerMixed-case internal headerUnsupported; no request sent

Sources: Next.js CVE-2025-29927 postmortem, Camel CVE-2025-27636, Camel CVE-2025-29891. These scenarios follow the safe transport canaries from draft PR1403. This feature is independent of that PR and does not include its exporter or guide.

The known k6 header normalization prevents claiming mixed-case wire fidelity. This first runner deliberately leaves the header case unsupported too; it does not infer wire fidelity from a requested header spelling. Recorded receiver header pairs are exposed for supported cases, but are not a capture of bytes at the load balancer. Query observations check the exact path, and supported probe headers must match at the origin when the case is allowed.

The JSON report separates scenario_delivery, rule_behavior, and runtime_patch_evidence. Every runtime/patch result is unverified. A pass means the explicit status and origin assertion agree during the stated window, with a unique matching query/header correlation ID, an exact path/header check for observed traffic, and successful correlated benign controls immediately before and after the case. An absent observation is only evidence within that window, under the forwarding assumptions above. It cannot exclude later delivery, arbitrary policy rewrites, or selective correlation removal. It does not prove request bytes reached the load balancer, application protection, remediation, authorization enforcement, bean invocation, or CVE exploitability. No runtime or patch is tested.

fail identifies an observed assertion mismatch, including false positives on benign traffic or a denial that still reaches the origin. Network errors, missing expected observations, malformed correlation, and failed flanking controls produce inconclusive unless an explicit status mismatch is already observed. They never prove blocking. unsupported is never a pass.

Exit codes: 0 only when every selected case passes, 1 for any failure, inconclusive or unsupported case, 2 for invalid configuration/startup/output errors. Consequently the full example pack intentionally returns 1 even when its five supported cases pass. To gate only supported cases, copy the JSON pack and explicitly remove the camel-header entry; all five other cases are mandatory. The schema rejects unknown fields/IDs, duplicate IDs, invalid status types, and controls changed to expect rejection. This is a closed set of safe requests, not a user-supplied payload or broad CVE catalog.

Local verification

python3 scripts/tests/test_security_rule_test_pack.py
ruff check scripts/security_rule*.py scripts/tests/test_security_rule_test_pack.py
ruff format --check scripts/security_rule*.py scripts/tests/test_security_rule_test_pack.py

The tests own real loopback proxy/recorder servers and exercise the CLI and JSON report. They do not validate a production load balancer, WAF implementation, Next.js/Camel runtime, TLS termination, or mixed-case header bytes. The dedicated CI workflow runs these offline tests without downloads or external targets.

Factual description suitable for later marketing review: “Preview safe security rule canaries with benign controls, exact response assertions, and correlated origin observations.” Publication and claims of CVE protection require separate review and application/runtime evidence.