Back to skill

Security audit

git-backed-obsidian-cli-workflows

Security checks for vulnerabilities and agentic risk

Overview

This note workflow skill is not clearly malicious, but it needs review because it can write outside the intended vault and automatically push more files than the user likely intended.

Install only if you trust the vault environment and are comfortable with automatic Git pushes. Before use, restrict execution to a non-privileged account, validate note paths, avoid absolute or traversal note names, review the backup script, and ensure the vault .gitignore excludes secrets and temporary files. A safer version would stage only the changed note and require explicit confirmation before pushing.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/notes_workflow.py:48
Finding

Unvalidated Note Paths Permit Writes Outside the Vault

Content
View full analysis
Path: p = Path(note) if p.suffix == "": p = p.with_suffix(".md") return p def ensure_parent(path: Path): path.parent.mkdir(parents=True, exist_ok=True) def append_plain(path: Path, content: str): ensure_parent(path) with path.open("a", encoding="utf-8") as f: f.write(content) if not content.endswith("\n"): f.write("\n") ``` ```python def do_memo(args): path = VAULT_ROOT / normalize_note(INBOX_NOTE) append_plain(path, args.content + "\n") return "fallback", str(path.relative_to(VAULT_ROOT)), True def do_append(args): path = VAULT_ROOT / normalize_note(args.note) append_plain(path, args.content + "\n") return "fallback", str(path.relative_to(VAULT_ROOT)), True def do_create(args): note = normalize_note(args.note) full = VAULT_ROOT / note if create_via_cli(note, args.content) and not args.force_fallback: return "cli", str(note), True if full.exists() and not args.overwrite: raise SystemExit(f"Note already exists: {full}") ensure_parent(full) full.write_text(args.content + ("" if args.content.endswith("\n") else "\n"), encoding="utf-8") return "fallback", str(full.relative_to(VAULT_ROOT)), True ``` ### Technical Analysis The `--note` argument is converted to a `Path` and joined to `VAULT_ROOT` without validating that the resulting path remains inside the vault. A relative path containing parent-directory components, such as `../../target.md`, can escape the vault. An absolute path is more direct: under `pathlib` semantics, joining a base path with an absolute path discards the base path. The affected write operations are: - `append`, which can append attacker-controlled text ...[truncated 2460 chars]
Remediation
View remediation
Path: candidate = normalize_note(note) if candidate.is_absolute(): raise ValueError("Absolute note paths are not allowed") root = VAULT_ROOT.resolve(strict=True) target = (root / candidate).resolve(strict=False) try: target.relative_to(root) except ValueError as exc: raise ValueError("Note path escapes the vault") from exc return target ``` The containment result must be used before any filesystem mutation. For strong protection against time-of-check/time-of-use and symlink races, use directory-relative file operations and refuse to follow symlinks where supported. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/backup.sh:14
Finding

Repository-Wide Git Staging Can Publish Unrelated Sensitive Files

Content
View full analysis
&2 exit 1 fi git pull --rebase --autostash origin "$CURRENT_BRANCH" git push origin "$CURRENT_BRANCH" ``` ### Technical Analysis Every successful note write invokes the backup script. The script uses `git add -A`, which stages all changes in the repository, including: - Modified tracked files. - Deleted tracked files. - Untracked files not excluded by `.gitignore`. - Changes unrelated to the note operation that triggered synchronization. The script then commits the complete staged set and pushes it to the configured `origin` remote. It does not receive or validate the path changed by the note workflow, inspect the staged file list, or limit staging to expected Markdown files. Consequently, a routine note update can commit and transmit unrelated files that happen to exist in the vault repository. This may include credentials, private exports, temporary files, application state, or other sensitive material. ### Attack Path 1. A sensitive or unintended file is created or modified anywhere inside the vault Git repository. 2. The file is not excluded by the repository's ignore rules. 3. A user performs any supported note write through `notes_workflow.py`. 4. The wrapper automatically invokes `scripts/backup.sh`. 5. The script detects repository changes and executes `git add -A`. 6. The sensitive or unrelated file is staged together with the intended ...[truncated 1220 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (10)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

A second description/behavior mismatch exists in that the skill claims broad query features and official-CLI-centric operation, while also allowing direct file writes and an unspecified backup script as core behavior. When a skill advertises safer, constrained interfaces but relies on more general mechanisms underneath, it weakens trust boundaries and increases the chance of unintended modification or sync of vault contents.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

A second description/behavior mismatch exists in that the skill claims broad query features and official-CLI-centric operation, while also allowing direct file writes and an unspecified backup script as core behavior. When a skill advertises safer, constrained interfaces but relies on more general mechanisms underneath, it weakens trust boundaries and increases the chance of unintended modification or sync of vault contents.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

In append/create fallback modes, user-controlled note names are joined directly with VAULT_ROOT, but absolute paths and traversal segments can escape the vault. Pathlib will discard the vault prefix for absolute paths, and ../../ segments can target arbitrary files, allowing overwrite or append outside the intended Obsidian directory.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill instructs use of shell commands, environment assumptions, backup scripts, and fallback file writes, but it declares no explicit tool scope or permissions boundary. That creates an authorization and review gap: an agent may execute shell/file-write actions broader than a user expects, including repo sync side effects, without an explicit allowlist.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill description does not clearly warn users that write actions automatically trigger Git backup/sync, which can publish or propagate note contents beyond the local vault. In the context of personal notes, this is especially sensitive because routine edits may unexpectedly cause commits, pushes, or remote disclosure of confidential information.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The script automatically stages all changes in the vault, creates a commit, rebases from origin, and pushes to the remote without any user confirmation or policy guardrails. In a note-management skill this can unintentionally exfiltrate sensitive notes, secrets, or transient local files to a remote repository, especially because untracked files are included via 'git add -A' after checking for untracked content.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/notes_workflow.py (reported line 11)May include surrounding context.

python
def run(cmd):
    return subprocess.run(cmd, text=True, capture_output=True)


def env(name: str, default: str) -> str:

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
83% confidence
Finding

The script reads NOTES_BACKUP_SCRIPT and NOTES_OBS_CMD from environment variables and later executes them as subprocesses. This is safety-relevant behavior because externally configured commands may run with side effects, but the code does not clearly disclose this behavior to the user before use.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The code executes a backup script from NOTES_BACKUP_SCRIPT, an environment-controlled path, after successful note operations. If an attacker can influence the environment or deployment configuration, they can cause arbitrary code execution under the privileges of this tool.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill automatically invokes an external backup script after note operations, which is a subprocess action with side effects beyond the local file write. While the final status is printed afterward, there is no prior warning, confirmation, or explanatory comment/docstring telling the user that a backup script will be executed automatically.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.