GHSA-r3g7-r4hr-m258: SQL Injection

Published Oct 23, 2026
·
Updated

Summary createentity, linkentities, renameentity, unlinkentities and deleteentity 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 - createentity and linkentities inserted the SQL row or relation before materialization. - renameentity 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. - unlinkentities removed the relation row before discovering the source note's rematerialization would be refused. - deleteentity'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 (restorenote) 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 obsidiantcid 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; createentity and linkentities 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 Software

1 affected componentFixes available
npm/obsidian-tc>=1.0.1<=1.31.3
1.31.4

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade npm/obsidian-tc to a version that resolves this vulnerability.

    Fixed in 1.31.4
  2. Upgrade

    Upgrade to a fixed release to a version that resolves this vulnerability.

    Fixed in 1.31.4
  3. Configuration

    Disable the write:memory scope for callers to prevent the vulnerable write path entirely.

    M5 memory tools write:memory scope = disabled

Event History

Oct 23, 2026
Advisory Published
via GitHub·06:47 PM
Data Sourced
via GitHub·06:47 PM
DescriptionWeaknessAffected Software

Frequently Asked Questions

1

Which notes are exposed to unintended content replacement?

A note is exposed when it already exists at the computed memory/<type>/<name>.md path but is not owned by the entity being written. This includes hand-authored notes and orphaned notes from another entity whose name sanitizes to the same path.

2

Which actions can trigger the issue?

The affected operations are create_entity, link_entities, rename_entity, unlink_entities, and delete_entity. A subsequent write for the matching type and name can overwrite the existing note body while retaining its frontmatter.

3

Can a refused filesystem write still change SQLite state?

Yes. Some operations modify SQL rows or relations before the fallible note-materialization step, so a refused write can leave a relation removed, a retired status committed, or the wrong entity deleted.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203