[GH-ISSUE #141] AnalysisSnapshotCache.export() exposes mutable snapshot entries #88

Closed
opened 2026-10-15 18:21:00 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @morluto on GitHub (Jul 14, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/141

Problem

AnalysisSnapshotCache returns internal AnalysisSnapshotEntry objects from export() via entries() without defensive cloning:

  • export() (src/application/AnalysisSnapshotCache.ts:108)
  • entries() (src/application/AnalysisSnapshotCache.ts:140)

Callers can mutate exported entries and directly alter cache internals.

Reproduction

import { AnalysisSnapshotCache } from "./dist/application/AnalysisSnapshotCache.js";
import { createEvidenceBundle } from "./dist/domain/evidenceBundle.js";

const cache = new AnalysisSnapshotCache();
const provider = { id: "official", name: "official", version: "1" };
const target = {
  kind: "executable",
  path: "/tmp/bin",
  sha256: "a".repeat(64),
  format: "elf",
  architecture: "x86",
  sourcePath: "/tmp/bin",
  loaderArgs: [],
};

cache.record(target, "current_address", { address: "0x1000" }, {
  result: { kind: "json", value: { ok: true } },
  raw_result: { bytes: [] },
  provider,
  limitations: ["orig"],
  locations: [],
  subject: null,
});

const exportResult = cache.export(target, createEvidenceBundle([]));
if (!exportResult.ok) throw new Error("export failed");
const snapshot = exportResult.value;

snapshot.entries[0].execution.provider = { id: "tamper", name: "tamper", version: "9" };
snapshot.entries[0].execution.limitations.push("tampered");

const lookup = cache.lookup(target, "current_address", { address: "0x1000" }, provider);
console.log(lookup?.provider);
console.log(lookup?.limitations);

Observed output:

  • lookup.provider becomes { id: 'tamper', name: 'tamper', version: '9' }
  • lookup.limitations includes appended tampered

Expected

export() / entries() should emit detached copies so external callers cannot mutate cache internals.

Actual

Mutating snapshot.entries mutates the internal cache entry object because references are shared.

Impact

Anyone with access to exported snapshots can tamper with cached provenance and limitations, causing subsequent lookups and trust assumptions to be polluted with caller-controlled data.

Originally created by @morluto on GitHub (Jul 14, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/141 ### Problem `AnalysisSnapshotCache` returns internal `AnalysisSnapshotEntry` objects from `export()` via `entries()` without defensive cloning: - `export()` (`src/application/AnalysisSnapshotCache.ts:108`) - `entries()` (`src/application/AnalysisSnapshotCache.ts:140`) Callers can mutate exported entries and directly alter cache internals. ### Reproduction ```ts import { AnalysisSnapshotCache } from "./dist/application/AnalysisSnapshotCache.js"; import { createEvidenceBundle } from "./dist/domain/evidenceBundle.js"; const cache = new AnalysisSnapshotCache(); const provider = { id: "official", name: "official", version: "1" }; const target = { kind: "executable", path: "/tmp/bin", sha256: "a".repeat(64), format: "elf", architecture: "x86", sourcePath: "/tmp/bin", loaderArgs: [], }; cache.record(target, "current_address", { address: "0x1000" }, { result: { kind: "json", value: { ok: true } }, raw_result: { bytes: [] }, provider, limitations: ["orig"], locations: [], subject: null, }); const exportResult = cache.export(target, createEvidenceBundle([])); if (!exportResult.ok) throw new Error("export failed"); const snapshot = exportResult.value; snapshot.entries[0].execution.provider = { id: "tamper", name: "tamper", version: "9" }; snapshot.entries[0].execution.limitations.push("tampered"); const lookup = cache.lookup(target, "current_address", { address: "0x1000" }, provider); console.log(lookup?.provider); console.log(lookup?.limitations); ``` Observed output: - `lookup.provider` becomes `{ id: 'tamper', name: 'tamper', version: '9' }` - `lookup.limitations` includes appended `tampered` ### Expected `export()` / `entries()` should emit detached copies so external callers cannot mutate cache internals. ### Actual Mutating `snapshot.entries` mutates the internal cache entry object because references are shared. ### Impact Anyone with access to exported snapshots can tamper with cached provenance and limitations, causing subsequent lookups and trust assumptions to be polluted with caller-controlled data.
bsakaguchi 2026-10-15 18:21:00 +00:00
  • closed this issue
  • added the
    bug
    label
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#88
No description provided.