Back to skill

Security audit

Obsidian Tasks

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a disclosed Obsidian task-board helper, but it needs review because its setup path can escape the chosen vault and its install/publish guidance runs mutable remote CLI code.

Install only if you are comfortable with a skill that can write markdown files in your vault. Use a simple relative --folder value such as Tasks, avoid absolute paths or ../ components, and consider pinning or preinstalling the ClawHub CLI before running the documented npx install/login/publish commands. Maintainers should run publishing with limited credentials in an isolated environment.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/setup.py:91
Finding

Unvalidated Folder Path Allows Writes Outside the Selected Vault

Content
View full analysis

Vulnerability Details

File Location: scripts/setup.py, lines 91–114
Vulnerability Type: Path traversal and unrestricted filesystem write
Risk Level: Medium

Vulnerable Code

python
folder_path = os.path.join(vault, args.folder)
os.makedirs(folder_path, exist_ok=True)

columns = [c.strip() for c in args.columns.split(",")]

# Relative path from vault root for Dataview queries
tasks_folder = args.folder

# Create Board.md
board_path = os.path.join(folder_path, "Board.md")
if os.path.exists(board_path):
    print(f"Board already exists: {board_path}")
else:
    with open(board_path, "w") as f:
        f.write(create_board(folder_path, columns))
    print(f"Created: {board_path}")

# Create Dashboard.md
dashboard_path = os.path.join(folder_path, "Dashboard.md")
if os.path.exists(dashboard_path):
    print(f"Dashboard already exists: {dashboard_path}")
else:
    with open(dashboard_path, "w") as f:
        f.write(create_dashboard(tasks_folder))
    print(f"Created: {dashboard_path}")

Technical Analysis

The user-controlled --folder argument is joined to the vault path without validating that the resulting destination remains inside the vault.

If args.folder is an absolute path, os.path.join(vault, args.folder) discards the vault prefix. A relative value containing parent-directory components, such as ../../target, can similarly resolve outside the vault. The implementation also does not resolve or check symlinks before creating directories and files.

The script protects existing Board.md and Dashboard.md files from direct replacement, but it can still create these files and intermediate directories at an unintended filesystem location.

Attack Path

  1. An attacker, untrusted automation, or an agent-controlled input supplies a malicious folder argument, for example:
    bash
    python3 scripts/setup.py /home/user/vault --folder ../../tmp/target
    

...[truncated 1047 chars]

Remediation
View remediation

Remediation Suggestions

  1. Reject absolute values for --folder.
  2. Resolve the vault and destination to canonical paths before creating directories.
  3. Verify that the resolved destination is a descendant of the resolved vault.
  4. Reject traversal through symlinks when the security model requires all writes to remain physically inside the vault.
  5. Return a clear error before performing any filesystem modification when validation fails.

A hardened implementation can use pathlib:

python
from pathlib import Path

vault = Path(args.vault_path).expanduser().resolve()
folder = Path(args.folder)

if folder.is_absolute():
    parser.error("--folder must be relative to the vault")

folder_path = (vault / folder).resolve()

try:
    folder_path.relative_to(vault)
except ValueError:
    parser.error("--folder must remain inside the vault")

folder_path.mkdir(parents=True, exist_ok=True)

Where supported, use Path.is_relative_to(vault) instead of the relative_to exception pattern. Consider checking each existing path component for symlinks before writing if external symlink targets must be prohibited.

T08 · Insecure Dependencies

Error
Location
scripts/publish_clawhub.sh:20
Finding

Mutable Latest Package Is Downloaded and Executed During Publishing

Content
View full analysis

Vulnerability Details

File Location: scripts/publish_clawhub.sh, lines 20–30
Vulnerability Type: Unpinned executable dependency and software supply-chain exposure
Risk Level: High

Vulnerable Code

bash
npx -y clawhub@latest \
  --site "$SITE_URL" \
  --registry "$REGISTRY_URL" \
  publish "$REPO_DIR" \
    --slug openclaw-obsidian-tasks \
    --name "Obsidian Tasks" \
    --version "$VERSION" \
    --tags "$TAGS" \
    --changelog "$CHANGELOG"

