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 < 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<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 & Wesson <LLP> "quote" 'tick'" as *u8)
90 total = total + 1; pass = pass + ht_kat_span(20, "flags <main>/<nav> landmark-loss & \"x\" 'y'" as *u8, "flags <main>/<nav> landmark-loss & "x" 'y'" 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}