code wiki / _hdl_build / nx_adnet_submit_gate.nx
nx_adnet_submit_gate.nx source
↩ module page · 127 lines · 6733 B
1// nx_adnet_submit_gate.nx -- GATE for the self-serve intake surface (nx_adnet_submit). Proves: the GET form
2// renders zero-JS with all fields; a VALID POST stages a row (read-back verified) and shows confirmation; a
3// malicious POST (external img / javascript: click / bad slug) is REJECTED, re-populates the form ESCAPED,
4// and stages NOTHING (load-bearing negative control on the live journal); reflected XSS in a field stays
5// escaped. expect_exit: 0 license_tier: ORIGINAL
6import "nx_syscalls.nx"
7import "_hdl_build/nx_adnet_submit.nx"
8
9func fg_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
10func fg_putn(v: i64) -> i64 { var m: i64 = v; if m < 0 { fg_puts("-" as *u8); m = 0 - m } let t: *u8 = sys_mmap(24); var k: i64 = 0; if m == 0 { t[0] = 48 as u8; k = 1 } while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } let o: *u8 = sys_mmap(24); var i: i64 = 0; while i < k { o[i] = t[k - 1 - i]; i = i + 1 } sys_write(1, o, k); return 0 }
11
12func fg_has(hay: *u8, n: i64, needle: *u8) -> i64 {
13 var nl: i64 = 0
14 while needle[nl] != (0 as u8) { nl = nl + 1 }
15 if nl == 0 { return 0 }
16 var i: i64 = 0
17 while i + nl <= n {
18 var j: i64 = 0
19 var eq: i64 = 1
20 while j < nl { if hay[i + j] != needle[j] { eq = 0; break } j = j + 1 }
21 if eq == 1 { return 1 }
22 i = i + 1
23 }
24 return 0
25}
26
27func fg_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
28
29func fg_readn(path: *u8, box: *i64) -> *u8 {
30 box[0] = 0
31 return sys_read_file(path, box)
32}
33
34func main() -> i64 {
35 fg_puts("=== nx_adnet_submit_gate ===\n" as *u8)
36 var pass: i64 = 0
37 var fail: i64 = 0
38 let out: *u8 = sys_mmap(65536)
39 let subs: *u8 = "/tmp/adnet_submit_test.log" as *u8
40 let f0: i64 = sys_openat_wr(subs, 0x1A4)
41 if f0 >= 0 { sys_close(f0) }
42
43 // T1 GET form zero-JS with all fields
44 let w0: i64 = asf_form_page(out, 65536)
45 var t1: i64 = 1
46 if w0 <= 0 { t1 = 0 }
47 if fg_has(out, w0, "name=\"slug\"" as *u8) == 0 { t1 = 0 }
48 if fg_has(out, w0, "name=\"business\"" as *u8) == 0 { t1 = 0 }
49 if fg_has(out, w0, "name=\"img\"" as *u8) == 0 { t1 = 0 }
50 if fg_has(out, w0, "name=\"click\"" as *u8) == 0 { t1 = 0 }
51 if fg_has(out, w0, "name=\"section\"" as *u8) == 0 { t1 = 0 }
52 if fg_has(out, w0, "<script" as *u8) == 1 { t1 = 0 }
53 // empty-form fields must render EMPTY (value="") -- guards the ""-literal alias-pool trap that leaked a
54 // stray pooled vhost string ("andelinwest.com") into every field. slug field value must be immediately "".
55 if fg_has(out, w0, "name=\"slug\" value=\"\"" as *u8) == 0 { t1 = 0 }
56 if fg_has(out, w0, "andelinwest" as *u8) == 1 { t1 = 0 }
57 if t1 == 1 { pass = pass + 1 } else { fail = fail + 1; fg_puts("T1 FAIL form render / empty-field alias leak\n" as *u8) }
58
59 // T2 valid POST stages + confirms
60 let good: *u8 = "slug=acme-spring&business=Acme+Co&img=%2Fsynth%2Facme.png&click=https%3A%2F%2Facme.example§ion=home" as *u8
61 let w1: i64 = asf_post(good, fg_slen(good), subs, out, 65536)
62 var t2: i64 = 1
63 if w1 <= 0 { t2 = 0 }
64 if fg_has(out, w1, "Submitted for review" as *u8) == 0 { t2 = 0 }
65 if fg_has(out, w1, "acme-spring" as *u8) == 0 { t2 = 0 }
66 let box: *i64 = sys_mmap(8) as *i64
67 let back1: *u8 = fg_readn(subs, box)
68 if (back1 as i64) == 0 { t2 = 0 } else {
69 if fg_has(back1, box[0], "acme-spring" as *u8) == 0 { t2 = 0 }
70 if fg_has(back1, box[0], "Acme Co" as *u8) == 0 { t2 = 0 }
71 if fg_has(back1, box[0], "/synth/acme.png" as *u8) == 0 { t2 = 0 }
72 }
73 if t2 == 1 { pass = pass + 1 } else { fail = fail + 1; fg_puts("T2 FAIL valid submit\n" as *u8) }
74
75 // T3 external img REJECTED + nothing staged
76 let badimg: *u8 = "slug=evilimg&business=Bad&img=https%3A%2F%2Fevil.example%2Fx.png&click=https%3A%2F%2Fok.example§ion=home" as *u8
77 let w2: i64 = asf_post(badimg, fg_slen(badimg), subs, out, 65536)
78 var t3: i64 = 1
79 if fg_has(out, w2, "Rejected" as *u8) == 0 { t3 = 0 }
80 let back2: *u8 = fg_readn(subs, box)
81 if (back2 as i64) != 0 { if fg_has(back2, box[0], "evilimg" as *u8) == 1 { t3 = 0 } }
82 if t3 == 1 { pass = pass + 1 } else { fail = fail + 1; fg_puts("T3 FAIL external img not rejected\n" as *u8) }
83
84 // T4 javascript: click REJECTED + nothing staged
85 let badclick: *u8 = "slug=evilclick&business=Bad&img=%2Fsynth%2Fb.png&click=javascript%3Aalert(1)§ion=home" as *u8
86 let w3: i64 = asf_post(badclick, fg_slen(badclick), subs, out, 65536)
87 var t4: i64 = 1
88 if fg_has(out, w3, "Rejected" as *u8) == 0 { t4 = 0 }
89 let back3: *u8 = fg_readn(subs, box)
90 if (back3 as i64) != 0 { if fg_has(back3, box[0], "evilclick" as *u8) == 1 { t4 = 0 } }
91 if t4 == 1 { pass = pass + 1 } else { fail = fail + 1; fg_puts("T4 FAIL javascript click not rejected\n" as *u8) }
92
93 // T5 bad slug (uppercase/space) REJECTED
94 let badslug: *u8 = "slug=Bad+Slug&business=Co&img=%2Fsynth%2Fc.png&click=%2Fx§ion=home" as *u8
95 let w4: i64 = asf_post(badslug, fg_slen(badslug), subs, out, 65536)
96 var t5: i64 = 1
97 if fg_has(out, w4, "Rejected" as *u8) == 0 { t5 = 0 }
98 if t5 == 1 { pass = pass + 1 } else { fail = fail + 1; fg_puts("T5 FAIL bad slug not rejected\n" as *u8) }
99
100 // T6 reflected XSS in business field stays escaped in the re-populated form (rejected via external img,
101 // so the form re-renders with the submitted business value -> must be escaped, raw tag absent).
102 let xss: *u8 = "slug=okslug&business=%3Cscript%3Ealert(1)%3C%2Fscript%3E&img=https%3A%2F%2Fevil%2Fx.png&click=%2Fx§ion=home" as *u8
103 let w5b: i64 = asf_post(xss, fg_slen(xss), subs, out, 65536)
104 var t6: i64 = 1
105 if fg_has(out, w5b, "<script>" as *u8) == 0 { t6 = 0 }
106 if fg_has(out, w5b, "<script>alert" as *u8) == 1 { t6 = 0 }
107 if t6 == 1 { pass = pass + 1 } else { fail = fail + 1; fg_puts("T6 FAIL reflected xss not escaped\n" as *u8) }
108
109 fg_puts("pass=" as *u8)
110 fg_putn(pass)
111 fg_puts(" fail=" as *u8)
112 fg_putn(fail)
113 fg_puts("\n" as *u8)
114
115 let log: *u8 = sys_mmap(256)
116 var lo: i64 = 0
117 if fail == 0 { lo = ad_cat(log, lo, "ADNETSUBMIT authored=organ verdict=GREEN" as *u8) } else { lo = ad_cat(log, lo, "ADNETSUBMIT authored=organ verdict=RED" as *u8) }
118 log[lo] = 10 as u8
119 lo = lo + 1
120 let fd: i64 = sys_openat_wr("knowledge/status/adnet_submit.log" as *u8, 0x1A4)
121 if fd >= 0 { sys_write(fd, log, lo); sys_close(fd) }
122
123 if fail == 0 { fg_puts("=== ADNET-SUBMIT-GATE verdict=GREEN ===\n" as *u8); sys_exit(0); return 0 }
124 fg_puts("=== ADNET-SUBMIT-GATE verdict=RED ===\n" as *u8)
125 sys_exit(1)
126 return 1
127}