Skip to content

Journal-integrity hardening against a semantically-valid MALICIOUS undo journal (out of decision #45 today) #53

Description

@jarodtaylor

The Codex gate on the U5 undo path (PR #52 + its follow-up) surfaced a class of crafted-journal attacks: duplicate entry-IDs redirecting undo(id) (findLast over the global journal), a self-declared projectRoot that doesn't constrain targetPath/backupPath, and quarantine side effects (poisoned-newest fallback, ABA-under-quarantine).

Why deferred — out of the ratified threat model (decision #45), not a bug today. Every one of these requires an adversary writing semantically-valid malicious entries into <dataDir>/undo-journal.jsonl (0600 file under the 0700 OS data dir, written only by the engine). On any legitimate journal none can occur — apply() stamps a fresh randomUUID batchId under one ingress-canonicalized root, entry ids are per-write randomUUIDs, and targetPath = posix.join(projectRoot, PortableRelPath) is a contained descendant by construction. An attacker who can write that file already owns the user's home/data dir — and can rewrite the user's real configs directly, without puppeting our undo. That is decision #45's explicit "attacker-owns-HOME / other side of the airtight hatchway" out-of-scope. The journal is validated on read for corruption-tolerance (torn tails / malformed lines → dropped), which is a different and lower bar than adversarial integrity.

What shipped anyway (best-effort defense-in-depth, documented as non-guarantees in src/provision/runs.ts): quarantining a cross-root batchId entirely.

Promotion trigger: ONLY if the threat model expands to a hostile data dir (e.g. a shared/multi-user or networked data store), or an always-on writer (U15) changes the trust boundary. Then, per the gate's recommendation, introduce one semantic journal-validation pass yielding {selectable batches, quarantined ids, duplicate entry-ids, conservative later-writer metadata}, require targetPath to be a canonical descendant of projectRoot and backupPath inside the backup store, make undo(id) reject non-unique ids, keep quarantined rows as supersession blockers, and fail-closed (return no batch) when the newest raw batch for the target is quarantined. Add filesystem-level regressions for each.

Refs: PR #52 + follow-up branch fix/u5-cross-project-undo-quarantine; gate rounds documenting the four vectors; decision #45 threat model in .claude/skills/unit-loop/references/codex-gate.md.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    deferredParked work with a promotion trigger

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions