hardening: mergeOverlay has no defense against malformed remote blocks

Open Beginner friendly
#1,146 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
84/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
typescript
Domain
backend, testing

Research direction

Start with mergeOverlay in packages/opencode/src/memory/prompt.ts:69-80 and the FINDING-prefixed cases in packages/opencode/test/skill/release-v0.9.7-adversarial.test.ts. Reproduce the current behavior with those tests, then make malformed remote input deterministic: duplicate remote ids should not both survive and missing updated should not throw. Done means the adversarial tests can be updated to assert the hardened behavior.

Written by the indexing model from the issue text.

Description

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.

Dominant language
TypeScript
Stars
813
Forks
134
Avg merge
2d 5h
Merged PRs (30d)
62

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from AltimateAI/altimate-code

All issues in AltimateAI/altimate-code

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.