[scan] Security attack vector mapping #5

Open
opened 2026-03-23 12:54:03 +00:00 by Virgil · 1 comment
Member

Map every external input entry point: function, file:line, input source, flows into, validation, attack vector.


Implementation Plan (Spark)

[scan] Security attack vector mapping — implementation plan

1) Files to scan

  • codegen/codegen.go
  • cmd/codegen/main.go
  • cmd/wasm/register.go
  • cmd/wasm/main.go
  • context.go
  • layout.go
  • node.go
  • path.go
  • pipeline.go
  • responsive.go
  • render.go

2) Scan focus

For each file, check:

  • External input entry points (function params, map keys/values, callbacks, args, CLI/stdin payloads, JS-WASM bridge args)
  • Validation gaps (missing allow-lists, format checks, length/capacity bounds, nil/state checks)
  • Injection vectors (HTML/JS/shell/JSON template/context escape gaps)
  • Race conditions (shared mutable Node/layout/context state with no guard)

3) Evidence format required for report

Use this exact row structure in findings:

file:line | input source | flows into | current validation | attack vector

Use one row per finding.

4) Report location

Write/update the report in the issue body itself (preferred), and also persist the working draft at:

./SECURITY-ATTACK-VECTOR-MAPPING-PLAN.md

Then copy the table rows from this plan file into the issue body.

5) Mapping targets (entry points to enumerate)

file:line input source flows into current validation attack vector
codegen/codegen.go:34 tag in GenerateClass(tag, slot string) and slot in same function Template rendering for JavaScript class + wcTemplate payload Validates only strings.Contains(tag, "-") Possible JS injection via unescaped tag/slot interpolation in JS template string, and invalid tag names from untrusted source
codegen/codegen.go:53 className in GenerateRegistration(tag, className string) and tag JS output customElements.define("%s", %s) className is untrusted by function contract JS injection through unquoted identifier position if class name contains special chars
codegen/codegen.go:57 tag in TagToClassName(tag) Class name derivation used by registration path No validation of tag grammar, only string transform Identifier injection / malformed JS token generation when upstream tag is untrusted
codegen/codegen.go:71 slots map in GenerateBundle(slots) (values are tags, keys are slots) Iterates all entries and calls GenerateClass No key/value canonicalization or size limits Unbounded/abuse of map input size and attacker-controlled duplicate keys/values can amplify output and payload size
cmd/codegen/main.go:163 r io.Reader content (stdin) as JSON map json.Unmarshal -> GenerateBundle -> stdout JS JSON parse only JSON-based injection/denial vector before bundle generation if caller controls stdin
cmd/wasm/main.go:263 slotsJSON argument to buildComponentJS JSON parse -> GenerateBundle JSON parse only Same as above (non-CLI call sites or future callers), malformed/massive payload risk
cmd/wasm/register.go:208 args[0] -> variant html.NewLayout(variant) and layout rendering No validation of variant characters/length Variant-driven rendering surface; odd characters can shift output shape and create unexpected DOM shape/logic behaviour
cmd/wasm/register.go:211 args[1] -> ctx.Locale html.Context passed into rendering pipeline Locale is trusted as string with no checks Injection risk is low for locale itself, but can break locale-sensitive rendering or cause logic abuse in custom service hooks
cmd/wasm/register.go:217 args[2] object slots values for H/L/C/R/F html.Raw(content.String()) then layout.Render output Type check for string + non-empty only High-risk raw HTML sink; direct DOM injection path if JS callers send untrusted content
cmd/wasm/register.go:260 slots object keys H/L/C/R/F Slot lookup and rendering switch Fixed key set, but key presence not validated against expected shape Unexpected keys ignored; useful to verify contract assumptions for bridge callers
context.go:7 External data via Context.Data map[string]any and Context.Entitlements consumed by downstream Entitled/Text/custom predicates No write-time validation in struct Mutable context shared across goroutines can produce races when untrusted render pipelines access it
layout.go:60 variant in NewLayout(variant) Controls rendered slots in Layout.Render No validation of grammar/length Unknown chars silently dropped; potential policy bypass confusion and DoS via malformed/long variants
layout.go:68 nodes in Layout.H/L/C/R/F Insert into internal mutable slot slices No nil/type guard beyond interface acceptance Mutating shared layout trees from multiple goroutines can race and cross-request content mixing
layout.go:104 ctx and layout slot contents Renders tags and recursively calls child Render Escapes attribute/tag names, but renders child nodes as opaque Race risk via shared layout map and nested layout path mutation (clone.path)
node.go:59 content in Raw(content string) Render output n.content without escaping No validation by design (explicit trusted-only hatch) High-impact XSS sink if caller passes attacker input without sanitisation
node.go:76 tag and children in El(tag, children...) Render path writes tag in HTML escapeHTML on tag string HTML syntax is escaped, but attacker controls tag names/structure and can induce parser ambiguity/DoS via large structures
node.go:86 key, value, wrapper node in Attr(n, key, value) Attribute serialization/escaping in elNode.Render No key-value validation beyond type checks Attacker can flood/abuse attribute map size if shared node reused; injection mostly mitigated by escaping
node.go:150 key, args in Text(key, args...) Translation resolution then escapeHTML No validation for translation keys before rendering If translation source is external, malicious content can still flow if later code path skips expected escaping or uses unsafe translation service implementation
node.go:172 cond function in If(cond, node) Conditional branch execution No nil guard for cond/node deref risk if caller passes nil Panic/DoS through nil function or nil node under hostile construction
node.go:191 cond function in Unless(cond, node) Same as above Same as above Same as above
node.go:211 feature in Entitled(feature, node) Gate check in render Default deny if context or function nil; no canonicalisation of feature Logic bypass if entitlement function comes from untrusted context and maps features dynamically
node.go:230 selector function and cases map in Switch Branch selection by map lookup key No check for nil selector/map contents Panic/logic abuse with nil selector/map in hostile composition
node.go:250 items (iter.Seq) and fn in Each/EachSeq Iterative rendering pipeline No bound checks; no panic wrapping Iterator-driven DoS through infinite iterators or panicking callbacks
path.go:418 id in ParseBlockID Returns byte slice used for programmatic traversal No format strictness, accepts malformed sequences Path-confusion risk for downstream consumers that trust parsed slots
pipeline.go:448 html in StripTags Output text for tokeniser + imprint and similarity checks Incomplete parse logic and minimal state handling Crafted input can cause inaccurate text extraction / algorithmic abuse for malformed tags
pipeline.go:482 node, ctx in Imprint End-to-end render + StripTags + tokenisation pipeline No output size guard Memory/time amplification with large rendered trees
pipeline.go:495 r, ctx in CompareVariants Multiple Imprint() calls and similarity map No bounds checks on variant count Quadratic cost with large variant arrays (time DoS)
responsive.go:551 name, layout in Variant Inserted into data attributes and variant list No validation for name; layout can be nil Nil layout causes panic in render; unvalidated name can be abused for very large outputs
responsive.go:557 ctx + list of variants in Responsive.Render Writes data-variant and renders each layout No nil/length checks Panic on nil layout pointer or unbounded work with many variants
render.go:523 node, ctx in Render Public render entrypoint Nil ctx defaulted to NewContext Single function-level sink requiring root-level input sanitation in callers

6) Execution plan for Codex

  1. Confirm scope against this list and walk each file top-down.
  2. For each input point, document:
    • Exact caller-controlled source
    • Data path to sinks (HTML/JS output, context mutation, iterator execution)
    • Existing validation and its weakness
    • Impact and severity
  3. Keep rows in severity buckets and include reproducible example payloads where possible.
  4. Mark all Raw() and renderToString slot paths as high-priority findings by default.
  5. Add explicit risk notes for race conditions where Node/Layout/Context objects are mutable and reused across goroutines.
Map every external input entry point: function, file:line, input source, flows into, validation, attack vector. --- ## Implementation Plan (Spark) # [scan] Security attack vector mapping — implementation plan ## 1) Files to scan - `codegen/codegen.go` - `cmd/codegen/main.go` - `cmd/wasm/register.go` - `cmd/wasm/main.go` - `context.go` - `layout.go` - `node.go` - `path.go` - `pipeline.go` - `responsive.go` - `render.go` ## 2) Scan focus For each file, check: - External input entry points (function params, map keys/values, callbacks, args, CLI/stdin payloads, JS-WASM bridge args) - Validation gaps (missing allow-lists, format checks, length/capacity bounds, nil/state checks) - Injection vectors (HTML/JS/shell/JSON template/context escape gaps) - Race conditions (shared mutable Node/layout/context state with no guard) ## 3) Evidence format required for report Use this exact row structure in findings: `file:line | input source | flows into | current validation | attack vector` Use one row per finding. ## 4) Report location Write/update the report in the issue body itself (preferred), and also persist the working draft at: `./SECURITY-ATTACK-VECTOR-MAPPING-PLAN.md` Then copy the table rows from this plan file into the issue body. ## 5) Mapping targets (entry points to enumerate) | file:line | input source | flows into | current validation | attack vector | | --- | --- | --- | --- | --- | | `codegen/codegen.go:34` | `tag` in `GenerateClass(tag, slot string)` and `slot` in same function | Template rendering for JavaScript class + `wcTemplate` payload | Validates only `strings.Contains(tag, "-")` | Possible JS injection via unescaped tag/slot interpolation in JS template string, and invalid tag names from untrusted source | | `codegen/codegen.go:53` | `className` in `GenerateRegistration(tag, className string)` and `tag` | JS output `customElements.define("%s", %s)` | `className` is untrusted by function contract | JS injection through unquoted identifier position if class name contains special chars | | `codegen/codegen.go:57` | `tag` in `TagToClassName(tag)` | Class name derivation used by registration path | No validation of `tag` grammar, only string transform | Identifier injection / malformed JS token generation when upstream tag is untrusted | | `codegen/codegen.go:71` | `slots` map in `GenerateBundle(slots)` (values are tags, keys are slots) | Iterates all entries and calls `GenerateClass` | No key/value canonicalization or size limits | Unbounded/abuse of map input size and attacker-controlled duplicate keys/values can amplify output and payload size | | `cmd/codegen/main.go:163` | `r io.Reader` content (`stdin`) as JSON map | `json.Unmarshal` -> `GenerateBundle` -> stdout JS | JSON parse only | JSON-based injection/denial vector before bundle generation if caller controls stdin | | `cmd/wasm/main.go:263` | `slotsJSON` argument to `buildComponentJS` | JSON parse -> `GenerateBundle` | JSON parse only | Same as above (non-CLI call sites or future callers), malformed/massive payload risk | | `cmd/wasm/register.go:208` | `args[0]` -> `variant` | `html.NewLayout(variant)` and layout rendering | No validation of variant characters/length | Variant-driven rendering surface; odd characters can shift output shape and create unexpected DOM shape/logic behaviour | | `cmd/wasm/register.go:211` | `args[1]` -> `ctx.Locale` | `html.Context` passed into rendering pipeline | Locale is trusted as string with no checks | Injection risk is low for locale itself, but can break locale-sensitive rendering or cause logic abuse in custom service hooks | | `cmd/wasm/register.go:217` | `args[2]` object `slots` values for `H/L/C/R/F` | `html.Raw(content.String())` then `layout.Render` output | Type check for string + non-empty only | High-risk raw HTML sink; direct DOM injection path if JS callers send untrusted content | | `cmd/wasm/register.go:260` | `slots` object keys `H/L/C/R/F` | Slot lookup and rendering switch | Fixed key set, but key presence not validated against expected shape | Unexpected keys ignored; useful to verify contract assumptions for bridge callers | | `context.go:7` | External data via `Context.Data map[string]any` and `Context.Entitlements` | consumed by downstream `Entitled`/`Text`/custom predicates | No write-time validation in struct | Mutable context shared across goroutines can produce races when untrusted render pipelines access it | | `layout.go:60` | `variant` in `NewLayout(variant)` | Controls rendered slots in `Layout.Render` | No validation of grammar/length | Unknown chars silently dropped; potential policy bypass confusion and DoS via malformed/long variants | | `layout.go:68` | `nodes` in `Layout.H/L/C/R/F` | Insert into internal mutable slot slices | No nil/type guard beyond interface acceptance | Mutating shared layout trees from multiple goroutines can race and cross-request content mixing | | `layout.go:104` | `ctx` and layout slot contents | Renders tags and recursively calls child Render | Escapes attribute/tag names, but renders child nodes as opaque | Race risk via shared layout map and nested layout path mutation (`clone.path`) | | `node.go:59` | `content` in `Raw(content string)` | Render output `n.content` without escaping | No validation by design (explicit trusted-only hatch) | High-impact XSS sink if caller passes attacker input without sanitisation | | `node.go:76` | `tag` and `children` in `El(tag, children...)` | Render path writes tag in HTML | `escapeHTML` on tag string | HTML syntax is escaped, but attacker controls tag names/structure and can induce parser ambiguity/DoS via large structures | | `node.go:86` | `key`, `value`, wrapper `node` in `Attr(n, key, value)` | Attribute serialization/escaping in `elNode.Render` | No key-value validation beyond type checks | Attacker can flood/abuse attribute map size if shared node reused; injection mostly mitigated by escaping | | `node.go:150` | `key`, `args` in `Text(key, args...)` | Translation resolution then `escapeHTML` | No validation for translation keys before rendering | If translation source is external, malicious content can still flow if later code path skips expected escaping or uses unsafe translation service implementation | | `node.go:172` | `cond` function in `If(cond, node)` | Conditional branch execution | No nil guard for `cond`/`node` deref risk if caller passes nil | Panic/DoS through nil function or nil node under hostile construction | | `node.go:191` | `cond` function in `Unless(cond, node)` | Same as above | Same as above | Same as above | | `node.go:211` | `feature` in `Entitled(feature, node)` | Gate check in render | Default deny if context or function nil; no canonicalisation of feature | Logic bypass if entitlement function comes from untrusted context and maps features dynamically | | `node.go:230` | `selector` function and `cases map` in `Switch` | Branch selection by map lookup key | No check for nil selector/map contents | Panic/logic abuse with nil selector/map in hostile composition | | `node.go:250` | `items` (`iter.Seq`) and `fn` in `Each`/`EachSeq` | Iterative rendering pipeline | No bound checks; no panic wrapping | Iterator-driven DoS through infinite iterators or panicking callbacks | | `path.go:418` | `id` in `ParseBlockID` | Returns byte slice used for programmatic traversal | No format strictness, accepts malformed sequences | Path-confusion risk for downstream consumers that trust parsed slots | | `pipeline.go:448` | `html` in `StripTags` | Output text for tokeniser + imprint and similarity checks | Incomplete parse logic and minimal state handling | Crafted input can cause inaccurate text extraction / algorithmic abuse for malformed tags | | `pipeline.go:482` | `node`, `ctx` in `Imprint` | End-to-end render + StripTags + tokenisation pipeline | No output size guard | Memory/time amplification with large rendered trees | | `pipeline.go:495` | `r`, `ctx` in `CompareVariants` | Multiple `Imprint()` calls and similarity map | No bounds checks on variant count | Quadratic cost with large variant arrays (time DoS) | | `responsive.go:551` | `name`, `layout` in `Variant` | Inserted into data attributes and variant list | No validation for name; layout can be nil | Nil `layout` causes panic in render; unvalidated name can be abused for very large outputs | | `responsive.go:557` | `ctx` + list of variants in `Responsive.Render` | Writes `data-variant` and renders each layout | No nil/length checks | Panic on nil layout pointer or unbounded work with many variants | | `render.go:523` | `node`, `ctx` in `Render` | Public render entrypoint | Nil ctx defaulted to `NewContext` | Single function-level sink requiring root-level input sanitation in callers | ## 6) Execution plan for Codex 1. Confirm scope against this list and walk each file top-down. 2. For each input point, document: - Exact caller-controlled source - Data path to sinks (HTML/JS output, context mutation, iterator execution) - Existing validation and its weakness - Impact and severity 3. Keep rows in severity buckets and include reproducible example payloads where possible. 4. Mark all `Raw()` and `renderToString` slot paths as high-priority findings by default. 5. Add explicit risk notes for race conditions where Node/Layout/Context objects are mutable and reused across goroutines.
Author
Member

Security Scan: Attack Vector Map completed. Details in agent log.

## Security Scan: Attack Vector Map completed. Details in agent log.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

-

Dependencies

No dependencies set.

Reference: core/go-html#5
No description provided.