Agent Markdown Link is a local file tool. It is designed to reduce accidental disclosure and canonical-note damage, not to protect data from another process or user that already controls the same account.
Use GitHub private vulnerability reporting for security issues. Do not include real vault contents, credentials, or other personal data. General bugs belong in the public issue tracker.
Security fixes are provided for the current 0.6.x release line while it remains supported. Pre-release snapshots and modified forks are not supported by the maintainer.
- Normal CLI and stdio MCP operation performs no network, Git, shell, child-process, telemetry, or Obsidian activity.
- Context reads are limited to configured vault-relative regular files. Lexical validation and real-path checks reject traversal and linked paths outside the vault.
- Search recursively reads regular Markdown files only below the selected project's configured vault-relative
searchRootsplus the sharedmemoryPathwhen configured. It skips discovered links, never writes an index or cache, and applies fixed scan, source, result, excerpt, and output bounds. - Candidate publication uses a same-directory private temporary file and a no-replace hard link. An existing destination is never overwritten, and there is no copy or rename fallback.
- Search and candidate input, plus all intended context, search, and candidate output, are byte-bounded. Errors contain only stable codes and fixed messages.
- Queries, note bodies, excerpts, candidate bodies, prompts, credentials, absolute paths, and session data are not written to logs or metrics.
- Created directories and files request modes
0700and0600on POSIX. Windows uses inherited ACLs and makes no ACL-rewrite claim.
The Codex SessionStart hook reads one bounded JSON object and operationally
uses only its event name, source, and working directory. Extra host fields are
ignored; the runtime does not read transcripts. Successful curated context is
capped at 9,000 UTF-8 bytes, and serialized hook stdout is capped at 32,768
bytes.
The trusted PreToolUse hook runs only for the three bundled Codex memory
tools. It validates the host-supplied absolute workspace, selects exactly one
configured project, and creates a random one-time workspace capability bound
to that tool name and the exact original input. The hook preserves the tool
input and adds only the reserved capability. Its allow decision enables that
rewrite; Codex still applies its MCP approval policy afterward.
Capability records live in a codex-capabilities directory under the private
state root, which must resolve outside the vault. The raw token is not stored in
that record. Each record requests mode 0600, the directory requests 0700,
and a capability expires after 10 minutes. For a call that reaches MCP, the
runtime removes the record before validation and tool execution, then checks
its expiry, tool name, exact input digest, workspace mapping, and project ID.
A host-rejected call leaves its unused record until expiry and a later bounded
cleanup pass. The token is present in the host-managed rewritten tool input, so
Codex may retain it under its own policy. Agent Markdown Link does not add it
to vault files, MCP results, diagnostics, its own logs or metrics, or captures.
Both plugin artifacts bundle the same local stdio MCP server with only
context, search, and capture tools. Each protocol frame is capped at 2
MiB. The server validates AGENT_MARKDOWN_LINK_HOST as exactly codex or
claude; a missing, blank, or unknown identity terminates startup with a fixed
diagnostic. Codex requires the hook capability for every tool call and ignores
CLAUDE_PROJECT_DIR and defaultProjectId. Claude uses
CLAUDE_PROJECT_DIR when present and otherwise uses the process working
directory.
Claude attempts exact project selection first. Only when exact selection
returns no project may Claude use an explicitly configured defaultProjectId
as a Claude-only fallback. Equal-specificity mappings for different projects
are ambiguous and always reject without fallback. Tool input cannot select or
override a config, project, vault, workspace, or host. Capture records the
validated provenance as sourceHost: codex or sourceHost: claude.
This is the fail-closed trust boundary: invalid host identity prevents MCP
initialization, an unmapped Codex workspace has no MCP access, and a disabled
or untrusted Codex authorization hook cannot create a valid capability. An
unmapped Claude workspace has no MCP access unless the operator explicitly
configured the Claude-only fallback, and ambiguity always rejects. An explicit
Claude default makes that project's configured context and the shared
memoryPath available to unmatched Claude MCP sessions that can reach the
local server, so enable it only for sessions inside the same intended trust
boundary.
The Claude SessionStart command hook emits only a fixed, content-free instruction telling Claude to call the MCP context tool before answering. The hook does not read configuration, vault data, or hook input. Codex context-hook failures are non-blocking and inject only the fixed context-unavailable notice. MCP failures use a stable code and fixed message. Context assembly is all-or-nothing, so a later file failure does not expose earlier file content.
Vault and memory files are plaintext. Protect the device, account, vault, backups, and sync provider as appropriate for the data. A private Git repository is not encryption; do not commit sensitive vault contents to a cloud repository unless they are encrypted before leaving the device.
Treat all curated Markdown as untrusted reference data. It cannot override system, developer, repository, or current-user instructions.
When a plugin supplies curated context, the host sends that selected text to the active model provider just as it sends other prompt context. When an agent invokes search, the host may retain the query, tool call, and intended result excerpts in task history and send them to the active model provider under the host's policy. Standard input keeps the query out of ordinary process command-line listings, and Agent Markdown Link diagnostics do not echo it; neither protection hides it from the host or model provider. The local runtime itself performs no automatic network activity.
Configure search roots narrowly and do not search sensitive material speculatively. Lexical search has no semantic-recall guarantee, so an empty result is not proof that no relevant note exists.
The credential check intentionally recognizes only a few high-confidence private-key, bearer-token, and GitHub-token patterns. It is not comprehensive data-loss prevention. Review memory records before sharing or syncing them.
Containment and no-overwrite checks address mistakes and linked-path escapes during ordinary local use. They do not defend against a malicious process with the same filesystem permissions racing path changes during an operation. Do not run the CLI concurrently with untrusted software that can modify the configured roots.
Outbox mode creates a local private staging directory but does not move files into the vault. Memory mode creates new records without overwrite and never edits curated summaries. Inbox review, promotion, rejection, deletion, backup, and sync remain manual operations outside the CLI.