| tiêu đề | thedotmack claude-mem v10.4.0 - Improper content hash construction - Field-boundary ambiguity |
|---|
| Mô tả | ## Suggested CWE
- CWE-682: Incorrect Calculation
- Alternative: CWE-20: Improper Input Validation
## Suggested Severity
- Severity: Medium
- Suggested CVSS 3.1: `CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L`
- Suggested score: 4.4
The vulnerability primarily affects integrity and availability of stored observations. It does not require breaking SHA-256; the collision is caused before hashing by ambiguous string concatenation.
## Summary
Claude-Mem used a SHA-256 content hash to deduplicate observations, but the input to the hash was built by directly concatenating three independent fields:
```ts
(memorySessionId || '') + (title || '') + (narrative || '')
```
Because no delimiter or length prefix separated the fields, different observation tuples could produce the same pre-hash string and therefore the same `content_hash`. An attacker able to influence observation fields could craft an observation that collides with another observation's deduplication key. The duplicate-detection logic could then treat a distinct legitimate observation as already stored, causing silent memory loss or poisoning of the persistent memory timeline.
## Technical Details
The affected function used `(memory_session_id, title, narrative)` as the semantic identity of an observation. In affected versions, these fields were concatenated without any boundary marker before hashing:
```ts
export function computeObservationContentHash(
memorySessionId: string,
title: string | null,
narrative: string | null
): string {
return createHash('sha256')
.update((memorySessionId || '') + (title || '') + (narrative || ''))
.digest('hex')
.slice(0, 16);
}
```
This makes different tuples indistinguishable when their concatenated representation is identical. For example:
| memorySessionId | title | narrative | pre-hash string |
|---|---|---|---|
| `session-abc` | `debug log` | `""` | `session-abcdebug log` |
| `session-ab` | `cdebug log` | `""` | `session-abcdebug log` |
| `session-` | `abcdebug log` | `""` | `session-abcdebug log` |
| `""` | `session-abcdebug log` | `""` | `session-abcdebug log` |
In affected versions, all four tuples hash to the same 16-character `content_hash`. The observation store then uses that hash for deduplication, so a colliding observation can suppress a distinct observation.
## Proof of Concept
The following standalone PoC demonstrates the pre-fix collision:
```js
import { createHash } from 'crypto';
function vulnerableHash(memorySessionId, title, narrative) {
return createHash('sha256')
.update((memorySessionId || '') + (title || '') + (narrative || ''))
.digest('hex')
.slice(0, 16);
}
const tuples = [
['session-abc', 'debug log', ''],
['session-ab', 'cdebug log', ''],
['session-', 'abcdebug log', ''],
['', 'session-abcdebug log', ''],
];
const hashes = tuples.map((tuple) => vulnerableHash(...tuple));
console.log(hashes);
console.log(new Set(hashes).size); // vulnerable result: 1
```
On an affected version, each tuple produces the same hash. If one tuple is stored first, a later distinct observation with another tuple can be incorrectly treated as a duplicate.
## Impact
An attacker who can influence observation fields can create content-hash collisions without attacking SHA-256 itself. This can:
- suppress legitimate observations during deduplication;
- cause the memory timeline to retain attacker-controlled content instead of later legitimate content;
- corrupt project memory used by future Claude-Mem sessions;
- reduce integrity and availability of stored development history.
This is a memory poisoning vector rather than arbitrary code execution.
## Fix
PR #1494 fixes the issue by joining the hash fields with a null-byte delimiter, making field boundaries explicit:
```ts
return createHash('sha256')
.update([memorySessionId || '', title || '', narrative || ''].join('\x00'))
.digest('hex')
.slice(0, 16);
```
The PR also adds a regression test proving the previously colliding tuples now produce four distinct hashes.
## Timeline
- 2026-02-23: Content-hash observation deduplication introduced.
- 2026-03-26: Fix commit authored: `9cfa57d4984f068be8492be5489727ae04fa9203`.
- 2026-03-26: PR #1494 opened.
- 2026-04-07: PR #1494 merged.
- 2026-04-07: Fix released in `v12.0.0`.
## Credits
- Reporter / patch author: `3em0`
- PR author: https://github.com/3em0
## References
- Pull request: https://github.com/thedotmack/claude-mem/pull/1494
- Fix commit: https://github.com/thedotmack/claude-mem/commit/9cfa57d4984f068be8492be5489727ae04fa9203
- Merge commit: https://github.com/thedotmack/claude-mem/commit/f32fda8b35e9fe9329f87da65c31149362a03f97
- Fixed release: https://github.com/thedotmack/claude-mem/releases/tag/v12.0.0
- Affected code before fix: https://github.com/thedotmack/claude-mem/blob/v11.0.1/src/services/sqlite/observations/store.ts
- Fixed code: https://github.com/thedotmack/claude-mem/blob/v12.0.0/src/services/sqlite/observations/store.ts
|
|---|
| Nguồn | ⚠️ https://github.com/thedotmack/claude-mem/pull/1494 |
|---|
| Người dùng | Dem00 (UID 84913) |
|---|
| Đệ trình | 18/05/2026 10:32 (cách đây 19 ngày) |
|---|
| Kiểm duyệt | 05/06/2026 08:56 (18 days later) |
|---|
| Trạng thái | được chấp nhận |
|---|
| Mục VulDB | 368870 [thedotmack claude-mem đến 11.0.1 Observation Content Hash store.ts computeObservationContentHash mã hóa yếu] |
|---|
| điểm | 20 |
|---|