The same mutable dependency reference is also recommended for installation and authentication in README.md lines 25 and 33.

Technical Analysis

npx -y clawhub@latest automatically resolves, downloads, and executes whichever package release is associated with the mutable latest tag at invocation time. The script does not pin a reviewed version or verify package integrity.

Consequently, the code executed by the publishing workflow can change after this project has been audited, without any modification to the repository. If the upstream package, publisher account, registry, or release process is compromised, malicious package lifecycle or CLI code could run under the maintainer's account.

This is particularly sensitive in a publishing workflow because the process may have access to registry authentication material, source artifacts, repository data, and other credentials present in the environment.

Attack Path

  1. The upstream package, publisher account, registry distribution path, or mutable latest release is compromised or publishes a malicious update.
  2. A user or maintainer runs the documented login, install, or publishing command.
  3. npx resolves clawhub@latest to the newly published package and downloads it.
  4. Package installation hooks or CLI entry-point code execute with the invoking user's privileges.
  5. Malicious code can access files, environment variables, network resources, and credentials available to that ...[truncated 685 chars]
Remediation
View remediation

Remediation Suggestions

  1. Replace clawhub@latest with an exact, reviewed package version in the script and all documentation.
  2. Use a lockfile and verified integrity metadata where the workflow permits.
  3. Update the pinned version only through a deliberate dependency-review process.
  4. Run publishing in an isolated, least-privileged environment with narrowly scoped and short-lived credentials.
  5. Disable or constrain package lifecycle scripts where practical.
  6. Verify that the configured package registry and authentication endpoint are expected and trusted before transmitting credentials.
  7. Consider installing the reviewed CLI in a controlled build image instead of downloading executable code during each release.

Example:

bash
CLAWHUB_VERSION="REVIEWED_EXACT_VERSION"

npx -y "clawhub@${CLAWHUB_VERSION}" \
  --site "$SITE_URL" \
  --registry "$REGISTRY_URL" \
  publish "$REPO_DIR" \
    --slug openclaw-obsidian-tasks \
    --name "Obsidian Tasks" \
    --version "$VERSION" \
    --tags "$TAGS" \
    --changelog "$CHANGELOG"
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (7)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description is about Obsidian task-board creation and management workflows. The supplied code does not implement any Obsidian, Kanban, Dataview, note creation, YAML frontmatter syncing, or dashboard behavior. Instead, it is a release/publishing utility script for distributing the skill to ClawHub. This is a materially different primary purpose and involves undeclared external publication behavior.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The implemented script is a one-time setup utility, not a full task-board management tool. It creates two markdown files: a Kanban board scaffold and a Dataview dashboard scaffold. While this partially matches the setup portion of the description, several core declared capabilities are absent: there is no code to create individual task notes, no YAML frontmatter generation, no logic to update or synchronize task status across board and notes, and no handling of links to supporting notes. The actual primary purpose is narrower than declared, so the description materially overstates behavior.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
93% confidence
Finding

The README instructs users to run npx clawhub@latest install ..., which fetches and executes the latest published package at install time rather than a fixed trusted version. If the package is compromised, typosquatted, or a malicious release is published, users could execute attacker-controlled code on their system. In this skill context, the command is part of installation/setup guidance, so the risk is meaningful because readers are likely to copy-paste it directly.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding

The publish instructions use npx -y clawhub@latest login, which again executes the newest remote package version without pinning. For maintainers, this is especially sensitive because publishing workflows often run with credentials or authenticated sessions, so a compromised upstream package could steal tokens or alter published artifacts. The skill context increases danger slightly because this command is aimed at maintainers performing privileged actions.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill instructs the agent to create and modify files in an Obsidian vault, but it does not declare any explicit tool scope such as permissions or allowed-tools. That gap weakens the security boundary because file-writing behavior can occur without transparent, least-privilege disclosure, making misuse or overbroad file modification harder to review and constrain.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding

The script executes 'npx -y clawhub@latest', which fetches and runs the newest package version at publish time without pinning. If the upstream package, dependency chain, or registry path is compromised, an attacker could achieve arbitrary code execution in the publisher's environment and potentially exfiltrate credentials or publish malicious artifacts.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.