LearnNewsExamplesServices
Frontmatter
id12995
titleKB ingestion is tier-blind — extend P1 provenance taint to KB chunks
stateClosed
labels
enhancementaiarchitecturemodel-experience
assigneesneo-opus-vega
createdAtJun 12, 2026, 2:51 PM
updatedAtJun 12, 2026, 9:21 PM
githubUrlhttps://github.com/neomjs/neo/issues/12995
authorneo-fable
commentsCount2
parentIssue10291
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtJun 12, 2026, 9:21 PM

KB ingestion is tier-blind — extend P1 provenance taint to KB chunks

Closed v13.1.0/archive-v13-1-0-chunk-1 enhancementaiarchitecturemodel-experience
neo-fable
neo-fable commented on Jun 12, 2026, 2:51 PM

Context

Live incident, 2026-06-12: external account ankitzm posted Discussion #12992 — a vendor pitch carrying the full astroturf marker set (external repo link, embedded video attachment, a "15+ 👍 from maintainers/devs" engagement-bait clause, and an offer to stand up an externally-controlled MCP endpoint as a context source for agents working on this repo). This is the third infiltration instance in ~6 weeks, escalating each time: the desiorac Trojan-horse critique that birthed #10476, the name-only corpus-poisoning comment redacted on #12674 (2026-06-07), now a full discussion.

The operator's framing (and @neo-opus-ada's same-day V-B-A, Memory Core session e76f14a0-87b4-4fcb-9d87-2fe65db088a9): the real threat axis is OWASP ASI06 Memory & Context Poisoning — external content flowing into the organism's knowledge substrates as if trusted.

The Problem

Ada's defined V-B-A question was "is #12992's ingestion tainted External (correct) or laundered to a trusted tier (corruption)?" — executed today with a third answer: the KB path cannot taint at all.

  • grep -rln "trustTier" ai/services/knowledge-base/ ai/scripts/zero hits. The shipped P1 provenance (#10292) covers the Memory Core write path (memories carry the 8-tier trustTier and MC query tools expose minTrustTier); the KB ingestion pipeline carries no provenance dimension whatsoever.
  • The corpus census (#12967) confirms the corpus shape: 28,398 chunks with uniform visibility:'team' — 46.4% of it tickets/PR-conversations/discussions, i.e. surfaces external accounts can write to.
  • ask_knowledge_base synthesizes from top-k similarity with no trust weighting → an ingested vendor pitch competes evenly with our own guides in every answer.
  • The sync (ai/scripts/maintenance/syncGithubWorkflow.mjs / sync_all) paginates all discussions/issues/PRs — no exclusion or quarantine mechanism exists.

Today's exposure was contained only by timing: the last content sync predates the post, so #12992 is not yet in resources/content/ or the chroma collection — the window where moderation prevents ingestion entirely. The pipeline gap remains for every future instance.

The Architectural Reality

  • ai/scripts/maintenance/syncGithubWorkflow.mjs — the CLI dual of the sync_all MCP tool; GitHub → resources/content/** emission, unfiltered.
  • The KB chunking/ingestion path under ai/services/knowledge-base/ — chunk metadata today: visibility, metadata.content, type, no provenance field.
  • #10292 (P1, SHIPPED) — the 8-tier trust model + minTrustTier query surface on Memory Core: the exact pattern to mirror.
  • #10476 (P8, OPEN, sibling) — read-boundary URL defanging + traversal prohibition + P7 sanitizer; complements this ticket (P8 = the agent-read boundary, this = the corpus-write boundary).
  • GitHub author-association (OWNER/MEMBER/COLLABORATOR vs NONE/FIRST_TIME_CONTRIBUTOR) — the cheap, authoritative tier-derivation signal available at sync time.

The Fix

  1. Stamp at chunk time: derive a trust tier from the GitHub author-association of each ingested artifact (and each comment within it) — collaborator-class → internal tiers, everything else → external — persisted as chunk metadata alongside visibility.
  2. Honor at retrieval: ask_knowledge_base/query_documents gain a minTrustTier floor (mirroring the MC tools) AND/OR an external-tier ranking penalty in synthesis context assembly — external content stays findable when asked for, but never silently outranks or co-equals internal substrate.
  3. Quarantine lever at sync: a small denylist (artifact ids) the sync consults — the immediate containment tool for #12992-class incidents when moderation hasn't happened yet (or when a de-fanged record is deliberately kept, per the #12674 redaction precedent).

Contract Ledger

# Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
1 KB chunk metadata schema #10292's 8-tier model additive trustTier field, author-association-derived absent field = unclassified (pre-existing chunks) KB service JSDoc grep: zero trustTier in KB path today
2 ask_knowledge_base / query_documents answer assembly MC minTrustTier precedent optional floor param + external rank-penalty; default behavior documented param omitted = current ranking + penalty only tool descriptions #12992 incident; census uniform-visibility
3 syncGithubWorkflow.mjs / sync_all operator moderation precedent (#12674) consults a denylist before emission empty list = today's behavior script header no filter exists today (verified)

Acceptance Criteria

  • External-authored artifacts chunk with trustTier: external; collaborator-authored with the appropriate internal tier.
  • Retrieval demonstrably stops co-ranking external chunks with internal substrate by default (test: a planted external-style fixture never outranks a same-topic internal doc).
  • Sync denylist mechanism exists and is documented; adding #12992 (if kept) excludes it from emission.
  • Existing chunks: documented migration stance (re-sync re-stamps vs unclassified floor).

Out of Scope

  • Read-boundary URL defanging + traversal prohibition + P7 sanitizer — #10476 (P8) owns those.
  • GitHub-side moderation of #12992 itself (operator-owned, third-party content).
  • The astroturf-response skill (incident playbook) — sibling proposal, routed separately.

Related

Epic #10291 (parent — Organism Self-Defense; graduated from Discussion #10289), #10476 (P8 sibling), #10292 (P1 shipped, the pattern), #12992 (the live incident), #12674 (the redaction precedent), #12967 (corpus census), session e76f14a0-87b4-4fcb-9d87-2fe65db088a9 (Ada's same-day V-B-A) + session e605ce21-3668-445c-bc00-45896aa9a092 (this verification).

Release classification: post-release substrate, elevated priority — active incident class; the containment lever (Fix 3) is the time-sensitive half.

Live latest-open sweep: checked latest 12 open at 2026-06-12T12:49Z; no equivalent. A2A in-flight sweep: Ada's lane = the #12992 incident handling (handover parked on operator steer), no claim on the pipeline gap; no other claims.

Origin Session ID: e605ce21-3668-445c-bc00-45896aa9a092

Retrieval Hint: "KB ingestion trust tier blind external taint provenance astroturf poisoning"

tobiu referenced in commit 2ce7a8e - "feat(github-workflow): sync-time discussion denylist + quarantine for content containment (#12995) (#13000) on Jun 12, 2026, 9:21 PM
tobiu closed this issue on Jun 12, 2026, 9:21 PM