feat(okf): scan reserved index.md/log.md in mode-b import, not path-reject (review MAJOR #2)
A received OKF bundle MAY legitimately carry index.md (directory listing, read first under progressive disclosure) and log.md (update history) at any level (spec §3.1/§6/§7). import_bundle previously hard-rejected those basenames in the T4 path gate, so a conformant third-party bundle was over-blocked in full (FAIL_SECURE) — and because the reject fired before scan_concept, index.md's body (the highest-priority injection surface) was never scanned. import_bundle now defaults allow_reserved=True: reserved basenames are scanned as structural files (path-safety checks — traversal / absolute / backslash / .md — still apply). The shadow-reject (an *upload* masquerading as index.md) is preserved: the front-end passes allow_reserved=False so a materialized upload landing on a reserved basename is still refused. That front-end opt-in was required to keep the shadow-reject once the default flipped (not in the plan's Filer set; traced from the code). - okf.py: validate_concept_path/_validate_concept/import_bundle gain the keyword; validate_concept_path default stays False (strict standalone). - tests: +3 (legit index/log admit; injection in index.md body caught; okf_version frontmatter admits). Per-concept-iteration test switched to a traversal vector; mode-b showcase's index.md surface reframed from reserved-name-reject to index.md-body-scan. - README honest-limits + CLAUDE.md context note the mode-b/upload distinction. Suite: 341 -> 344 passed. Core invariant intact (dependencies=[]).
This commit is contained in:
parent
4d53765c63
commit
0772dafb70
6 changed files with 105 additions and 18 deletions
|
|
@ -3,8 +3,9 @@
|
|||
The OKF analogue of ``tests/test_showcase.py``: one realistic *received external
|
||||
OKF bundle* that plants one attack per OKF surface at once — a body injection, a
|
||||
frontmatter-``description`` injection, a non-``https`` ``resource:``, a
|
||||
path-traversal concept key, a reserved-name shadow, a dangerous frontmatter
|
||||
value, a dangerous-scheme cross-link, a dangling cross-link, and a
|
||||
path-traversal concept key, an injection in a reserved ``index.md`` body, a
|
||||
dangerous frontmatter value, a dangerous-scheme cross-link, a dangling
|
||||
cross-link, and a
|
||||
homoglyph-obfuscated body injection — run through the public ``okf`` surface
|
||||
exactly as an "upload inbox" consumer would compose it. Every planted surface is
|
||||
caught or rejected and the aggregate disposition fails secure.
|
||||
|
|
@ -73,8 +74,10 @@ def _poisoned_bundle() -> dict:
|
|||
"dangerous-frontmatter.md": "---\ntype: &anchor table\n---\nbody\n",
|
||||
# T4 — a path-traversal concept key escapes the bundle root.
|
||||
"../escape.md": "---\ntype: table\n---\nbody\n",
|
||||
# T4 — a reserved basename shadows the directory listing.
|
||||
"index.md": "---\ntype: table\ndescription: Listing.\n---\nbody\n",
|
||||
# A2 — index.md is a legitimate structural file in a *received* bundle
|
||||
# (not path-rejected in mode-b), but its body IS scanned: an injection
|
||||
# planted in the directory listing is caught, not silently admitted.
|
||||
"index.md": "---\ntype: table\ndescription: Listing.\n---\n" + _INJECTION + "\n",
|
||||
# LLM05 — the zero-click EchoLeak primitive: an auto-fetched markdown
|
||||
# image URL that exfiltrates the moment the concept is rendered.
|
||||
"echoleak.md": (
|
||||
|
|
@ -124,7 +127,7 @@ def _surface_checks(result: BundleResult) -> dict:
|
|||
desc = by_path.get("frontmatter-desc.md")
|
||||
return {
|
||||
"T4:path-traversal": rejected("../escape.md"),
|
||||
"T4:reserved-name": rejected("index.md"),
|
||||
"A2:index-body-scanned": caught("index.md", "override:ignore-previous"),
|
||||
"T3:resource": rejected("bad-resource.md"),
|
||||
"T2:frontmatter": rejected("dangerous-frontmatter.md"),
|
||||
"T1:body-injection": caught("body-injection.md", "override:ignore-previous"),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue