The pre-fix badUrlValidate() only HTML-encoded the *first* double quote it found
+ * (replaceFirst instead of replaceAll) before splicing the result into a double-quoted
+ * href="" attribute. A payload with a harmless decoy quote up front left a later, real
+ * quote un-encoded, letting an attacker close the href attribute early and append a
+ * brand new onmouseover/onerror/onclick attribute that HTML parsers (browsers and the
+ * JTidy/Jsoup pipeline FindXSS.search() uses) accept even with no whitespace between
+ * attributes. Confirmed against the original code (outside this test, via a standalone
+ * harness) that this exact payload shape scores FindXSS.search() == true; these tests
+ * assert the fixed code closes it while leaving legitimate http(s) links untouched.
+ */
+class XssChallengeFiveExploitTest {
+
+ private static String buildUserPost(String searchTerm) {
+ String validated = XssFilter.badUrlValidate(searchTerm);
+ return "Your HTTP Link!";
+ }
+
+ @Test
+ void decoyQuoteOnmouseoverBreakout_noLongerDetectedAsXss() {
+ String payload = "http:\"foo\"onmouseover=\"alert(1)";
+ String userPost = buildUserPost(payload);
+ assertFalse(FindXSS.search(userPost), "onmouseover attribute-breakout should be neutralised");
+ }
+
+ @Test
+ void decoyQuoteOnerrorBreakout_noLongerDetectedAsXss() {
+ String payload = "http:\"foo\"onerror=\"alert(1)";
+ String userPost = buildUserPost(payload);
+ assertFalse(FindXSS.search(userPost), "onerror attribute-breakout should be neutralised");
+ }
+
+ @Test
+ void decoyQuoteOnclickBreakout_noLongerDetectedAsXss() {
+ String payload = "https:\"foo\"onclick=\"alert(1)";
+ String userPost = buildUserPost(payload);
+ assertFalse(FindXSS.search(userPost), "onclick attribute-breakout should be neutralised");
+ }
+
+ @Test
+ void legitimateHttpLink_stillRendersAndIsNotFlagged() {
+ String legit = "http://example.com/page?x=1";
+ String userPost = buildUserPost(legit);
+ assertTrue(userPost.contains("http://example.com/page?x=1"), "legitimate link must survive unchanged");
+ assertFalse(FindXSS.search(userPost), "legitimate link must never be flagged as XSS");
+ }
+
+ @Test
+ void legitimateHttpsLink_stillWorks() {
+ String legit = "https://example.com/";
+ String userPost = buildUserPost(legit);
+ assertTrue(userPost.contains("https://example.com/"));
+ assertFalse(FindXSS.search(userPost));
+ }
+}
From 56fedfcb238ba933ef0e5e79e43b7b97847c9cd5 Mon Sep 17 00:00:00 2001
From: beanbeah <24713371+beanbeah@users.noreply.github.com>
Date: Sun, 9 Aug 2026 11:36:41 -0700
Subject: [PATCH 2/3] style: apply spotless/google-java-format to
XssChallengeFiveExploitTest
Co-Authored-By: Claude Sonnet 5 The pre-fix badUrlValidate() only HTML-encoded the *first* double quote it found
- * (replaceFirst instead of replaceAll) before splicing the result into a double-quoted
- * href="" attribute. A payload with a harmless decoy quote up front left a later, real
- * quote un-encoded, letting an attacker close the href attribute early and append a
- * brand new onmouseover/onerror/onclick attribute that HTML parsers (browsers and the
- * JTidy/Jsoup pipeline FindXSS.search() uses) accept even with no whitespace between
- * attributes. Confirmed against the original code (outside this test, via a standalone
- * harness) that this exact payload shape scores FindXSS.search() == true; these tests
- * assert the fixed code closes it while leaving legitimate http(s) links untouched.
+ * (replaceFirst instead of replaceAll) before splicing the result into a double-quoted href=""
+ * attribute. A payload with a harmless decoy quote up front left a later, real quote un-encoded,
+ * letting an attacker close the href attribute early and append a brand new
+ * onmouseover/onerror/onclick attribute that HTML parsers (browsers and the JTidy/Jsoup pipeline
+ * FindXSS.search() uses) accept even with no whitespace between attributes. Confirmed against the
+ * original code (outside this test, via a standalone harness) that this exact payload shape
+ * scores FindXSS.search() == true; these tests assert the fixed code closes it while leaving
+ * legitimate http(s) links untouched.
*/
class XssChallengeFiveExploitTest {
@@ -52,7 +52,8 @@ void decoyQuoteOnclickBreakout_noLongerDetectedAsXss() {
void legitimateHttpLink_stillRendersAndIsNotFlagged() {
String legit = "http://example.com/page?x=1";
String userPost = buildUserPost(legit);
- assertTrue(userPost.contains("http://example.com/page?x=1"), "legitimate link must survive unchanged");
+ assertTrue(
+ userPost.contains("http://example.com/page?x=1"), "legitimate link must survive unchanged");
assertFalse(FindXSS.search(userPost), "legitimate link must never be flagged as XSS");
}
From 6833b81855170491ba5009708d72c9f43de811ba Mon Sep 17 00:00:00 2001
From: beanbeah <24713371+beanbeah@users.noreply.github.com>
Date: Sun, 9 Aug 2026 11:40:47 -0700
Subject: [PATCH 3/3] style: switch test file's class comment to // lines to
avoid javadoc reflow mismatch
Co-Authored-By: Claude Sonnet 5 The pre-fix badUrlValidate() only HTML-encoded the *first* double quote it found
- * (replaceFirst instead of replaceAll) before splicing the result into a double-quoted href=""
- * attribute. A payload with a harmless decoy quote up front left a later, real quote un-encoded,
- * letting an attacker close the href attribute early and append a brand new
- * onmouseover/onerror/onclick attribute that HTML parsers (browsers and the JTidy/Jsoup pipeline
- * FindXSS.search() uses) accept even with no whitespace between attributes. Confirmed against the
- * original code (outside this test, via a standalone harness) that this exact payload shape
- * scores FindXSS.search() == true; these tests assert the fixed code closes it while leaving
- * legitimate http(s) links untouched.
- */
+// Reproduces the XssChallengeFive.doPost() output-construction chain: userPost is
+// "Your HTTP Link!", exercised here
+// without needing the full servlet container.
+//
+// The pre-fix badUrlValidate() only HTML-encoded the FIRST double quote it found
+// (replaceFirst instead of replaceAll) before splicing the result into a double-quoted
+// href="" attribute. A payload with a harmless decoy quote up front left a later, real
+// quote un-encoded, letting an attacker close the href attribute early and append a new
+// onmouseover/onerror/onclick attribute - HTML parsers accept a new attribute right after
+// a closing quote even with no whitespace in between. Confirmed (outside this test, via a
+// standalone harness) that this exact payload shape scored FindXSS.search() == true against
+// the original code; these tests assert the fixed code closes it off while legitimate
+// http(s) links keep working.
class XssChallengeFiveExploitTest {
private static String buildUserPost(String searchTerm) {