Skip to content

fix(cache): bind impact and oracle consumption to verified archive bytes #36

Description

@TheHalfMoon

Finding

The post-CF-13 hardening audit found additional verify-then-reopen cache integrity gaps on canonical main 8a45857bf31c4acae57fdfb1e3cdde3d0f7d0361.

This is related to, but broader than, issue #35 (terminology).

commandf impact

crates/commandf-cli/src/impact.rs currently:

  1. calls before_cache.verify(&before_locked.sha256) / after_cache.verify(...);
  2. later calls read_locked_archive, which performs an independent raw fs::read of the cache path;
  3. feeds those newly read bytes to diff_package_archives.

A local mutation between verification and the second read can therefore rebind structural/impact input to bytes that were never digest-verified.

commandf oracle

crates/commandf-cli/src/oracle.rs currently:

  1. verifies before/after package and R4 core digests;
  2. reconstructs cache paths;
  3. independently raw-reads before/after bytes for commandF structural matching;
  4. passes cache paths directly to the external HL7 JVM adapter for later reads.

The external oracle can therefore consume a different cache file generation from the one commandF verified. Merely replacing the commandF fs::read with PackageCache::read_verified is insufficient if the JVM still receives the mutable cache path.

Required repair contract

Impact

Consume the exact bytes returned from a verified cache read boundary. Do not verify then reopen the cache path for structural/impact analysis.

Oracle

Bind both commandF and JVM oracle execution to the exact verified byte generation. A likely safe pattern is:

  • obtain verified bytes once per required archive;
  • stage those verified bytes into commandF-owned private temporary files/directories with bounded lifetime and safe publication/permissions;
  • use the same staged immutable-for-the-invocation paths for commandF/JVM comparison authority;
  • retain original package SHA-256 identity in report evidence;
  • ensure cleanup and no host-path leakage into machine-readable semantic evidence.

Do not assume this exact implementation if a stronger equivalent is found, but the invariant is mandatory: the bytes consumed must be the bytes whose digest was verified.

Regression requirements

  • deterministic test proving impact does not perform verify-then-independent cache reopen;
  • deterministic oracle test proving an external adapter invocation cannot be rebound by mutating the original cache path after the verified-byte boundary;
  • no timing-dependent race test as the only evidence;
  • inspect all production cache consumers for the same pattern before closeout;
  • preserve existing corrupted-cache, process timeout/tree termination, determinism, CF-06 identity, and oracle reconciliation tests.

Separate lockfile input review

impact.rs, oracle.rs, and main CLI paths also use direct fs::read for caller-provided lockfiles. Audit their input-size bounds separately; do not silently fold an unrelated unbounded-lockfile fix into this cache-generation issue without task/review scope.

Governance

Severity rationale

Integrity/evidence-boundary defect. Current attackers/actors need local cache mutation capability, so no remote exploitability is claimed. However commandF explicitly treats cache digest verification as evidence authority; consuming a later filesystem generation violates that authority and can invalidate deterministic/reproducible claims under concurrent or malicious local mutation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions