CVE-2026-61647: @roomi-fields/notebooklm-mcp has a path traversal in vault.batch tool that allows arbitrary file write outside intended vault directory
The `@roomi-fields/notebooklm-mcp` `vault_batch` tool and its `POST /batch-to-vault` endpoint accept a caller-supplied `vault_dir` with no containment check, so a caller or a prompt-injected LLM can write `.md` and `.json` files anywhere the server can write. Versions 1.6.0 up to 2.0.3 are affected. Upgrade to 2.0.3 and set `NOTEBOOKLM_VAULT_ROOT`.
Published Sep 22, 2026 · Analysis Oct 22, 2026
What an attacker can do
vault_dir goes straight into path.resolve() and fs.mkdir(). The server then writes the answer files as markdown with JSON sidecars into that directory. A second, smaller flaw: slug_prefix is concatenated into the filename without sanitizing, so a prefix with / or .. can escape the resolved vault directory.
The attacker needs to reach the MCP tool or the HTTP endpoint. The CVSS vector requires low privileges. The usual route is an LLM driving the MCP server that has read untrusted content, which injects a vault_dir argument. The written files are inert content and give no code execution by themselves. The risk is planting files in sensitive places such as autostart folders or shell startup files for a later step, and overwriting files in locations the process can write. Integrity is the affected property.
The flaw has existed since 1.6.0, when /batch-to-vault was introduced, and since 1.7.0 for the batch_to_vault MCP tool, through 2.0.2.
Who is affected
@roomi-fields/notebooklm-mcp >= 1.6.0, < 2.0.3. The HTTP /batch-to-vault endpoint is exposed since 1.6.0 and the MCP tool since 1.7.0. Servers run by a user with broad write access, or driven by an LLM that reads untrusted content, are the most exposed.
npm ls -g @roomi-fields/notebooklm-mcp@roomi-fields/notebooklm-mcp
- Ecosystem
- npm
- Affected
- >= 1.6.0, < 2.0.3
- Fixed in
- 2.0.3
- Check
npm ls @roomi-fields/notebooklm-mcp
How to fix it
Upgrade to @roomi-fields/notebooklm-mcp 2.0.3:
npm install -g @roomi-fields/[email protected]Important: 2.0.3 keeps the old unrestricted behavior when NOTEBOOKLM_VAULT_ROOT is unset, so existing local setups keep working. Set NOTEBOOKLM_VAULT_ROOT to the directory that should bound all vault writes. With it set, vault_dir is resolved under that root with realpath containment, and absolute paths or .. outside it are rejected. slug_prefix is always sanitized: separators, .. and NUL are stripped and the length is capped at 64 characters.
If you cannot upgrade, run the server as an unprivileged user that can write only to the vault, do not expose the HTTP endpoint beyond localhost, and validate vault_dir before passing it on.
How to tell if you were hit
Search for unexpected .md and .json files outside the vault, especially in autostart folders, home-directory dotfile locations and other users' directories, with names that look like notebook answers. Review MCP tool-call logs and HTTP logs for vault_batch or /batch-to-vault requests with an absolute vault_dir, .. segments, or a slug_prefix containing slashes. Beam records MCP tool calls and file access, so its rules can flag vault_dir arguments pointing outside your project.
Original advisory
From the GitHub Advisory Database (CC BY 4.0).
Summary
The vault_batch MCP tool (and the equivalent POST /batch-to-vault HTTP endpoint) accepted a caller-supplied vault_dir path that was passed directly to path.resolve() + fs.mkdir() with no containment check. A caller — or a prompt-injected LLM driving the MCP — could therefore create directories and write .md / .json answer files anywhere the server process can write.
The slug_prefix parameter had a parallel, smaller traversal vector: it was concatenated into the filename without sanitization, so a prefix containing / or .. could escape the resolved vault directory through the filename component.
Impact
File write (markdown + JSON sidecars) to any location writable by the server process. The written files are inert content (no code execution by themselves), but in a multi-user context — or when the MCP server is driven by an LLM that has read untrusted content (prompt injection) — this allows an attacker to plant files in sensitive locations (autostart folders, shell startup files, etc.) for downstream exploitation.
The vulnerability exists from v1.6.0 (when the HTTP /batch-to-vault endpoint was introduced) and v1.7.0 (when the same logic was exposed as the batch_to_vault MCP tool) through v2.0.2.
Patch
Fixed in v2.0.3:
- Opt-in containment via `NOTEBOOKLM_VAULT_ROOT` env var. When set,
vault_diris resolved relative to that root andrealpath-based containment is enforced. Absolute paths or..segments outside the root are rejected with a clear error. - `slug_prefix` is always sanitized. Path separators (
/,\),..sequences and NUL bytes are stripped, length capped at 64 characters. This applies regardless of whetherNOTEBOOKLM_VAULT_ROOTis set. - 15 unit tests in
src/__tests__/vault-writer.test.tscover the escape vectors (absolute paths, sibling-prefix attacks,..traversal, NUL/separator stripping).
Workarounds for users who cannot upgrade
- Run the MCP server under a dedicated unprivileged user with write access only to the intended vault directory.
- Do not expose the HTTP
/batch-to-vaultendpoint beyond localhost. - If using an LLM that ingests untrusted content, validate any
vault_dirarguments before forwarding them to the MCP.
Configuration requirement after upgrade (important)
v2.0.3 preserves the legacy unrestricted behaviour when NOTEBOOKLM_VAULT_ROOT is unset, to keep existing single-user local setups working. To enable containment, set `NOTEBOOKLM_VAULT_ROOT` in the server environment to a directory that should bound all vault writes.
Credit
Reported by @mcfly-zzh — thanks for the careful diagnosis and follow-up verification.
Credited to mcfly-zzh.
Questions
- Does upgrading to 2.0.3 fix the path traversal by itself?
Not for
vault_dir. 2.0.3 keeps unrestricted behavior unlessNOTEBOOKLM_VAULT_ROOTis set. You must set it to enable containment.slug_prefixis sanitized in all cases.- Can the attack run code?
Not directly. The written files are inert markdown and JSON. The danger is planting them where a later process, such as shell startup or autostart, would use them.
- How would an attacker reach the tool?
Through the HTTP
/batch-to-vaultendpoint if it is reachable, or through a prompt-injected LLM that calls thevault_batchMCP tool with a craftedvault_dir.
References
Read for this analysis:
- https://github.com/roomi-fields/notebooklm-mcp/security/advisories/GHSA-jjhp-8crj-mppq
- https://nvd.nist.gov/vuln/detail/CVE-2026-61647
- https://github.com/roomi-fields/notebooklm-mcp/issues/15
- https://github.com/roomi-fields/notebooklm-mcp/commit/13828d9ff3933839ce14c1797d3b20a6bb7694a6
- https://github.com/roomi-fields/notebooklm-mcp/releases/tag/v2.0.3
How this page is made: the data panel comes from the GitHub Advisory Database, CISA’s KEV catalog, the NVD and FIRST EPSS, and updates twice a day. The analysis is written by an AI model from the sources listed above and checked by automated rules before it is published. Check versions against the vendor's advisory before you act. Methodology
More Other MCP servers and tools vulnerabilities
All Other MCP servers and tools entriesCVE-2026-77361
obsidian-tc : Symlink read-ACL scope bypass via lexical path checks
medium4.7Oct 23, 2026CVE-2026-114126
Storybook dev server vulnerable to code injection from the local network
high8.7Oct 22, 2026CVE-2026-113731
djust: Arbitrary absolute-path file read in the find_handlers_for_template MCP tool
low3.3Oct 21, 2026CVE-2026-114125
Storybook: Missing origin validation in Storybook preview allows code injection from malicious websites
critical9.4Oct 21, 2026CVE-2026-111770
MCP TypeScript server SDK: Shared transport or server instances delivered one HTTP client's messages to another
high7.7Oct 20, 2026GHSA-953h-535j-jg2v
agent-router: MCP session resume does not verify the embedded anti-hijacking subject; default Helm seed makes session IDs forgeable
medium6.8Oct 19, 2026
