Back to skill

Security audit

Obsidian Official CLI Headless

Security checks for vulnerabilities and agentic risk

Overview

This skill is purpose-aligned but needs review because its root-run setup scripts can make broad system changes, create an unsafe wrapper, and modify vault notes during verification.

Review this skill before installing on any important host. Use only a carefully chosen vault path, clear privileged environment variables such as WRAPPER_PATH and OBSIDIAN_USER, avoid running verification unless you accept a write to the daily note, and prefer a version that validates paths, safely creates the wrapper, and verifies the downloaded package.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/configure_official_cli.sh:62
Finding
Shell Injection Through Unsafely Generated Wrapper Script<![CDATA[ ## Vulnerability Details **File Location**: `scripts/configure_official_cli.sh`, lines 8–10 and 62–76 **Vulnerability Type**: Shell command injection through unescaped configuration values **Risk Level**: High ### Vulnerable Code ```bash VAULT_PATH="$(realpath -m "${1:-/root/obsidian-vault}")" OBSIDIAN_USER="${OBSIDIAN_USER:-obsidian}" WRAPPER_PATH="${WRAPPER_PATH:-/usr/local/bin/obs}" ``` ```bash cat > "$WRAPPER_PATH" <<EOF #!/usr/bin/env bash set -euo pipefail cmd=() for arg in "\$@"; do cmd+=("\$(printf '%q' "\$arg")") done exec su - ${OBSIDIAN_USER} -c "cd ${VAULT_PATH} && xvfb-run -a /usr/bin/obsidian --disable-gpu \${cmd[*]}" EOF chmod +x "$WRAPPER_PATH" ``` ### Technical Analysis The script generates an executable shell wrapper while directly interpolating `VAULT_PATH` and `OBSIDIAN_USER` into shell source code. These values are not encoded with `printf '%q'`, passed as positional arguments, or otherwise constrained to a safe character set. Although `realpath -m` normalizes the vault path, it does not remove shell metacharacters such as double quotes, semicolons, command substitutions, or newlines. A crafted path can therefore terminate the generated `cd` command context and insert additional commands into the wrapper. The arguments passed to the generated wrapper are individually escaped, but that protection does not apply to the values embedded while the wrapper is created. The generated wrapper is normally installed at `/usr/local/bin/obs` and may subsequently be executed by the root-run verification workflow. The same vault path and vault name are also interpolated into JSON without JSON escaping: ```bash cat > "$CONFIG_FILE" <<JSON { "cli": true, "vaults": { "${VAULT_NAME}": { "path": "${VAULT_PATH}", "ts": ${TS}, "open": true } } } JSON ``` This can produce malformed or attacker-controlled configuration fields, although the direct shell injection in the wrapper is the more severe issue. ### Att ...[truncated 1274 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Do not generate executable shell code containing interpolated paths or usernames. - Store the vault path in a root-owned configuration file and read it as data at runtime. - Pass dynamic values as positional parameters rather than inserting them into a `su -c` command string. - If source generation cannot be avoided, encode every inserted shell value with `printf '%q'` before writing it. - Validate `OBSIDIAN_USER` against an appropriate strict username pattern and verify that its home directory is obtained from the system account database rather than constructed from the username. - Generate `obsidian.json` with a JSON-aware tool such as Python or `jq` so quotes, backslashes, control characters, and newlines are correctly escaped. - Add regression tests using vault paths containing spaces, quotes, semicolons, dollar signs, command substitutions, and newlines. - Avoid invoking the generated wrapper as root during verification when root privileges are not required. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/configure_official_cli.sh:62
Finding
Unrestricted Privileged File Overwrite Through WRAPPER_PATH<![CDATA[ ## Vulnerability Details **File Location**: `scripts/configure_official_cli.sh`, lines 10 and 62–76 **Vulnerability Type**: Arbitrary file overwrite and unsafe privileged file creation **Risk Level**: High ### Vulnerable Code ```bash WRAPPER_PATH="${WRAPPER_PATH:-/usr/local/bin/obs}" ``` ```bash cat > "$WRAPPER_PATH" <<EOF #!/usr/bin/env bash set -euo pipefail cmd=() for arg in "\$@"; do cmd+=("\$(printf '%q' "\$arg")") done exec su - ${OBSIDIAN_USER} -c "cd ${VAULT_PATH} && xvfb-run -a /usr/bin/obsidian --disable-gpu \${cmd[*]}" EOF chmod +x "$WRAPPER_PATH" ``` ### Technical Analysis The script is required to run as root but permits `WRAPPER_PATH` to be supplied through an unrestricted environment variable. The selected path is opened with shell redirection, which creates or truncates the target. The script then marks that target executable. There is no validation that the destination is `/usr/local/bin/obs`, that it resides in an approved directory, or that it is a regular file. There are also no protections against symbolic links. Consequently, a malicious or accidentally inherited environment can redirect the write to another root-accessible file. The operation is not atomic and does not explicitly establish secure ownership and permissions before exposing the generated file. ### Attack Path 1. An attacker influences the environment inherited by the privileged configuration process, or convinces an operator to set `WRAPPER_PATH` to an attacker-selected destination. 2. The operator executes `configure_official_cli.sh` as root. 3. Shell redirection follows the supplied path, including a symbolic link if present, and truncates or creates the destination. 4. The script writes wrapper content to that file. 5. `chmod +x` changes the target's executable permissions. 6. Depending on the destination, the overwrite can immediately damage system configuration or replace a script that is later run by a privileged process. ### Impact Assessment Th ...[truncated 508 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove the `WRAPPER_PATH` environment override unless it is strictly necessary. - Prefer a fixed destination such as `/usr/local/bin/obs`. - If customization is required, resolve the destination and enforce an allowlist of approved absolute paths or directories. - Reject symbolic links and any existing target that is not a regular root-owned file. - Create the wrapper in a secure temporary file within the destination directory using restrictive permissions, set ownership explicitly, and atomically rename it into place. - Use `install -o root -g root -m 0755` after validating the destination rather than unrestricted redirection followed by `chmod`. - Clear or explicitly control privileged environment variables before running the configuration process. ]]>

T08 · Insecure Dependencies

Warning
Location
scripts/install_official_obsidian.sh:41
Finding
Downloaded Debian Package Is Installed as Root Without Integrity Verification<![CDATA[ ## Vulnerability Details **File Location**: `scripts/install_official_obsidian.sh`, lines 9–10 and 41–42 **Vulnerability Type**: Unverified remote package installation **Risk Level**: Medium ### Vulnerable Code ```bash VERSION="${OBSIDIAN_VERSION:-1.12.4}" DEB_URL="https://github.com/obsidianmd/obsidian-releases/releases/download/v${VERSION}/obsidian_${VERSION}_amd64.deb" ``` ```bash curl -LfsS "$DEB_URL" -o "$TMPDIR/obsidian.deb" apt-get install -y "$TMPDIR/obsidian.deb" ``` ### Technical Analysis The installer downloads a Debian package from the official Obsidian GitHub release repository over HTTPS and immediately installs it as root. It does not verify a pinned cryptographic checksum or package signature before installation. HTTPS provides transport protection but does not independently verify that the release asset matches a version reviewed or approved by the project. A compromise of the upstream release account, release asset, redirect chain, or delivery infrastructure could replace the package. The `OBSIDIAN_VERSION` environment variable also permits selection of a different release without requiring a corresponding trusted digest. Debian package installation can execute package maintainer scripts with root privileges, making package integrity security-critical. ### Attack Path 1. An attacker compromises or replaces the selected upstream release asset, or otherwise causes the trusted URL to deliver a modified package. 2. Alternatively, an unreviewed version is selected through `OBSIDIAN_VERSION` and its package contains compromised content. 3. The installer downloads the package successfully because no expected digest or signature is checked. 4. `apt-get install` installs the package as root. 5. Malicious binaries or Debian maintainer scripts execute with root privileges during installation or later use. This attack requires compromise or malicious modification of the upstream package or its distribution path; the audited code does n ...[truncated 474 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Pin each approved Obsidian version to a known SHA-256 or stronger digest maintained within the Skill. - Verify the downloaded file with `sha256sum -c` before invoking `apt-get`. - Fail closed if the requested version has no trusted checksum. - If Obsidian publishes signed checksums or an authenticated package repository, verify the signature using a pinned official signing key. - Restrict `OBSIDIAN_VERSION` to an explicit allowlist of reviewed versions and associated digests. - Record the final URL, package version, and verified digest in installation output for auditability. - Consider downloading as an unprivileged user and only elevating privileges after integrity verification. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • 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
Findings (8)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The skill claims to set up a safer headless model with a dedicated non-root user, ACL-restricted vault access, Xvfb adaptation, and a stable wrapper, but the analyzed behavior reportedly does not actually enforce those controls. This mismatch is dangerous because operators may trust the documented safety properties and run a workflow as root or in an incompletely configured state, exposing sensitive vault data or causing insecure system changes under false assumptions.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill clearly instructs shell execution as root and references multiple installation/configuration scripts, but it declares no explicit tool scope such as allowed-tools or permissions. That creates an authorization gap where an agent may invoke shell commands without a formally constrained execution boundary, increasing the risk of unintended or over-privileged command execution in a high-impact system-modifying workflow.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The script, when run as root, recursively changes ACLs on a user-supplied vault path, modifies /root traversal permissions when the vault is under /root, writes a config file, and installs an executable wrapper under /usr/local/bin without any confirmation, scoping checks, or warning to the operator. In this headless Obsidian setup context these actions are expected, but they still create real risk because a mis-specified VAULT_PATH or wrapper path can silently broaden access to sensitive files or overwrite system binaries.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
set -euo pipefail

if [[ ${EUID:-$(id -u)} -ne 0 ]]; then
  echo "Run as root." >&2
  exit 1
fi
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
set -euo pipefail

if [[ ${EUID:-$(id -u)} -ne 0 ]]; then
  echo "Run as root." >&2
  exit 1
fi
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
This shell script runs as root and makes system-level changes by updating packages, installing dependencies, and creating a new local user account. Although it prints status messages after some actions, there is no prior disclosure or confirmation warning that these privileged changes will be made to the host system.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The verification script performs a real write to the user's vault by appending a marker to the daily note, which modifies user data during what appears to be a validation step. In this skill context, the behavior is likely intended as an end-to-end test, but it is still unsafe because it changes persistent note content without explicit consent, dry-run support, or cleanup.

Missing User Warnings

Low
Confidence
89% confidence
Finding
The verification sequence includes a write operation, `obs daily:append content="skill verification"`, but the skill does not warn that verification will modify user vault contents. In a notes or knowledge-management context, silent data mutation can damage trust, pollute records, or alter sensitive files unexpectedly, even if the change seems minor.

Static analysis

No suspicious patterns detected.