code wiki / _hdl_build / nx_html_sanitize.nx
nx_html_sanitize.nx
buildroot/runtime/_hdl_build/nx_html_sanitize.nx
about
nx_html_sanitize.nx -- CMS ladder step 9 (KEYSTONE): KSES-style HTML ALLOWLIST sanitizer, run on
WRITE at the /admin/save boundary (global rule 12: defensive at boundaries). Everything not on the
allowlist is REMOVED, never blocklisted: unknown tags stripped (inner text kept), ALL attributes
dropped except a@href, href accepted ONLY for http:// https:// / # schemes (post-filter, so
"java\tscript:" tricks die with the filtered whitespace), <script>/<style> CONTENT stripped too,
stray '<' escaped to <. Quote-aware '>' scan (a '>' inside a quoted attribute does not end the
tag). hs_escape = full entity escape for plain-text fields (escape-on-render, defense in depth).
Allowlist = packed table HS_TAGS (data-driven, rule 11) -- add a tag = add a table entry.
NEEDS_TUTOR build (PARSER shape, not yet emitter-covered): Claude authored, Engineer KATs = real
XSS vectors in nx_html_sanitize_test.nx. LAWS: struct-free, integer-only, flat ifs. license_tier: ORIGINAL
dependencies 1 imports · 9 importers
imports: nx_syscalls.nx
imported by: _pe_blockr.nx_pe_seohead.nx_wb_tmpl.nxnx_cms_draft_exceed_gate.nxnx_cms_render.nxnx_html_sanitize_test.nxnx_sitegen.nxnx_sitegen_freeform.nxnx_sitegen_video.nx
structs
| none |
consts
| 14 | const HS_TAGS: *u8 = "b\0i\0u\0em\0strong\0p\0br\0ul\0ol\0li\0a\0h2\0h3\0blockquote\0\0" |
functions
| 16 | func hs_lc(c: i64) -> i64 { if c >= 65 { if c <= 90 { return c + 32 } } return c } |
| 17 | func hs_alpha(c: i64) -> i64 { let l: i64 = hs_lc(c); if l >= 97 { if l <= 122 { return 1 } } return 0 } |
| 18 | func hs_digit(c: i64) -> i64 { if c >= 48 { if c <= 57 { return 1 } } return 0 } called by 1: hs_name_at |
| 21 | func hs_tag_allowed(t: *u8, tl: i64) -> i64 called by 1: hs_sanitize |
| 41 | func hs_emitb(out: *u8, o: i64, cap: i64, c: i64) -> i64 |
| 46 | func hs_emit(out: *u8, o: i64, cap: i64, s: *u8) -> i64 |
| 54 | func hs_name_at(inp: *u8, n: i64, j: i64, tbuf: *u8) -> i64 |
| 71 | func hs_find_gt(inp: *u8, n: i64, i: i64) -> i64 |
| 87 | func hs_skip_close(inp: *u8, n: i64, j: i64, tbuf: *u8, tl: i64) -> i64 |
| 110 | func hs_href_value(inp: *u8, gt: i64, v: i64, hbuf: *u8, hcap: i64) -> i64 called by 1: hs_href_extract |
| 136 | func hs_href_extract(inp: *u8, n: i64, i: i64, gt: i64, hbuf: *u8, hcap: i64) -> i64 |
| 164 | func hs_scheme_ok(h: *u8, hl: i64) -> i64 |
| 184 | func hs_sanitize(inp: *u8, n: i64, out: *u8, cap: i64) -> i64 called by 3: ca_save_fieldmainht_kat calls 9: sys_mmaphs_emitbhs_name_aths_emiths_find_gths_tag_allowed+3 |
| 261 | func hs_cat_esc_span(d: *u8, o: i64, q: *u8, s: i64, e: i64, cap: i64) -> i64 |
| 279 | func hs_escape(inp: *u8, n: i64, out: *u8, cap: i64) -> i64 called by 13: _pe_blockr_put_pe_seohead_put_wb_tmpl_putca_esc_intoca_stats_pageca_subs_page+7 calls 2: hs_emiths_emitb |