Back to skill

Security audit

Headless Bitwarden

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent Bitwarden unlock helper, but it needs review because it handles a vault master password using a public tunnel option and an unsafe predictable FIFO/environment handoff.

Install only if you are comfortable with a review-level credential-handling risk. Use it on a trusted machine/account, disable the public tunnel unless remote unlock is necessary, treat the token URL as secret, avoid concurrent helper runs, and prefer a version that uses a private per-run FIFO or direct pipe instead of a fixed /tmp FIFO and password environment variable.

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 (1)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/rbw-remote-unlock/server.mjs:255
Finding
Predictable Shared FIFO Exposes the Vault Password to Same-User Race Attacks## Vulnerability Details **File Location**: `scripts/rbw-remote-unlock/server.mjs`, lines 17 and 255–278; `scripts/rbw-remote-unlock/pinentry.sh`, lines 5 and 31–33 **Vulnerability Type**: Predictable temporary-file path and non-atomic FIFO creation **Risk Level**: Medium ### Vulnerable Code `scripts/rbw-remote-unlock/server.mjs`: ```js const PASSWORD_FIFO = process.env.PASSWORD_FIFO || '/tmp/rbw-remote-unlock-password.fifo'; async function attemptUnlock(password) { console.error('rbw remote unlock: unlock attempt started'); await fs.rm(PASSWORD_FIFO, { force: true }).catch(() => {}); const mkfifoResult = await runCommand('mkfifo', ['-m', '600', PASSWORD_FIFO], { env: process.env, timeoutMs: 5_000, }); if (mkfifoResult.code !== 0) { throw new Error(summarizeCommandFailure(mkfifoResult, 'mkfifo failed')); } const fifoWriter = spawn('bash', ['-lc', 'for _ in 1 2 3; do printf "%s\\n" "$RBW_REMOTE_UNLOCK_PASSWORD" > "$PASSWORD_FIFO" || break; done'], { env: { ...process.env, RBW_REMOTE_UNLOCK_PASSWORD: password, PASSWORD_FIFO, }, stdio: 'ignore', }); try { const childEnv = { ...process.env, PASSWORD_FIFO, }; const unlockResult = await runCommand(RBW_BIN, ['unlock'], { env: childEnv }); if (unlockResult.code !== 0) { const msg = summarizeCommandFailure(unlockResult, 'rbw unlock failed'); console.error(`rbw remote unlock: unlock attempt failed: ${msg}`); throw new Error(msg); } console.error('rbw remote unlock: unlock attempt succeeded'); } finally { fifoWriter.kill('SIGTERM'); await fs.rm(PASSWORD_FIFO, { force: true }).catch(() => {}); } } ``` `scripts/rbw-remote-unlock/pinentry.sh`: ```bash password_fifo="${PASSWORD_FIFO:-/tmp/rbw-remote-unlock-password.fifo}" if [[ -z "$password" && -p "$password_fifo" ]]; then IFS= read -r -t 10 pass ...[truncated 2615 chars]
Remediation
## Remediation Suggestions 1. Eliminate the filesystem FIFO where possible. Pass the password through an anonymous pipe connected directly between the controlled parent and child processes so no shared pathname can be raced. 2. If a FIFO is required, create a unique private directory for every invocation using `fs.mkdtemp()` under a secure runtime location such as `$XDG_RUNTIME_DIR`. Set the directory permissions to `0700`. 3. Generate an unpredictable FIFO name inside that private directory and pass the exact path only to the required child processes. 4. Before use, validate the object with `lstat`: verify that it is a FIFO, is owned by the expected user, and has no group or world permissions. 5. Do not use a shared fallback pathname. Make failure to create a private per-run location fatal. 6. Remove the FIFO and private directory in all normal, error, timeout, and signal-handling paths. 7. Add concurrency tests that start multiple helpers simultaneously and verify that credentials cannot cross instance boundaries. 8. Minimize secret exposure in process environments as an additional defense. Avoid supplying the master password through `RBW_REMOTE_UNLOCK_PASSWORD` when direct pipe-based transfer is feasible.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (7)

Lp3

Medium
Category
MCP Least Privilege
Confidence
83% confidence
Finding
The skill describes shell and environment-variable based behavior but does not declare any explicit tool scope or permissions boundary. In an agent ecosystem, this can cause the skill to run with broader-than-necessary capabilities, increasing the chance of unintended command execution or secret exposure when the skill is invoked.

Session Persistence

Medium
Category
Rogue Agent
Content
3) **No secret logging / no secret persistence**
- Do not log request bodies.
- Do not write secrets to disk.

4) **Always restore rbw config**
- If a temporary `pinentry` override is used, it must be restored even on failure.
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Skill Enumeration

Medium
Category
Agent Snooping
Content
## Prereqs

1) Follow the workspace Bitwarden skill for setup (install, register/login):
- `skills/bitwarden/SKILL.md`

2) Additional requirements for the unlock helper:
- `rbw` installed and registered/logged-in (device approved)
Confidence
80% confidence
Finding
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The script reads a password from the RBW_REMOTE_UNLOCK_PASSWORD environment variable and from a FIFO, both of which are sensitive credential-handling operations. There is no confirmation prompt, logging, print statement, or explanatory comment warning that the script will consume secret material non-interactively.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The server executes binaries and shell commands selected through environment variables (`RBW_BIN`, `PINENTRY_PATH`) and invokes `bash -lc`, creating a command-execution surface that exceeds what a narrowly scoped unlock helper needs. If an attacker can influence the runtime environment or deployment wrapper, they can replace the intended `rbw`/pinentry programs with arbitrary executables and gain code execution in the helper's security context, which is especially sensitive because the service handles the Bitwarden master password.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The manifest frames this skill as a short-lived remote unlock helper so the user can unlock without pasting secrets into chat. In addition to serving the unlock page, the implementation modifies the user's rbw config.json to replace the pinentry setting and, when enabled, invokes `rbw sync`, which is a broader side effect than the description suggests.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
if [[ "$START_TUNNEL" != "0" ]]; then
  if command -v cloudflared >/dev/null 2>&1; then
    CLOUDFLARED_LOG="$(mktemp)"
    chmod 600 "$CLOUDFLARED_LOG"
    cloudflared tunnel --url "http://${HOST_VALUE}:${PORT_VALUE}" >"$CLOUDFLARED_LOG" 2>&1 &
    CLOUDFLARED_PID=$!
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/rbw-remote-unlock/server.mjs:164