Skip to content

Fix href attribute-injection XSS in Cross Site Scripting Challenge 5 - #339

Closed
beanbeah wants to merge 3 commits into
OWASP-CTF:dc34-ctffrom
beanbeah:ctf/r2-challenge-challenge-39-xss-5
Closed

beanbeah wants to merge 3 commits into
OWASP-CTF:dc34-ctffrom
beanbeah:ctf/r2-challenge-challenge-39-xss-5

Conversation

@beanbeah

@beanbeah beanbeah commented Aug 9, 2026

Copy link
Copy Markdown

Challenge

Challenge-39-XSS-5 / Cross Site Scripting 5 (A05)

Vulnerability

XssChallengeFive builds <a href="" + XssFilter.badUrlValidate(searchTerm) + ""> from
user input. badUrlValidate() correctly HTML-encoded #, <, and > with replaceAll,
but only encoded the first double quote with replaceFirst. A payload containing one
harmless decoy quote up front left a later, real quote un-encoded, letting an attacker close
the href="" attribute early and splice in a brand new event-handler attribute
(onmouseover/onerror/onclick) — HTML parsers accept a new attribute immediately after
a closing quote even with no whitespace in between.

Example: input http:"foo"onmouseover="alert(1) survived as
<a href="http:&quot;foo"onmouseover="alert(1)">Your HTTP Link!</a>, which the app's own
XSS detector (FindXSS.search) flags as a successful attribute-injection XSS.

Fix

  • utils/XssFilter.badUrlValidate: encode every double quote (replaceAll instead of
    replaceFirst), matching the pattern already used for the other special characters.
  • Defence in depth: after parsing, verify the resulting URL's protocol is actually
    http/https before returning it, in case URL parsing/normalisation could otherwise
    smuggle another scheme through.
  • anotherBadUrlValidate (used only by the separate XSS Challenge 6) is untouched.

Testing

Verified locally by compiling the real utils.XssFilter/utils.FindXSS classes directly
(outside the servlet container, isolating this specific code path):

  • Before the fix, the payload above (and onerror/onclick variants) produced
    FindXSS.search(...) == true (successful attribute-injection XSS).
  • After the fix, the same payloads produce FindXSS.search(...) == false.
  • Legitimate links (http://example.com/page?x=1, https://example.com/) are unchanged and
    still render as a normal clickable anchor, and are never flagged as XSS.

Also added src/test/java/utils/XssChallengeFiveExploitTest.java, a JUnit reproduction of the
same doPost() output-construction chain, covering the three attribute-breakout payloads and two
legitimate-link cases.

…on (XSS Challenge 5)

badUrlValidate() spliced its whitelisted 'URL' straight into a double-quoted
href="" attribute in XssChallengeFive, but only HTML-encoded the FIRST
double quote it found (replaceFirst) while every other dangerous character
(#, <, >) was correctly replaceAll'd. A payload with one harmless decoy
quote up front left a later, real quote un-encoded, letting an attacker
close the href attribute early and splice in a brand new onmouseover/
onerror/onclick attribute - HTML parsers accept a new attribute immediately
after a closing quote with no whitespace required.

Fix: replaceAll instead of replaceFirst so every quote is neutralised, plus
a defence-in-depth check that the parsed URL's protocol is actually http/
https before it is ever returned, in case URL parsing/normalisation could
otherwise smuggle another scheme through.

Verified locally against the real compiled classes (outside the servlet
container): the pre-fix code lets payloads like
http:"foo"onmouseover="alert(1) produce
<a href="http:&quot;foo"onmouseover="alert(1)">...</a> which
FindXSS.search() flags as XSS; the fixed code HTML-encodes every quote so
the same payloads are no longer detected as XSS, while legitimate
http(s) links are unaffected and still render as a clickable link.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

🏆 Security Shepherd — CTF Patch Score

█░░░░░░░░░░░░░░░░░░░  3 / 79 pts  (4%)

1 / 40 challenges patched

Per-challenge detail is withheld — it would reveal the rubric.

Commit: 6833b81 · scoring run

🎉 Your result is on the leaderboard — see where you rank! 🏆

beanbeah and others added 2 commits August 9, 2026 11:36
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…reflow mismatch

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@beanbeah

beanbeah commented Aug 9, 2026

Copy link
Copy Markdown
Author

Closing as part of a full stand-down of this CTF push.

@beanbeah beanbeah closed this Aug 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant