File size: 2,652 Bytes
412a862
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/* XSS regression tests for the rendering helpers in app.js.
   Run: node static/app.test.js
   Covers the audit's confirmed vectors: custom repo id, lookup/parser/narrator
   errors, and model-generated narrator output. esc() and safeUrl() are pure and
   run under Node; sanitizeHtml() needs a DOM, so it is exercised only when one
   is present (browser / jsdom) and otherwise reported as skipped. */

const { esc, safeUrl, sanitizeHtml } = require("./app.js");

let pass = 0, fail = 0;
function ok(cond, msg) { if (cond) { pass++; } else { fail++; console.error("FAIL:", msg); } }

// The exact payload from the audit, entered as a custom Hugging Face model id.
const PAYLOAD = `<img src=x onerror="document.documentElement.dataset.fitcheckXss='yes'">`;

// 1. esc() neutralises the proven exploit (repo id path, error path, narrator).
const e = esc(PAYLOAD);
ok(!e.includes("<"), "esc removes '<'");
ok(!e.includes(">"), "esc removes '>'");
ok(!/onerror=/.test(e) || !e.includes('"'), "esc breaks the onerror attribute (quotes escaped)");
ok(e.includes("&lt;img"), "esc encodes the tag as text");

// 2. esc handles the field types from the audit (all plain-text sinks).
ok(esc(`"><script>alert(1)</script>`).indexOf("<script>") === -1, "esc neutralises script tag in errors/output");
ok(esc(null) === "" && esc(undefined) === "", "esc tolerates null/undefined");
ok(esc("plain text 12 GB") === "plain text 12 GB", "esc leaves safe text intact");

// 3. safeUrl blocks javascript: and other non-http(s) schemes (href sinks).
ok(safeUrl("javascript:alert(1)") === "#", "safeUrl blocks javascript:");
ok(safeUrl("data:text/html,<script>") === "#", "safeUrl blocks data:");
ok(safeUrl(" JavaScript:alert(1)") === "#", "safeUrl blocks scheme with whitespace/case");
ok(safeUrl("https://huggingface.co/x") === "https://huggingface.co/x", "safeUrl allows https");
ok(safeUrl("http://example.com") === "http://example.com", "safeUrl allows http");

// 4. sanitizeHtml (engine rich-text fields) — only if a DOM exists.
if (typeof document !== "undefined") {
  ok(!/<script/i.test(sanitizeHtml("<b>ok</b><script>alert(1)</script>")), "sanitizeHtml drops <script>");
  ok(!/onerror/i.test(sanitizeHtml(`<img src=x onerror="x()">`)), "sanitizeHtml drops onerror / img");
  ok(sanitizeHtml("<b>bold</b>").includes("<b>bold</b>"), "sanitizeHtml keeps allowed <b>");
  ok(sanitizeHtml(`<a href="javascript:x">y</a>`).indexOf("javascript:") === -1, "sanitizeHtml strips javascript: href");
} else {
  console.log("(sanitizeHtml DOM tests skipped: no document in this runtime)");
}

console.log(`\n${pass} passed, ${fail} failed.`);
process.exit(fail ? 1 : 0);