code wiki / _hdl_build / nx_html_sanitize_test.nx

nx_html_sanitize_test.nx source

↩ module page · 97 lines · 5595 B

1// nx_html_sanitize_test.nx -- ENGINEER verification of the CMS sanitizer keystone: byte-exact KATs 2// over REAL stored-XSS vectors (script, event handlers, javascript: URLs, case games, unterminated 3// tags, style content, quote-embedded '>'), plus the escape-on-render path. Exit 0 = all green. 4import "nx_html_sanitize.nx" 5import "nx_syscalls.nx" 6 7func ht_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 8func ht_len(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 9 10// run one sanitize KAT: returns 1 on byte-exact match, prints a FAIL line otherwise 11func ht_kat(id: i64, inp: *u8, want: *u8) -> i64 { 12 let out: *u8 = sys_mmap(4096) 13 let ol: i64 = hs_sanitize(inp, ht_len(inp), out, 4095) 14 let wl: i64 = ht_len(want) 15 var ok: i64 = 1 16 if ol != wl { ok = 0 } 17 if ok == 1 { 18 var i: i64 = 0 19 while i < ol { if (out[i] as i64) != (want[i] as i64) { ok = 0 } i = i + 1 } 20 } 21 if ok == 0 { 22 ht_w("FAIL KAT " as *u8) 23 let d: *u8 = sys_mmap(8); d[0] = (48 + id/10) as u8; d[1] = (48 + id%10) as u8; d[2] = 0 as u8 24 ht_w(d); ht_w(": got [" as *u8); sys_write(1, out, ol); ht_w("] want [" as *u8); ht_w(want); ht_w("]\n" as *u8) 25 } 26 return ok 27} 28 29// seq677: the span-adapter every HTML emitter is meant to share MUST agree with hs_escape byte-for-byte, 30// and must neutralise the exact payload that was LIVE on /standup (journal text containing <main>/<nav>). 31// Non-vacuous by construction: it also asserts a mid-buffer span (offset preserved) and control->space. 32func ht_kat_span(id: i64, inp: *u8, want: *u8) -> i64 { 33 let a: *u8 = sys_mmap(4096) 34 let n: i64 = ht_len(inp) 35 let al: i64 = hs_escape(inp, n, a, 4095) 36 let b: *u8 = sys_mmap(4096) 37 let bl: i64 = hs_cat_esc_span(b, 0, inp, 0, n, 4095) 38 var ok: i64 = 1 39 if al != bl { ok = 0 } 40 if ok == 1 { var i: i64 = 0; while i < al { if (a[i] as i64) != (b[i] as i64) { ok = 0 } i = i + 1 } } 41 let wl: i64 = ht_len(want) 42 if bl != wl { ok = 0 } 43 if ok == 1 { var j: i64 = 0; while j < wl { if (b[j] as i64) != (want[j] as i64) { ok = 0 } j = j + 1 } } 44 let c: *u8 = sys_mmap(4096) 45 var co: i64 = 0 46 co = hs_emit(c, co, 4095, "PRE:" as *u8) 47 co = hs_cat_esc_span(c, co, inp, 0, n, 4095) 48 if co != 4 + bl { ok = 0 } 49 if ok == 1 { var k: i64 = 0; while k < bl { if (c[4+k] as i64) != (b[k] as i64) { ok = 0 } k = k + 1 } } 50 if ok == 0 { ht_w("FAIL SPAN KAT\n" as *u8) } 51 return ok 52} 53 54func ht_kat_esc(id: i64, inp: *u8, want: *u8) -> i64 { 55 let out: *u8 = sys_mmap(4096) 56 let ol: i64 = hs_escape(inp, ht_len(inp), out, 4095) 57 let wl: i64 = ht_len(want) 58 var ok: i64 = 1 59 if ol != wl { ok = 0 } 60 if ok == 1 { 61 var i: i64 = 0 62 while i < ol { if (out[i] as i64) != (want[i] as i64) { ok = 0 } i = i + 1 } 63 } 64 if ok == 0 { ht_w("FAIL ESC KAT\n" as *u8) } 65 return ok 66} 67 68func main() -> i64 { 69 var pass: i64 = 0 70 var total: i64 = 0 71 total = total + 1; pass = pass + ht_kat(1, "<script>alert(1)</script>Hello" as *u8, "Hello" as *u8) 72 total = total + 1; pass = pass + ht_kat(2, "<img src=x onerror=alert(1)>Hi" as *u8, "Hi" as *u8) 73 total = total + 1; pass = pass + ht_kat(3, "<a href=\"javascript:alert(1)\">x</a>" as *u8, "<a>x</a>" as *u8) 74 total = total + 1; pass = pass + ht_kat(4, "<a href=\"https://ok.com\">x</a>" as *u8, "<a href=\"https://ok.com\">x</a>" as *u8) 75 total = total + 1; pass = pass + ht_kat(5, "<b onmouseover=evil()>bold</b>" as *u8, "<b>bold</b>" as *u8) 76 total = total + 1; pass = pass + ht_kat(6, "a < b" as *u8, "a &lt; b" as *u8) 77 total = total + 1; pass = pass + ht_kat(7, "<P>case</P>" as *u8, "<p>case</p>" as *u8) 78 total = total + 1; pass = pass + ht_kat(8, "<div><b>x</b></div>" as *u8, "<b>x</b>" as *u8) 79 total = total + 1; pass = pass + ht_kat(9, "ok<b" as *u8, "ok&lt;b" as *u8) 80 total = total + 1; pass = pass + ht_kat(10, "<STYLE>p{color:red}</STYLE>ok" as *u8, "ok" as *u8) 81 total = total + 1; pass = pass + ht_kat(11, "<a href=javascript:x>y</a>" as *u8, "<a>y</a>" as *u8) 82 total = total + 1; pass = pass + ht_kat(12, "<a href=\"/about\">y</a>" as *u8, "<a href=\"/about\">y</a>" as *u8) 83 total = total + 1; pass = pass + ht_kat(13, "<a href=\"java script:alert(1)\">y</a>" as *u8, "<a>y</a>" as *u8) 84 total = total + 1; pass = pass + ht_kat(14, "<img alt=\"a>b\" onerror=alert(1)>z" as *u8, "z" as *u8) 85 total = total + 1; pass = pass + ht_kat(15, "<SCRIPT SRC=evil.js></SCRIPT>tail" as *u8, "tail" as *u8) 86 total = total + 1; pass = pass + ht_kat(16, "<ul><li>one</li></ul>" as *u8, "<ul><li>one</li></ul>" as *u8) 87 total = total + 1; pass = pass + ht_kat(17, "<A HREF='HTTPS://X.Y'>u</A>" as *u8, "<a href=\"HTTPS://X.Y\">u</a>" as *u8) 88 total = total + 1; pass = pass + ht_kat(18, "<form action=\"/steal\"><input></form>f" as *u8, "f" as *u8) 89 total = total + 1; pass = pass + ht_kat_esc(19, "Smith & Wesson <LLP> \"quote\" 'tick'" as *u8, "Smith &amp; Wesson &lt;LLP&gt; &quot;quote&quot; &#39;tick&#39;" as *u8) 90 total = total + 1; pass = pass + ht_kat_span(20, "flags <main>/<nav> landmark-loss & \"x\" 'y'" as *u8, "flags &lt;main&gt;/&lt;nav&gt; landmark-loss &amp; &quot;x&quot; &#39;y&#39;" as *u8) 91 ht_w("SANITIZE KATs pass=" as *u8) 92 let d: *u8 = sys_mmap(8); d[0] = (48 + pass/10) as u8; d[1] = (48 + pass%10) as u8; d[2] = 47 as u8; d[3] = (48 + total/10) as u8; d[4] = (48 + total%10) as u8; d[5] = 10 as u8; d[6] = 0 as u8 93 ht_w(d) 94 if pass == total { sys_exit(0) } 95 sys_exit(1) 96 return 1 97}