Back to skill

Security audit

zettel-brainstormer

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a coherent local-note brainstorming workflow, but it has real review-worthy risks around reading Markdown outside the intended vault and running an unverified external skill script.

Review before installing. Use it only with a trusted notes vault, replace the bundled config paths, and consider fixing wikilink containment before running on notes you did not fully control. Treat the optional zettel-link integration as a separate dependency: verify its source and path before allowing this skill to run its search script.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (2)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/obsidian_utils.py:20
Finding

Wikilink Path Traversal Allows Markdown Files Outside the Vault to Be Read

Content
View full analysis
Optional[Path]: """Resolve a wikilink target to a markdown file path.""" target = normalize_wikilink_target(link_name) if not target: return None exact = zettel_dir / f"{target}.md" if exact.exists(): return exact ``` The returned path is subsequently read during recursive traversal: ```python try: content = current_path.read_text(encoding="utf-8") except Exception as exc: print(f"Warning: could not read {current_path}: {exc}", file=sys.stderr) continue ``` ### Technical Analysis The normalized wikilink target is appended directly to the configured `zettel_dir`. The implementation does not reject: - Absolute path targets. - Parent-directory components such as `..`. - Paths that resolve outside the configured vault. - Symlinks whose resolved targets are outside the vault. For example, a vault note containing a link such as: ```markdown [[../../private/secret]] ``` causes the code to construct a path equivalent to: ```text /../../private/secret.md ``` If that file exists, `find_note_path()` returns it. `extract_links_recursive()` then reads its contents. Because retrieved note content is intended for later preprocessing and drafting subagents, the out-of-vault content may also be placed into model context or reproduced in generated output. The fallback `rglob("*.md")` search remains scoped to the vault, but it does not mitigate the unsafe direct-path branch. ### Attack Path 1. An attacker creates, imports, or modifies a Markdown note within the configured vault. 2. The note includes a crafted wikilink containing parent-directory traversal or an absolute path. 3. Th ...[truncated 1119 chars]
Remediation
View remediation
Optional[Path]: target = normalize_wikilink_target(link_name) if not target: return None target_path = Path(target) if target_path.is_absolute() or ".." in target_path.parts: return None root = zettel_dir.expanduser().resolve() candidate = (root / f"{target}.md").resolve() try: candidate.relative_to(root) except ValueError: return None if candidate.is_file(): return candidate for note in root.rglob("*.md"): resolved_note = note.resolve() try: resolved_note.relative_to(root) except ValueError: continue if resolved_note.stem.lower() == target.lower(): return resolved_note return None ``` Additional hardening should include: 1. Define and enforce a symlink policy. Reject symlinks or validate every resolved symlink target against the vault root. 2. Validate that the seed note is within the configured vault when the workflow is intended to be vault-only. 3. Recheck containment immediately before every file read, rather than relying only on the resolver. 4. Reject null bytes, absolute paths, and traversal components in wikilink targets. 5. Add regression tests for: - `[[../outside]]` - `[[../../outside]]` - Absolute-path wikilinks - Symlinks pointing outside the vault - Valid nested notes inside the vault 6. Avoid passing absolute local paths or unauthorized file content into model context. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:20
Finding

Unverified External Skill Script Is Discovered and Executed by Name

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (6)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The description focuses on brainstorming and publishing, but the workflow also performs setup, configuration mutation, and environment-driven model selection. That mismatch can mislead users into approving a seemingly content-only skill that also changes local state, which is dangerous in a security-sensitive agent environment.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The description focuses on brainstorming and publishing, but the workflow also performs setup, configuration mutation, and environment-driven model selection. That mismatch can mislead users into approving a seemingly content-only skill that also changes local state, which is dangerous in a security-sensitive agent environment.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The description focuses on brainstorming and publishing, but the workflow also performs setup, configuration mutation, and environment-driven model selection. That mismatch can mislead users into approving a seemingly content-only skill that also changes local state, which is dangerous in a security-sensitive agent environment.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The description focuses on brainstorming and publishing, but the workflow also performs setup, configuration mutation, and environment-driven model selection. That mismatch can mislead users into approving a seemingly content-only skill that also changes local state, which is dangerous in a security-sensitive agent environment.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
84% confidence
Finding

The skill instructs the agent to run Python scripts, read local notes, and write outputs and configuration files, but it does not declare any explicit tool scope or permissions. This creates an authorization ambiguity where a host may grant broader filesystem or environment access than users expect, increasing the chance of unintended data exposure or modification.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
98% confidence
Finding

The file is being analyzed in the context of the zettel-brainstormer skill, but the footer says Generated by writing-brainstormer. That is an active documentation/labeling contradiction about which skill produced the artifact, not merely missing detail.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.