Skip to content

hardening: mergeOverlay has no defense against malformed remote blocks #1146

Description

@anandgupta42

Found while writing v0.9.7 release adversarial tests (packages/opencode/test/skill/release-v0.9.7-adversarial.test.ts).

mergeOverlay (packages/opencode/src/memory/prompt.ts:69-80) has two narrow fragilities, both currently unreachable via the production hydrate/refresh path (which always supplies well-formed RemoteMemoryBlocks via toBlock()), but present in the exported function itself:

  1. Duplicate ids within the remote list are not deduplicated against each other. The dedup check only compares new remote entries against local keys (localKeys.has(...)); it never checks a remote entry against remote entries already pushed from the same list. Two remote records sharing one non-sibling scope+id (a corrupted or duplicated overlay fetch) both survive into the merged output.
  2. A remote block missing updated throws a TypeError out of the final sort (b.updated.localeCompare(a.updated)) instead of degrading gracefully. toBlock() always guarantees updated via a fallback chain ending in new Date().toISOString(), so this isn't reachable today — but a future caller building RemoteMemoryBlock by hand, or a corrupted overlay cache, would hit it. The memory-read tool's outer try/catch happens to downgrade this to an error response rather than crashing the process, but that's accidental defense-in-depth one layer up, not a property of mergeOverlay itself.

Both are pinned by FINDING:-prefixed tests in the adversarial test file (documenting current behavior, not asserting it's correct). Deferred from v0.9.7 because neither is reachable via the real production path today — worth a hardening pass regardless, since mergeOverlay is exported and its contract implicitly promises a 'deterministic, non-crashing merge' that doesn't fully hold for malformed input.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions