Skip to content

CWE-83: XSS (Improper Neutralization)

Overview

This guidance helps you interpret and remediate findings from DAST (Dynamic Application Security Testing) tools. The scanner detected that the application performed insufficient or context-inappropriate neutralization of user input before placing it in HTML output, allowing XSS attacks to bypass weak filters or exploit incorrect encoding. DAST tools identify this by:

Detection Methods:

  • Filter Bypass Testing: Submitting payloads designed to evade common filters:
    • Tag nesting: <scr<script>ipt>alert(1)</scr</script>ipt>
    • Case variation: <ScRiPt>alert(1)</sCrIpT>
    • Alternative encodings: HTML entities (&lt;script&gt;), URL encoding (%3Cscript%3E), Unicode (\u003cscript\u003e)
    • Null byte injection: <script%00>alert(1)</script>
  • Context-Specific Bypasses:
    • Attribute context: " onload="alert(1), ' onerror='alert(1)', javascript:alert(1) in href/src
    • JavaScript context: Breaking out of strings ('-alert(1)-', "; alert(1)//)
    • CSS context: expression(alert(1)), url('javascript:alert(1)')
    • JSON/Script context: </script><script>alert(1)//
  • Double-Encoding: Testing %253Cscript%253E (double URL-encoded) to bypass decode-then-validate logic
  • Template Injection: Testing for unsafe template rendering ({{7*7}}, ${7*7}, <%= 7*7 %>)

HTTP Evidence:

  • Bypass payloads reflected unencoded in HTML responses (view-source shows <scr<script>ipt>)
  • Successful attribute breakout visible in response HTML (<img src="user-input" onload="...">)
  • JavaScript execution confirmed via HTTP callbacks to scanner infrastructure
  • Incomplete encoding: quotes not encoded in attribute context, <> encoded but quotes left unencoded
  • Double-encoding vulnerabilities: %253C becomes %3C after first decode, then < after second
  • Context mismatches: HTML-encoded output placed in JavaScript context where HTML entities are invalid

Scanner Behavior: OWASP ZAP and PortSwigger Burp test context-specific bypasses systematically. They submit polyglot payloads that work across multiple contexts, analyze encoding applied to each character in the payload, and use automated browser testing to verify execution. Advanced scanners test both client-side (DOM-based) and server-side (reflected/stored) XSS with context-aware payloads.

Analyzing the Dynamic Scan Result

What the DAST Scanner Found

When reviewing your security scan results, you'll see:

HTTP Request Details

  • URL and endpoint that triggered the finding
  • HTTP method (GET, POST, etc.)
  • Query parameters or form data with test payloads
  • Request headers and body content

HTTP Response Evidence

  • Response showing the vulnerability manifestation
  • Evidence of improper handling or injection
  • Runtime behavior indicators

Attack Vector

  • Which parameter or input is vulnerable
  • Type of exploitation possible
  • Context where the vulnerability appears

Mapping DAST Findings to Source Code

Find the Vulnerable Endpoint

Use the HTTP request URL to locate the code:

# Search for escaping/encoding functions
grep -r "escape" src/
grep -r "sanitize" src/
grep -r "encode" src/
grep -r "strip_tags" src/

Locate Output Encoding

Common patterns to search for:

  • Incomplete escaping: Only escaping <> but not quotes
  • Wrong context: HTML encoding in JavaScript context
  • Denylist filtering: Blocking specific tags instead of allowlisting
  • Double encoding: Encoding twice causes bypass
  • Client-side filtering: Can be bypassed

Find Insufficient Neutralization

Search for encoding issues:

# Find encoding attempts
grep -r "replace('<', '')" src/
grep -r "strip_tags" src/
grep -r "htmlspecialchars" src/

Trace to Vulnerable Operation

Look for improper neutralization:

  • Wrong encoding: Using HTML encoding in JavaScript
  • Incomplete encoding: Missing quotes, backslashes
  • Denylist bypass: Filtering <script> but allowing <img>
  • Double encoding: %253Cscript%253E becomes <script>
  • Attribute injection: Not encoding quotes in attributes

Remediation

Core principle: Never rely on ad-hoc filtering or partial escaping for XSS; encode untrusted data for the specific output context (HTML, attribute, JS, URL) using vetted framework encoders so it cannot change interpretation.

Verification and Follow-Up Testing

After applying the fix:

Reproduce the Vulnerability

# Test filter bypasses
curl "http://localhost/search?q=<scr<script>ipt>alert(1)</scr</script>ipt>"
curl "http://localhost/msg?txt=<img src=x onerror=alert(1)>"

# Test context-specific bypasses
curl "http://localhost/user?name='; alert(1)//"

Verify the Fix

  • Confirm context-appropriate encoding used
  • Confirm contextual output encoding at the sink (HTML/attr/JS/URL)
  • Confirm templates have auto-escaping enabled and unsafe “raw/safe” rendering is not used
  • Confirm DOM sinks (innerHTML, document.write, etc.) are avoided or use safe APIs (textContent)
  • Confirm CSP is defense-in-depth (not a fix)
  • Ensure no double-encoding issues
  • Test comprehensive HTML entity encoding

Test Edge Cases

# Bypassing denylist filters
<scr<script>ipt>alert(1)</scr</script>ipt>
<ScRiPt>alert(1)</sCrIpT>
<img src="x" onerror="alert(1)">

# JavaScript context
'-alert(1)-'
"; alert(1)//

# Attribute context
" onload="alert(1)
' onmouseover='alert(1)

# Double encoding
%253Cscript%253E

# Or use browser DevTools Network tab to copy as cURL

Re-run DAST Scanner

Run your dynamic scanner again on the fixed endpoint to confirm remediation.

Additional Resources