diff --git a/docs/index.html b/docs/index.html index 9584583a9..6c8002506 100644 --- a/docs/index.html +++ b/docs/index.html @@ -152,6 +152,7 @@

+ '; + var sanitized = testSanitizeInput(malicious); + assert.equal("", sanitized, "Script tags should be completely removed"); + }); + + test("strips img onerror handlers", function () { + var malicious = ""; + var sanitized = testSanitizeInput(malicious); + assert.equal("", sanitized, "Img tags with onerror should be removed"); + }); + + test("strips all HTML tags and attributes", function () { + var malicious = '
Click me
'; + var sanitized = testSanitizeInput(malicious); + assert.equal( + "Click me", + sanitized, + "HTML tags removed but text content preserved", + ); + }); + + test("handles empty and null inputs safely", function () { + assert.equal("", testSanitizeInput("")); + assert.equal("", testSanitizeInput(null)); + assert.equal("", testSanitizeInput(undefined)); + }); + }); + + suite("Client-side URL safety", function () { + test("blocks javascript: URLs", function () { + var malicious = "javascript:alert(1)"; + var safe = safeUrl(malicious); + assert.equal("", safe, "javascript: URLs should be blocked"); + }); + + test("blocks data: URLs", function () { + var malicious = "data:text/html,"; + var safe = safeUrl(malicious); + assert.equal("", safe, "data: URLs should be blocked"); + }); + + test("allows legitimate HTTP URLs", function () { + var legitimate = "https://www.w3.org/TR/html/"; + var safe = safeUrl(legitimate); + assert.equal( + "https://www.w3.org/TR/html/", + safe, + "Legitimate URLs should be allowed", + ); + }); + + test("handles case-insensitive protocol detection", function () { + assert.equal( + "", + safeUrl("JAVASCRIPT:alert(1)"), + "Uppercase javascript: should be blocked", + ); + assert.equal( + "", + safeUrl("JavaScript:alert(1)"), + "Mixed case javascript: should be blocked", + ); + assert.equal( + "", + safeUrl("DATA:text/html,'; + testEndpoint("search-refs", { q: scriptPayload }, function (err, result) { + if (err) return done(err); + assert.deepEqual( + result, + { message: "Missing q parameter" }, + "Script tags should be sanitized to empty, treated as missing parameter", + ); + done(); + }); + }); + + test("/reverse-lookup blocks XSS in urls parameter", function (done) { + var xssPayload = ""; + testEndpoint( + "reverse-lookup", + { urls: xssPayload }, + function (err, result) { + if (err) return done(err); + assert.deepEqual( + result, + {}, + "Malicious URL should return empty result", + ); + done(); + }, + ); + }); + + test("/reverse-lookup blocks javascript: URLs", function (done) { + var jsPayload = "javascript:alert(1)"; + testEndpoint( + "reverse-lookup", + { urls: jsPayload }, + function (err, result) { + if (err) return done(err); + assert.deepEqual( + result, + {}, + "JavaScript URLs should return empty result", + ); + done(); + }, + ); + }); + + test("/search-refs preserves legitimate queries", function (done) { + testEndpoint("search-refs", { q: "html" }, function (err, result) { + if (err) return done(err); + assert.ok( + typeof result === "object", + "Legitimate query should return object", + ); + assert.ok( + Object.keys(result).length > 0, + "Legitimate query should return results", + ); + done(); + }); + }); + + test("/reverse-lookup preserves legitimate URLs", function (done) { + testEndpoint( + "reverse-lookup", + { urls: "https://www.w3.org/TR/html/" }, + function (err, result) { + if (err) return done(err); + assert.ok( + typeof result === "object", + "Legitimate URL should return object", + ); + // May be empty if URL not in database, but should not error + done(); + }, + ); + }); + }); + + suite("Integration security tests", function () { + test("XSS payload completely neutralized through full pipeline", function () { + var xssPayload = ""; + var serverSanitized = testSanitizeInput(xssPayload); + assert.equal( + "", + serverSanitized, + "Server should strip malicious HTML completely", + ); + }); + + test("Legitimate content preserved through pipeline", function () { + var legitimate = "HTML specification"; + var serverSanitized = testSanitizeInput(legitimate); + assert.equal( + "HTML specification", + serverSanitized, + "Legitimate text preserved", + ); + }); + + test("Mixed content handled safely", function () { + var mixed = "Normal text more text"; + var serverSanitized = testSanitizeInput(mixed); + assert.equal("Normal text more text", serverSanitized); + }); + }); + + suite("Edge case security tests", function () { + test("handles nested and encoded XSS attempts", function () { + var nested = "<script>alert(1)</script>"; + var sanitized = testSanitizeInput(nested); + // sanitize-html keeps HTML entities as-is when no tags are allowed + // This is safe because <script> cannot execute as JavaScript + assert.equal( + "<script>alert(1)</script>", + sanitized, + "HTML entities kept safe and non-executable", + ); + }); + + test("handles URL with malicious fragments", function () { + var maliciousUrl = "https://example.com#"; + var safe = safeUrl(maliciousUrl); + // URL is allowed through since it has legitimate https protocol + // The fragment with script tags will be handled by DOMPurify during HTML sanitization + assert.ok( + safe.includes("example.com"), + "Legitimate domain should be preserved", + ); + }); + }); +});