BACK TO SEARCH
JBMD-Creations/obsidian-mcpcritical

Remote MCP server for ChatGPT-driven Obsidian note capture

This MCP server enables ChatGPT to capture notes into a private Obsidian vault hosted on GitHub. It provides tools to search, read, append to, and cre...

purpose: This MCP server enables ChatGPT to capture notes ithreat: network exposed
TypeScript · 0 · Jun 7, 2026 · Jun 8, 2026 · GITHUB ↗
RISK SCORE
0/ 100 risk
high findings+75
medium findings+30
capped at100
VULNERABILITY ANALYSIS · 5 findings in 5 blocks3 HIGH · 2 MEDIUM
HIGH1 finding
src/index.ts:478
478      async ({ content, path, related_notes }) =>
479        asText(
480          await appendToNote({
481            config,
482            content,
483            login: this.props!.login,
484            octokit,
485            path,
486            relatedNotes: related_notes,
487          }),
488        ),
src/index.ts:478src/github-vault.ts:327src/github-vault.ts:283src/github-vault.ts:130

// Network-exposed MCP; exploitable by any authenticated user or compromised LLM.

EXPLAINThe append_to_note and append_footer_note tools accept a 'path' parameter that is passed directly to appendToNote/appendFooterNote without any validation. The path is only validated later in getFile via assertAllowedMarkdownPath, but that function only checks for .md extension and disallowed prefixes. It does not restrict the path to the intended sections or folders. An attacker could provide a path like '../sensitive.md' or 'some/other/folder/note.md' to append content to any markdown file in the repository, bypassing the intended restriction to only append under the configured sections.
IMPACTAn attacker (compromised LLM or malicious user) could append arbitrary content to any markdown file in the vault, potentially injecting malicious links, altering existing notes, or defacing content. This violates the intended purpose of restricting writes to specific sections.
FIXValidate that the provided path is within the allowed scope (e.g., under the configured createFolder or sessionFolderRoot) before performing the append. Alternatively, restrict the path to only notes that were previously created by the MCP or are in designated folders.
HIGH1 finding
src/index.ts:416
416      async ({ path }) => asText(await getNote({ config, octokit, path: assertAllowedMarkdownPath(path) })),
src/index.ts:416src/github-vault.ts:266src/github-vault.ts:130

// Network-exposed MCP; exploitable by any authenticated user or compromised LLM.

EXPLAINThe get_note and fetch tools accept a 'path' parameter that is validated by assertAllowedMarkdownPath. However, this validation only checks for .md extension and disallowed prefixes like .git/ and .obsidian/. It does not restrict the path to any specific folder or scope. An attacker could read any markdown file in the repository, including notes outside the intended scope (e.g., personal notes, configuration files).
IMPACTAn attacker could read any markdown file in the vault, leading to information disclosure of sensitive notes, credentials, or other private data stored in the Obsidian vault.
FIXRestrict read operations to only notes within the configured allowed folders (e.g., createFolder, sessionFolderRoot, appDevRoot) or implement a whitelist of allowed paths.
HIGH1 finding
src/index.ts:407
407      async ({ folder, query }) => asText(await searchNotes({ config, folder, octokit, query })),
src/index.ts:407src/github-vault.ts:211src/github-vault.ts:107

// Network-exposed MCP; exploitable by any authenticated user or compromised LLM.

EXPLAINThe search_notes tool accepts an optional 'folder' parameter that is passed directly to searchNotes without validation. In searchNotes, the folder is used to filter paths via listMarkdownPaths, which calls assertAllowedMarkdownPath on a constructed path. However, the folder itself is not validated before being used in the prefix filter. An attacker could provide a folder like '../' or '..' to traverse directories and list markdown files outside the intended scope.
IMPACTAn attacker could enumerate markdown files in arbitrary directories of the repository, leading to information disclosure about the vault structure and existence of sensitive notes.
FIXValidate the folder parameter using assertAllowedFolderPath before passing it to searchNotes, and ensure it is within the allowed scope (e.g., under createFolder or sessionFolderRoot).
MEDIUM1 finding
src/index.ts:267
267      async ({ group }) => asText(await refreshAppDevChatgptDashboard({ config, group, octokit })),
src/index.ts:267src/github-vault.ts:571src/pathing.ts:118

// Network-exposed MCP; requires knowledge of valid group names.

EXPLAINThe create_appdev_chatgpt_note and refresh_appdev_chatgpt_dashboard tools accept a 'group' parameter that is only trimmed and lowercased before being used to resolve a folder via resolveAppDevGroupFolder. While resolveAppDevGroupFolder validates the group against sessionGroups, if the group is not found, it throws an error. However, an attacker could potentially provide a group that exists but is not intended for App Dev OVR, leading to writing notes in unintended folders. Additionally, the group parameter is not validated against a schema beyond being a non-empty string.
IMPACTAn attacker could potentially write notes to unintended App Dev OVR group folders if they guess or enumerate valid group names, though the impact is limited to the configured groups.
FIXAdd explicit validation that the group is one of the configured App Dev OVR groups (e.g., by checking against a whitelist) before proceeding with the operation.
MEDIUM1 finding
src/index.ts:343
343      async ({ content, related_notes, session_id, text }) => {
344        const activeSession = await loadActiveSession();
345        if (!activeSession) {
346          throw new Error('No active session. Run start_session(group, folder_path?) first.');
347        }
348
349        const resolvedSessionId = resolveSessionId({
350          session_id,
351          storedSessionId: activeSession.sessionId,
352        });
353        if (!resolvedSessionId || resolvedSessionId !== activeSession.sessionId) {
354          throw new Error('Session mismatch. Run start_session(group, folder_path?) again.');
355        }
src/index.ts:343src/session-tools.ts:9

// Network-exposed MCP; requires knowledge of another user's session UUID.

EXPLAINThe note and end_session tools accept an optional 'session_id' parameter that is compared to the stored session ID. However, the session_id is not validated for format or origin. An attacker could potentially brute-force or guess a valid session_id to hijack an active session, though the session_id is a UUID and the KV store is scoped to the authenticated user. The risk is low but the validation is weak.
IMPACTAn attacker with knowledge of another user's session_id could append notes to their session log or end their session prematurely.
FIXConsider removing the optional session_id parameter or requiring it to match the stored session ID without allowing override. Alternatively, implement additional authentication checks.
6/8/2026
Findings are produced by automated LLM analysis and may include false positives or miss issues. Verify independently before acting.