GHSA-R3G7-R4HR-M258
Vulnerability from github – Published: 2026-10-23 18:47 – Updated: 2026-10-23 18:47Summary
create_entity, link_entities, rename_entity, unlink_entities and delete_entity regenerate a memory note's body from SQLite at the computed memory/<type>/<name>.md path. When a note already existed at that path and was not owned by the entity being written (a hand-authored note, or an orphan left by a different entity whose name sanitized to the same path), its entire body was overwritten on the next write naming that (type, name), keeping only its frontmatter. Separately, several of these tools inserted or removed their SQLite row before the fallible filesystem step, so a refused note write could leave a relation gone, a retired status committed, or the wrong entity deleted.
Details
create_entityandlink_entitiesinserted the SQL row or relation before materialization.rename_entityseeded the destination path with a direct atomic write that bypassed the ownership check, and for a status-only rename could commit a retired status with the note write refused.unlink_entitiesremoved the relation row before discovering the source note's rematerialization would be refused.delete_entity's cascade could delete the target and its relations before a neighbour's note was found to be foreign.
The overwrite exists in every released version since materializeEntity shipped (git show v1.0.1:packages/server/src/memory/materialize.ts).
Impact
An authorized caller with memory-write scope (any agent using the M5 memory tools) can, without intending to, destroy the body of a vault note outside the entity it is writing, and can leave the memory graph inconsistent with the notes on disk. Snapshots-before-write (restore_note) mitigate the overwrite only where snapshots are enabled and the note had been written through obsidian-tc before.
Patches
Fixed in 1.31.4 at the shared primitive: materializeEntity refuses to write over a note whose obsidian_tc_id is missing or belongs to another entity; a new assertNoteOwnership pre-check runs before any SQLite mutation in the three lifecycle tools, so a refusal is a no-op; create_entity and link_entities roll back the row they had inserted. Verified by test/m5-memory-ownership.test.ts, which covers all five call sites and the rollback.
Workarounds
None that preserve the tools. Disabling the write:memory scope for callers prevents the write path entirely.
Credit
Found by the maintainer while building obsidian-tc memory import (PR #978); the vulnerability class was independently confirmed by a cross-vendor adversarial review.
References
- PR #978 (fix and test), CHANGELOG
## [1.31.4] ### Security packages/server/src/memory/materialize.ts,packages/server/src/tools/m5/memory-lifecycle-tools.ts
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 1.31.3"
},
"package": {
"ecosystem": "npm",
"name": "obsidian-tc"
},
"ranges": [
{
"events": [
{
"introduced": "1.0.1"
},
{
"fixed": "1.31.4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-115478"
],
"database_specific": {
"cwe_ids": [
"CWE-459",
"CWE-863"
],
"github_reviewed": true,
"github_reviewed_at": "2026-10-23T18:47:25Z",
"nvd_published_at": "2026-10-23T15:17:30Z",
"severity": "HIGH"
},
"details": "### Summary\n`create_entity`, `link_entities`, `rename_entity`, `unlink_entities` and `delete_entity` regenerate a memory note\u0027s body from SQLite at the computed `memory/\u003ctype\u003e/\u003cname\u003e.md` path. When a note already existed at that path and was not owned by the entity being written (a hand-authored note, or an orphan left by a different entity whose name sanitized to the same path), its entire body was overwritten on the next write naming that `(type, name)`, keeping only its frontmatter. Separately, several of these tools inserted or removed their SQLite row before the fallible filesystem step, so a refused note write could leave a relation gone, a retired status committed, or the wrong entity deleted.\n\n### Details\n- `create_entity` and `link_entities` inserted the SQL row or relation before materialization.\n- `rename_entity` seeded the destination path with a direct atomic write that bypassed the ownership check, and for a status-only rename could commit a retired status with the note write refused.\n- `unlink_entities` removed the relation row before discovering the source note\u0027s rematerialization would be refused.\n- `delete_entity`\u0027s cascade could delete the target and its relations before a neighbour\u0027s note was found to be foreign.\n\nThe overwrite exists in every released version since `materializeEntity` shipped (`git show v1.0.1:packages/server/src/memory/materialize.ts`).\n\n### Impact\nAn authorized caller with memory-write scope (any agent using the M5 memory tools) can, without intending to, destroy the body of a vault note outside the entity it is writing, and can leave the memory graph inconsistent with the notes on disk. Snapshots-before-write (`restore_note`) mitigate the overwrite only where snapshots are enabled and the note had been written through obsidian-tc before.\n\n### Patches\nFixed in 1.31.4 at the shared primitive: `materializeEntity` refuses to write over a note whose `obsidian_tc_id` is missing or belongs to another entity; a new `assertNoteOwnership` pre-check runs before any SQLite mutation in the three lifecycle tools, so a refusal is a no-op; `create_entity` and `link_entities` roll back the row they had inserted. Verified by `test/m5-memory-ownership.test.ts`, which covers all five call sites and the rollback.\n\n### Workarounds\nNone that preserve the tools. Disabling the `write:memory` scope for callers prevents the write path entirely.\n\n### Credit\nFound by the maintainer while building `obsidian-tc memory import` (PR #978); the vulnerability class was independently confirmed by a cross-vendor adversarial review.\n\n### References\n- PR #978 (fix and test), CHANGELOG `## [1.31.4] ### Security`\n- `packages/server/src/memory/materialize.ts`, `packages/server/src/tools/m5/memory-lifecycle-tools.ts`\n\n---",
"id": "GHSA-r3g7-r4hr-m258",
"modified": "2026-10-23T18:47:39Z",
"published": "2026-10-23T18:47:25Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/The-40-Thieves/obsidian-tc/security/advisories/GHSA-r3g7-r4hr-m258"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-115478"
},
{
"type": "WEB",
"url": "https://github.com/The-40-Thieves/obsidian-tc/pull/978"
},
{
"type": "WEB",
"url": "https://github.com/The-40-Thieves/obsidian-tc/commit/99f7914ca0fbeed92e7c4d39cc8c3e5830dab133"
},
{
"type": "PACKAGE",
"url": "https://github.com/The-40-Thieves/obsidian-tc"
},
{
"type": "WEB",
"url": "https://github.com/The-40-Thieves/obsidian-tc/blob/v1.31.4/CHANGELOG.md"
},
{
"type": "WEB",
"url": "https://github.com/The-40-Thieves/obsidian-tc/releases/tag/v1.31.4"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:L/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "obsidian-tc: Memory-lifecycle tools overwrite unowned notes or partially commit lifecycle changes"
}
Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Vulnerability timeline
Sightings and recorded dates, grouped by day · UTC
Loading timeline…
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
Related by attack behaviour
Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.