Development record
fenceMask spans the frontmatter so a fence delimiter inside a block scalar switches off the excluded key scan for the rest of the block
fenceMask spans the frontmatter so a fence delimiter inside a block scalar switches off the excluded key scan for the rest of the block
Found by the round-10 adversarial security review of build/itd-183. NOT introduced by this branch -- it is present on the round-9 parent too, and is recorded rather than chased under the ruling that round 10 closes only what the branch introduced.
fenceMask is computed over the WHOLE document, frontmatter included, so a
fence delimiter written inside a frontmatter block scalar toggles the mask on
and marks the rest of the block as fenced. Both excludedKeyInFirstBlock and
unresolvableFrontmatterShape skip a fenced line, so every key spelling
frontmatter.Fields does not itself report then travels:
---
a: |
```
"origin": <value>
b: |
```
---
A YAML reader reads a top-level origin there. Fields wants an unquoted key
at column 0 and does not report it, the redactor drops nothing, and the refusal
that exists to catch exactly that gap is switched off. Verified leaking on this
round and on the parent, for the quoted spelling and for the indented one.
Candidate remedies: scope fenceMask to the body, or refuse a frontmatter block
containing a fence delimiter -- the second is the cheaper and matches how
unresolvableFrontmatterShape already answers a construction this package will
not parse. Seed material for the exclusion floor's own intent.
Grounds
- pursued: we expect locating the frontmatter block before any mask is computed, and refusing a fence delimiter inside it, to close the switch-off path rather than one spelling of it, because the mask can no longer be toggled from a region the key scan is walking; a document whose frontmatter carries a fence and still assembles, or an excluded key surviving inside a block the manifest marks parsed, would show it wrong
Frontmatter
| id | iss-2608301350533102 |
|---|---|
| type | issue |
| lifecycle | resolved |
| severity | critical |
.abcd/work/issues/resolved/iss-2608301350533102-fencemask-spans-the-frontmatter-so-a.md
open on GitHub ↗ · commit history ↗
mentions4
- iss-2609250955207041The cold-reading exclusion floor can be walked through by a fence shape both of its halves misread the same way, so an excluded heading's section travels in the bundle and nothing refuses. redactExcluded finds headings through site.Sections, whose private fence toggle (iss-2609250955051598) flips a boolean on every line that starts with three backticks. verifyRedaction re-checks with bodyFenceMask, a second private backtick-only toggle, so the two agree on the wrong answer. Probe at 70daf701: a document holding a four-backtick fence that quotes a bare three-backtick line, then '## Private Notes' with a body line, then a ~~~ block holding a three-backtick line. redactExcluded with the heading Private Notes excluded returns nil error and the body line still in the output. Under CommonMark (mdrecord.Mask) the heading is live. The four-backtick block is one fence, and the three-backtick line inside the tilde block is literal. So the manifest asserts a refusal that did not happen, the silent-bypass class iss-2608301350533102 closed for a delimiter inside the frontmatter. The fix is not a one-line swap. Moving the verifier onto mdrecord.Mask would make it refuse this shape, but mdrecord also masks HTML comments, and comment text travels to the reader, so the floor's view of comments needs a decision.
- itd-183The cold reading sees exactly what the assembler passes — positive inclusion, field projection, and a per-run manifest
- itd-194The reading include table admits only what the exclusion floor can read
- spc-2609021003136831The include table declares what the floor parses, the floor refuses the markdown it cannot resolve, and the manifest marks every item it did not examine