Skip to content

Semantic Notes Vault MCP 0.12.0

Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 30 Jul 02:11
· 54 commits to main since this release

Semantic Notes Vault MCP 0.12.0

Security release

This release closes three ways a vault write could reach disk without passing through the plugin's security layer, and makes Read-only mode take effect immediately instead of at the next server start.

If you point an AI agent at a vault and rely on Read-only mode to contain it, please update. Two of the three issues did not require Read-only mode to be enabled at all — they were reachable in the default configuration.

Writes could bypass the security layer

Vault writes are meant to funnel through a single gate that enforces Read-only mode and validates paths. Three paths reached the vault without it:

  • bases.create wrote via a direct vault call. With Read-only mode on it still created files, and a ../ path created files outside the vault root. It could not overwrite existing files, only create new ones.
  • vault.move and vault.rename relocated files using Obsidian's rename API directly, with the destination unvalidated. A ../ destination moved files out of the vault entirely. These worked in the default configuration — Read-only mode was not involved — and because they are moves, they removed data from the vault rather than merely writing to it.

The cause was a gap in the abstraction rather than a faulty check: the security layer had no move/rename method, so calling code reached around it to the raw Obsidian API. The fix adds the missing methods and routes every write through the existing gate. No second enforcement path was introduced — the two disagreeing paths were the underlying problem.

Also hardened, though not reachable from any tool today: the active-file write methods, executeCommand (the command palette contains destructive commands), and an empty-string path that skipped validation — which was allowing writes with an undefined path.

Read-only mode now applies immediately

Toggling Read-only mode only reconfigured the security layer at server start. In between, the toggle blocked vault writes but left edit writes working — while the confirmation message claimed all writes were blocked. Disabling it had the mirror-image problem: writes stayed blocked until a restart, including when the server had started with Read-only on.

Read-only mode now takes effect the moment you toggle it, in both directions, which is what the switch appeared to promise.

Behaviour change: Read-only mode no longer blocks opening a note in Obsidian. Opening a document changes nothing in the vault, so it is treated as a read. Running an Obsidian command by id remains blocked, since the command palette can delete and move files. The setting description has been corrected — it previously listed only "create, update, delete, move, rename", which both understated and mis-stated what the mode does.

Authentication hardening

  • API key comparison is now constant-time. A plain === short-circuits on the first differing byte, which leaks a key prefix through response timing.
  • Basic auth no longer truncates a key containing a colon. Such a key was silently cut short at the first colon and a valid key rejected.
  • Security settings loaded from data.json are coerced to booleans. A hand-edited string value could render the Read-only toggle as ON while enforcement was off.

Reliability of the security boundary

Session creation now fails loudly rather than degrading silently if the security layer or plugin reference is ever missing, instead of serving a session with nothing between it and vault writes.

Dependencies

All runtime dependency advisories are cleared — npm audit --omit=dev reports zero. The bare npm audit count is larger, and that is expected: the remainder is a single denial-of-service advisory in a transitive package shared across the jest/eslint toolchain, fanned out across every dependent. It is development-only and does not reach the shipped bundle; clearing it would require moving dev dependencies across majors.

Testing

Read-only enforcement is now covered by a matrix derived from the shipped tool schemas, so a newly added action fails the suite until it is explicitly classified as read or write — the gap that let these bypasses exist. Tool visibility and authentication, which previously had no tests, are now covered.

Reporting security issues

GitHub private vulnerability reporting was not enabled on this repository, so the channel SECURITY.md pointed at returned a 404 and reporters had to fall back to email. It is now enabled: https://github.com/aaronsb/obsidian-mcp-plugin/security/advisories/new is the preferred route.

The bases.create bypass was reported privately by an external researcher following a source review and live probing. The vault.move / vault.rename escape was found while verifying that report.

Claude Desktop (.mcpb connector)

If you connect Claude Desktop via the .mcpb bundle, re-import obsidian-mcp.mcpb from this release to update the connector — BRAT updates only the Obsidian plugin, not the Desktop bridge.

Installation via BRAT (Obsidian plugin)

  1. Install the BRAT plugin if you haven't already
  2. Command palette → "BRAT: Add a beta plugin for testing"
  3. Enter: aaronsb/obsidian-mcp-plugin
  4. Enable the plugin in Community Plugins

What's Changed

  • fix(security): route every vault write through the security layer by @aaronsb in #276
  • fix(security): make read-only mode take effect immediately (ADR-108) by @aaronsb in #277
  • test(security): cover the two switches with no coverage, harden HTTP auth by @aaronsb in #278
  • fix(deps): clear all runtime advisories (lockfile only) by @aaronsb in #279

Full Changelog: 0.11.42...0.12.0