Most production targets today sit behind a WAF. Cloudflare, AWS WAF, Akamai, Imperva, Fastly, or a self-hosted ModSecurity. Default sqlmap against any of them gets identified inside the first three requests, the source IP gets challenge-rated or blocked, and your scan is dead before it started.
This is the practical evasion playbook. Tamper scripts that still work today, request shaping that survives modern signature engines, fingerprint reduction at the protocol level, and the point at which you should stop fighting sqlmap and switch to manual exploitation in Burp Repeater.
If you have not read the sqlmap cheat sheet, the tamper script references below will make more sense after. Background on the variants is in the SQL injection deep dive.
What WAFs actually catch
Modern WAFs combine three detection layers:
- Signature matching. Regex and lexer-based rules looking for SQL keywords, comment markers, payload patterns. The OWASP CRS (Core Rule Set) is the open reference; commercial engines layer their own on top.
- Reputation and fingerprint. User-Agent, TLS fingerprint (JA3/JA4), HTTP/2 frame ordering, request timing patterns. A client that "looks like sqlmap" gets flagged before the payload is even inspected.
- Behavioural and ML. Rate of requests, parameter-value entropy, response-size variance. Aggressive scans tip the behavioural signals even when individual payloads are clean.
Evasion has to address all three. A clever tamper script that defeats signatures is useless if your TLS fingerprint screams "Python requests library" on connection.
Step 1: identify the WAF
Before evasion, know what you are evading. sqlmap's built-in detector:
sqlmap -u 'https://target.example/product?id=1' --identify-wafOutput names the WAF if recognised:
[INFO] heuristics detected web page charset 'utf-8'
[INFO] WAF/IPS identified as 'Cloudflare (Cloudflare Inc.)'
wafw00f is the standalone tool with broader signatures and is worth running as a cross-check:
wafw00f https://target.example/Knowing the WAF tells you which tamper scripts to try first. Cloudflare and AWS WAF respond well to different obfuscations.
Step 2: tamper scripts that still work
sqlmap ships with around fifty tamper scripts. Most were written against specific WAF versions and have aged unevenly. These are the ones I find still pulling weight today, grouped by what they do:
Whitespace and comment obfuscation:
| Tamper | What it does | Defeats |
|---|---|---|
space2comment | Replaces spaces with /**/ | Basic CRS, naive blacklists |
space2plus | Replaces spaces with + | Some URL-encoded contexts |
space2randomblank | Random tab/newline/whitespace | Lexers that only match literal space |
space2dash | Replaces spaces with -- <random>\n | Same family |
between | Replaces > with NOT BETWEEN 0 AND # | WAFs that block > specifically |
Case and encoding:
| Tamper | What it does | Defeats |
|---|---|---|
randomcase | SeLeCt-style random case | Case-sensitive blacklists (rare but still seen) |
charencode | Hex-encode payload | Naive ASCII-only signatures |
charunicodeencode | Unicode escape keywords | Unicode-unaware lexers |
charunicodeescape | Same family, different encoding | Same |
equaltolike | = becomes LIKE | = blacklists |
MySQL-specific:
| Tamper | What it does | Defeats |
|---|---|---|
versionedkeywords | /*!UNION*/ | Old ModSec rules |
versionedmorekeywords | More aggressive versioned comments | Same |
halfversionedmorekeywords | Versioned comments before each keyword | More aggressive variant |
apostrophenullencode | ' becomes %00%27 | WAFs that miss null bytes |
Chains worth trying:
Cloudflare currently (heuristic, varies by ruleset version):
--tamper=between,randomcase,space2commentAWS WAF managed rules:
--tamper=charunicodeencode,space2randomblank,randomcaseModSecurity with CRS 3.x (still common in self-hosted):
--tamper=modsecurityversioned,space2comment,randomcaseCycle through chains. A combination that worked last month may not work this month if the WAF vendor pushed updates.
Tamper scripts I would not bother with anymore:
appendnullbyte, most modern stacks handle null bytes safely now.halfversionedmorekeywordsoutside MySQL, most other DBMS do not parse versioned comments at all.multiplespaces, almost no current WAF cares about multiple spaces.
Step 3: request shaping
Tamper scripts change the payload. Request shaping changes the request envelope around it. Both matter.
Pacing:
--delay=5 --threads=1 --timeout=30 --retries=3Slow enough that behavioural detection treats you as a human-paced client. --delay=5 adds five seconds between requests. With --threads=1 you get a steady five-second cadence. Forget about scan time; you are buying detection-rate reduction.
User-Agent and headers:
--random-agent
-H "Accept-Language: en-US,en;q=0.9"
-H "Accept-Encoding: gzip, deflate, br"
-H "Cache-Control: max-age=0"
-H "Upgrade-Insecure-Requests: 1"Default sqlmap headers are sparse. Real browsers send a dozen headers. Pad with realistic values to reduce header-shape fingerprinting.
HTTP parameter pollution (HPP):
--hppSplits payloads across duplicate parameters: ?id=1&id=UNION&id=SELECT.... Different servers reassemble these differently. PHP takes the last, Java's getParameter takes the first, ASP.NET concatenates with commas. WAFs that reassemble differently from the application miss the payload entirely.
Chunked transfer encoding:
--chunkedSplits POST bodies via Transfer-Encoding: chunked. Some WAFs do not reassemble before inspection; the application does. Less effective than it used to be because mature WAFs handle chunked now, but worth trying when the WAF identifies as something older.
HEAD-based detection:
--null-connectionUse HEAD requests for boolean detection. The WAF often inspects fewer headers on HEAD, and content-length differences alone signal true/false without body content for the WAF to match against.
Step 4: TLS and HTTP fingerprint reduction
This is where sqlmap's defaults betray you. Python's requests library (which sqlmap uses) has a JA3 TLS fingerprint that every commercial WAF recognises. No tamper script fixes this.
Options:
curl-impersonate is the easiest fix. It is a build of curl with patched TLS and HTTP/2 stacks that match real browsers' fingerprints. Use it as a per-request fetcher via sqlmap's --eval or roll a small wrapper:
# Pseudo-pattern (sqlmap does not natively use curl-impersonate, so you wrap):
# Capture sqlmap requests, replay through curl-impersonate, return responses.Honest assessment: this is awkward to bolt onto sqlmap. The realistic options when TLS fingerprinting is the blocker are:
- Burp Suite as the relay. Run sqlmap through Burp (
--proxy=http://127.0.0.1:8080). Burp's TLS stack is browser-like enough to pass most fingerprint checks. You lose some speed; you gain fingerprint legitimacy. - Drop to manual. If TLS fingerprinting is being aggressively used, you are dealing with a hardened target and the productivity gain of sqlmap is gone. Burp Repeater plus hand-crafted payloads through a real browser session is the alternative.
Step 5: avoid sqlmap's tells
sqlmap leaves signatures even when payloads are obfuscated:
- Sequential parameter probing. sqlmap tests one parameter at a time with predictable payload progression. Behavioural detection latches onto this. Mitigate with
-pto restrict to one parameter at a time across separate runs. information_schemaaccess. sqlmap reaches forinformation_schemafor enumeration. Even with tampered keywords, the volume of metadata queries from one source IP is the signal. Slow down with--threads=1 --delay=5.- Predictable request ordering. ORDER BY probing, column-count probing, and union enumeration each have characteristic request shapes. Spreading across multiple sessions and IPs (Tor exit rotation, see the Tor guide) breaks the per-source pattern but does not change the global pattern.
Step 6: when to give up on sqlmap
I switch to manual when any of:
- Three tamper-chain combinations fail to get past the WAF.
- The TLS fingerprint is being used as a primary block (sqlmap returns identical 403/challenge regardless of payload).
- The target is custom enough that sqlmap's payload templates do not fit (unusual encodings on the wire, gRPC, GraphQL with depth checks, or a JWT-signed parameter where the WAF is checking the signature).
The manual fallback workflow:
- Confirm injection with three hand-crafted payloads in Burp Repeater (one boolean, one error-trigger, one time-based).
- Build a manual extraction loop using Burp Intruder (Pro) or a small Python script. Read one character of one column at a time with explicit conditional payloads.
- For a fully-blind target through a heavy WAF, the manual loop with hand-shaped payloads will be slower than sqlmap on an unprotected target but faster than sqlmap getting blocked every fifty requests.
This is unglamorous and accounts for maybe 10% of my SQLi work. The other 90% is sqlmap with the right tamper chain.
What this looks like from the defender's side
If you are on the other side of this, the signals that should fire:
- WAF logs showing one source-IP cycling tamper-encoded payloads. Even when individual requests pass, the cluster across requests is the signal. A SIEM rule counting "payloads that look encoded" per source per hour is the right shape.
- Application logs showing
information_schemaaccess from an account that should not need it. This is the highest-value detection rule for SQLi exploitation. Easy to write, near-zero false positive rate. - Behavioural rate anomalies. A single client making thousands of requests to the same parameter with varying value lengths matches the binary-search shape regardless of payload obfuscation.
- TLS fingerprint that does not match a known browser combined with parameter-heavy traffic. A scan that defeats every payload signature still leaves a TLS fingerprint that, against your real user base, is anomalous.
Defenders: lean on the second one. Application-level alerts on suspicious database access are cheaper, more reliable, and harder to bypass than network-layer WAF rules.
A practical evasion order of operations
When sqlmap defaults get blocked, the order I try:
--random-agentand realistic headers (Step 3).--delay=3 --threads=1(slow down).- A tamper chain matched to the identified WAF (Step 2).
--hppand--chunked(Step 3).- Route through Burp as a proxy to launder the TLS fingerprint (Step 4).
- Drop to manual in Burp Repeater (Step 6).
If step 5 still fails, the target is hardened enough that scanning it without an explicit allow-list is a bad use of time. Get the IP whitelisted, scan from a known source, then unblock the harder work for engagements where the WAF itself is the test target.
Where to go next
- The sqlmap cheat sheet for the full flag reference.
- The sqlmap with Tor and proxychains guide for the source-IP side of opsec.
- The sqlmap tutorial against a vulnerable lab for the baseline workflow with no WAF in the way.
- The SQL injection deep dive for the underlying mechanics.
- The best SQL injection tools list for 2026 for ghauri's WAF-handling profile and the alternatives.
Sources
Authoritative references this article was fact-checked against.
- sqlmap, bundled tamper scripts (official source)github.com
- sqlmap, Usage wikigithub.com
- OWASP, Web Application Firewallowasp.org





