Follow-up to #653 / PR #655 (owner-accepted P2).
Context
#655 made auto-distillation work on every harness by mirroring the memory-dream trust model: the read-only/plan permission mode stays a hard gate, and the trusted system-prompt channel became observed (ride _meta.systemPrompt when present, else prepend the policy inline). This lets Codex/OpenCode distill instead of silently no-op'ing.
Residual risk (accepted as P2 by the owner for now)
Auto-distillation differs from a dream in two ways that make the untrusted-channel path riskier than the dream path:
- No staging/review — the distiller parses the model's JSON and appends it to shared agent-scoped live memory directly (unlike a dream, which stages + reviews, or requires an explicit
autoAdopt opt-in).
- Runs on the warm host —
runMemoryExtraction reuses the agent's warm ACP host (full agent tool credentials + materialized config files), whereas a dream runs on a dedicated excludeAgentToolCredentials host.
On a runtime without an ACP system-prompt channel, the inline policy and the attacker-controlled finished turn share user-message priority, so a prompt injection could:
- control the distilled JSON → write poisoned "facts" into shared memory unreviewed; and
- ask the runtime to read a credential and re-encode it into a "memory" — the read-only mode blocks writes/side-effects but not reads, and the literal-value secret masker is defense-in-depth and won't catch arbitrary re-encoding.
(The trusted-channel/Claude path is unchanged and keeps the prior protection.)
Proposed fix
Give the untrusted-channel distillation path the dream's credential isolation: run extraction on a dedicated excludeAgentToolCredentials host (reuse buildDreamHost / buildAcpHost), cached per agent (long-lived) since distillation runs every turn — so cost stays ~one extra process per auto-distill agent rather than a spawn per turn. This closes the credential-read/re-encode path; the remaining unreviewed-write (memory-poisoning) residual matches the class the trusted-channel path already tolerates. Optionally, consider a lightweight review/quarantine for untrusted-channel distilled writes.
The provider-credential-vs-model-tools gap is the same accepted P2 as the dream path (F3, #36).
Follow-up to #653 / PR #655 (owner-accepted P2).
Context
#655 made auto-distillation work on every harness by mirroring the memory-dream trust model: the read-only/plan permission mode stays a hard gate, and the trusted system-prompt channel became observed (ride
_meta.systemPromptwhen present, else prepend the policy inline). This lets Codex/OpenCode distill instead of silently no-op'ing.Residual risk (accepted as P2 by the owner for now)
Auto-distillation differs from a dream in two ways that make the untrusted-channel path riskier than the dream path:
autoAdoptopt-in).runMemoryExtractionreuses the agent's warm ACP host (full agent tool credentials + materialized config files), whereas a dream runs on a dedicatedexcludeAgentToolCredentialshost.On a runtime without an ACP system-prompt channel, the inline policy and the attacker-controlled finished turn share user-message priority, so a prompt injection could:
(The trusted-channel/Claude path is unchanged and keeps the prior protection.)
Proposed fix
Give the untrusted-channel distillation path the dream's credential isolation: run extraction on a dedicated
excludeAgentToolCredentialshost (reusebuildDreamHost/buildAcpHost), cached per agent (long-lived) since distillation runs every turn — so cost stays ~one extra process per auto-distill agent rather than a spawn per turn. This closes the credential-read/re-encode path; the remaining unreviewed-write (memory-poisoning) residual matches the class the trusted-channel path already tolerates. Optionally, consider a lightweight review/quarantine for untrusted-channel distilled writes.The provider-credential-vs-model-tools gap is the same accepted P2 as the dream path (F3, #36).