Google's Open Knowledge Format (OKF v0.1) is the LLM-wiki pattern this
library guards. Capture a security brief for OKF ingestion as tracked
future work -- NOT shipped scope. The v0.1 core is format-agnostic text;
OKF surfaces beyond the body (YAML frontmatter, resource URLs, cross-link
graph, file path / reserved names, format-level authenticity) are uncovered.
- Coverage claims verified against the code at 5397ba1 (brief section 9): no
YAML parse in src, neutralize defangs but has no reject-gate, no path/graph
logic, disposition machinery exists.
- OKF confirmed real at the format level (Google Cloud, 2026-06-12; spec
GoogleCloudPlatform/knowledge-catalog).
- Design move: an OKF adapter ON TOP of the format-agnostic core; the core
stays text->findings.
- Section 8 lists 8 v0.2 tasks (T1-T8); T8 (surface two OKF residual risks in
README honest-limits) can land independently.
198 lines
13 KiB
Markdown
198 lines
13 KiB
Markdown
# Security brief: OKF ingestion with `llm-ingestion-guard`
|
||
|
||
**Status:** Draft v0.1 — captured 2026-07-06.
|
||
**Applies to:** write-time ingestion pipelines for LLM wikis based on Google's
|
||
Open Knowledge Format (OKF v0.1).
|
||
**Inputs:** internal and external data, ingested automatically or manually.
|
||
|
||
> This document is a **future-work brief**, not shipped scope. The `v0.1` core
|
||
> (`docs/PLAN.md`, all modules built + hardened at commit `5397ba1`) is
|
||
> **format-agnostic text** (`prepare_input(text)` / `screen_output(text, policy)`).
|
||
> None of the OKF-specific controls below are implemented yet; §8 is the v0.2
|
||
> task list. The coverage claims in §4 were verified against the code on
|
||
> 2026-07-06 — see the verification log in §9.
|
||
|
||
---
|
||
|
||
## 1. Summary
|
||
|
||
OKF is, in practice, exactly the "LLM-wiki" pattern `llm-ingestion-guard` was
|
||
built to protect: untrusted content is enriched/persisted into a markdown corpus
|
||
that a *downstream* agent later reads as **trusted context**. The guard therefore
|
||
belongs at the persist gate, and the existing contract (carrier-strip → fence →
|
||
tool-less transform → capability isolation → output scan → fail-secure) covers the
|
||
markdown *body* directly.
|
||
|
||
OKF, however, introduces five attack surfaces **beyond** the body that must be
|
||
covered explicitly: YAML frontmatter, `resource` URLs, the cross-link graph, file
|
||
path / reserved names, and the absence of format-level authenticity. The largest
|
||
residual risk is **semantic poisoning**, which is out of scope by design (§7).
|
||
|
||
## 2. Scope
|
||
|
||
**In scope:** everything written into or merged into an OKF bundle that the
|
||
pipeline controls — both its own enrichment output and received external bundles.
|
||
|
||
**Out of scope:** query-time / runtime guardrails, the vector/embedding layer, and
|
||
semantic truth-assessment of concepts (see §7). These match the existing
|
||
out-of-scope boundary in `README.md` and `docs/PLAN.md`.
|
||
|
||
## 3. Why OKF is the right place to enforce
|
||
|
||
- OKF formalizes the LLM-wiki pattern into a portable markdown format; concepts
|
||
are meant to be read directly by agents as curated, authoritative context.
|
||
- The format has **no schema registry, no central authority, and no
|
||
signing/authenticity**. A received bundle's claimed origin is not verifiable at
|
||
the format level. (Verified at the format level — OKF v0.1 is a directory of
|
||
markdown files with YAML frontmatter, minimal by design; §9.)
|
||
- Consequence: **your ingestion pipeline *is* the trust boundary.** Provenance and
|
||
disposition must be stamped by you at ingestion, not assumed from the format.
|
||
|
||
## 4. Attack surfaces and required controls
|
||
|
||
Status column verified against the code at commit `5397ba1` on 2026-07-06 (§9).
|
||
|
||
| Surface | Vector | Required control | Status today |
|
||
|---|---|---|---|
|
||
| **Markdown body** | Prompt injection, hidden carriers (zero-width, BIDI, Unicode-tag, HTML comments, `data:` URIs) | Carrier-strip → fence → tool-less transform → output scan → fail-secure | ✅ Covered (core contract) |
|
||
| **YAML frontmatter** | Injection in `title`/`description`/`tags` + arbitrary unknown keys; `description` propagates into `index.md` (read **first** under progressive disclosure); YAML anchor/alias DoS + dangerous type coercion | Same sanitize/scan on frontmatter *values*; parse YAML with a safe loader | ⚠️ **Partial** — values are scanned **iff** the caller passes the whole document (frontmatter included) as text; the core **never parses YAML**, so the safe-loader is a genuinely new gate at an OKF-adapter boundary (§9) |
|
||
| **`resource` URL** | `data:`/`javascript:`/`file:`/SSRF target that a consumer or visualizer fetches | Scheme allowlist (`https` only), validate before commit | ❌ **New control** — `neutralize` defangs schemes for human audit but there is **no reject-gate** and no `resource`-field concept (§9) |
|
||
| **Cross-link graph** | "Dead links are valid" → *dormant* injection: plant a link to a non-existent concept-ID now, write the poisoned target later | Constrain link targets to relative in-bundle paths + scheme check; re-scan on write of a link target | ❌ **New control** (graph level) |
|
||
| **File path / reserved names** | Concept-ID = file path minus `.md`; path traversal (`../`) and shadowing of reserved `index.md`/`log.md` | Sanitize/normalize paths; reject `..` and reserved filenames as concept names | ❌ **New control** — no path validation in the core (§9) |
|
||
| **`log.md` / provenance** | No authenticity at the format level | Stamp disposition + trust tier per concept | ↔️ **Machinery exists** — `Trust` × `Provenance` × `Disposition` types are built; emission-to-`log.md` + an origin/channel stamp is new wiring on top (§9) |
|
||
|
||
## 5. Trust-tier model
|
||
|
||
Trust follows the data's **origin**, not the insertion channel. A manual paste of
|
||
external material is still external. This maps onto the existing `Trust` enum
|
||
(`TRUSTED` / `UNTRUSTED`) plus a channel dimension the pipeline records.
|
||
|
||
| Origin | Channel | Tier | Treatment |
|
||
|---|---|---|---|
|
||
| External | Automatic | Lowest | Full contract + fail-secure |
|
||
| External | Manual | Low | Full contract (channel grants *no* discount) |
|
||
| Internal | Automatic | Medium | Full contract; may relax the lexicon threshold with logging |
|
||
| Internal | Manual (trusted author) | Highest | Keep carrier-strip + scan; **note residual risk §7** |
|
||
|
||
**Nuance:** "manual internal" is not safe in itself. In-place edits by a trusted
|
||
author are outside the guard's scope — the channel does not authenticate the
|
||
content's origin. This is the same insider-edit limitation already in
|
||
`README.md` honest-limitations.
|
||
|
||
## 6. Two ingestion modes
|
||
|
||
**(a) Own enrichment output** — your agent writes concepts. The guard runs on your
|
||
own output before commit. One transform per concept. This is the existing
|
||
`prepare_input` → tool-less transform → `screen_output` bookend flow, applied
|
||
per concept.
|
||
|
||
**(b) Received external bundle** — you merge a whole third-party OKF bundle (the
|
||
format is explicitly built for cross-organization exchange). The guard must
|
||
**iterate over each concept** and validate body + frontmatter + links + `resource`
|
||
before merge — not treat the bundle as one unit. This is a **new iterator layer**
|
||
(§8 T7); the core has no bundle concept.
|
||
|
||
## 7. Residual risk (explicitly out of scope)
|
||
|
||
Cross-referenced to `README.md` honest-limitations. Items 1, 3, 5 are **already
|
||
documented there**; items 2 and 4 are OKF-specific and **not yet surfaced** (→ §8 T8).
|
||
|
||
1. **Semantic / factual poisoning** — a plausible-but-wrong concept (wrong
|
||
join-path, wrong metric definition, wrong runbook step) passes entropy + lexicon
|
||
cleanly and is treated as ground truth. **Highest impact for a wiki.** Needs
|
||
human review or source verification, not token analysis. *(Already in README;
|
||
the `grounding` module ships the `SourceGroundingCheck` seam for it.)*
|
||
2. **Dormant broken-link injection** — see §4; a per-concept write-time scan does
|
||
not see it over time. Needs graph / re-scan logic. *(Not yet in README.)*
|
||
3. **Trusted-author in-place edits** — normal OKF workflow (git-native editing) is
|
||
not gated by the guard. *(Already in README as the insider-edit limitation.)*
|
||
4. **Own security content as a false positive** — concepts that *document*
|
||
prompt-injection payloads will trip the carrier-strip / fail-secure path. Needs
|
||
a deliberate escaped path for "this concept is *about* attacks." *(Not yet in
|
||
README; also tracked as the corpus false-positive tension.)*
|
||
5. **Multimodal stego, embedding layer, query-time** — refer to the existing
|
||
threat-model docs. *(Already in README / out-of-scope boundary.)*
|
||
|
||
## 8. Recommendations → v0.2 task list
|
||
|
||
The unifying design move: add an **OKF adapter** *on top of* the format-agnostic
|
||
core. The core stays `text -> findings` (design principle 3); the adapter knows OKF
|
||
structure (frontmatter, paths, links, `resource`, bundles) and feeds scannable text
|
||
regions into the existing `sanitize` / `scan_output` / `disposition` machinery. No
|
||
YAML/format awareness leaks into the core.
|
||
|
||
| # | Task | Builds on | New? |
|
||
|---|---|---|---|
|
||
| **T1** | Whole-concept scan surface — route frontmatter *values* + `resource` strings through the same `sanitize`/`scan_output` path as the body | `sanitize`, `output` | adapter layer |
|
||
| **T2** | YAML parse-safety gate — safe loader (block anchor/alias DoS + dangerous type coercion) at the adapter boundary | — | **new** |
|
||
| **T3** | `resource`-URL allowlist gate — hard-reject non-`https` (and `data:`/`javascript:`/`file:`) *before commit* | `neutralize` scheme detection | **new** (reject, not defang) |
|
||
| **T4** | Path / reserved-name validation — reject `..` traversal + `index.md`/`log.md` shadowing; normalize concept-ID → path | — | **new** |
|
||
| **T5** | Cross-link graph re-scan — constrain targets to relative in-bundle paths + scheme check; re-scan on write of a link target (dormant-injection, §7.2) | — | **new** (graph state) |
|
||
| **T6** | Provenance stamping — origin + channel → tier + disposition per concept, emitted to `log.md` | `Trust`/`Provenance`/`Disposition` | new emission on existing types |
|
||
| **T7** | Bundle-import iterator (mode b) — iterate concepts; validate body + frontmatter + links + `resource` per concept | §6 bookends | **new** |
|
||
| **T8** | Docs — surface §7.2 (dormant broken-link) + §7.4 (own security content) in README honest-limitations; §7.1/§7.3/§7.5 already there | `README.md` | doc |
|
||
|
||
**Sequencing note:** T1–T4 + T6 are per-concept and composable with the existing
|
||
bookends; T7 is the mode-(b) wrapper around them; T5 is the hardest (needs graph
|
||
state across writes) and the one the residual risk §7.2 explicitly warns a
|
||
per-concept scan cannot cover. T8 is cheap and can land independently.
|
||
|
||
**Naming caveat:** the illustrative stamp vocabulary in an earlier draft
|
||
(`SANITIZED`/`FENCED`/`QUARANTINED`/`FAIL_SECURE`) is **not** the actual
|
||
`Disposition` enum (which is `WARN` / `QUARANTINE_REVIEW` / `FAIL_SECURE`). A
|
||
provenance stamp (T6) would compose from `Trust` × `Provenance` × `Disposition`,
|
||
not add new disposition values.
|
||
|
||
## 9. Verification log (2026-07-06, commit `5397ba1`)
|
||
|
||
Per the operator's verification duty — what was checked against ground truth, and
|
||
what remains the operator's premise.
|
||
|
||
**Verified against the code:**
|
||
|
||
- **The guard is format-agnostic text.** Public API is `prepare_input(text)` /
|
||
`screen_output(text, policy)` (`src/llm_ingestion_guard/__init__.py`). A grep of
|
||
`src/` finds **no YAML import and no frontmatter parsing** anywhere. Implication
|
||
for the §4 "YAML frontmatter" row: frontmatter *values* are scanned **only if the
|
||
caller includes them in the text** passed to the scanner; the safe-loader is a
|
||
genuinely new gate, because the core never parses YAML.
|
||
- **`resource` URL — no reject-gate today.** `neutralize.py` recognizes dangerous
|
||
schemes (`javascript|data|vbscript|file|blob` defanged; `http(s)`/`ftp` → `hxxp`)
|
||
but this is *neutralization for human audit*, not an allowlist that **rejects**
|
||
non-`https` before commit, and there is no `resource`-field concept. §4 "New
|
||
control" confirmed.
|
||
- **Cross-link graph, file path / reserved names — absent.** No graph logic, no
|
||
path normalization / traversal check / reserved-name (`index.md`/`log.md`) check
|
||
in `src/`. §4 "New control" confirmed for both.
|
||
- **Provenance machinery exists.** `disposition.py` defines `Disposition`
|
||
(`WARN`/`QUARANTINE_REVIEW`/`FAIL_SECURE`), `Trust` (`TRUSTED`/`UNTRUSTED`),
|
||
`Provenance` (`PROSE`/`CODE_FENCE`/`LOCALIZED`) + presets. Per-concept stamping
|
||
to `log.md` is new emission on top; the types are ready. §4 "Machinery exists"
|
||
confirmed.
|
||
- **README already covers residual risks 1, 3, 5** (semantic poisoning + grounding
|
||
seam; insider in-place edits; multimodal/query-time). Residual risks 2 and 4 are
|
||
**not** yet in README → T8.
|
||
|
||
**Verified externally:**
|
||
|
||
- **OKF is real, format level.** Google Cloud's Open Knowledge Format v0.1,
|
||
announced 2026-06-12: a directory of markdown files with YAML frontmatter,
|
||
minimal by design (only a `type` field required), vendor-neutral,
|
||
producer/consumer-independent — which confirms the LLM-wiki framing, the
|
||
cross-org exchange mode (b), and the "no central authority / no signing"
|
||
premise in §1/§3. Spec: `GoogleCloudPlatform/knowledge-catalog/okf/SPEC.md`.
|
||
|
||
**Operator premise — not independently verified this session:**
|
||
|
||
- OKF *concept-level* specifics used above (concept-ID = file path minus `.md`;
|
||
reserved `index.md`/`log.md`; a `resource` field; `description` propagating into
|
||
`index.md` under progressive disclosure) are taken from the operator's brief
|
||
citing the OKF spec. They are consistent with the format-level facts but were not
|
||
each checked against `SPEC.md`. A focused pass over the OKF spec should confirm
|
||
the reserved-filename and `resource`-field details before T3/T4/T5 are built.
|
||
|
||
## Sources
|
||
|
||
- [Google Cloud — How the Open Knowledge Format can improve data sharing](https://cloud.google.com/blog/products/data-analytics/how-the-open-knowledge-format-can-improve-data-sharing/)
|
||
- [GoogleCloudPlatform/knowledge-catalog — okf/SPEC.md](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md)
|
||
- [MarkTechPost — Google Cloud Introduces Open Knowledge Format (OKF)](https://www.marktechpost.com/2026/06/16/google-cloud-introduces-open-knowledge-format-okf-a-vendor-neutral-markdown-spec-for-giving-ai-agents-curated-context/)
|