Back to skill

Security audit

Passwordstore Broker

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent password-helper skill, but its LAN credential intake and TOTP enrollment handling create real secret-exposure risks users should review before installing.

Install only if you are comfortable with a local password broker handling real credentials. Prefer localhost mode, avoid the LAN phone flow on untrusted networks, treat the QR code and otpauth URL as secrets, and review every command that will run with injected credentials. Be aware that this stores account secrets in pass and stores the broker's TOTP seed locally under ~/.passwordstore-broker.

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/get_password_from_user.py:553
Finding

LAN Secret Intake Uses an Unverifiable Self-Signed TLS Certificate

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/get_password_from_user.py:481
Finding

Unbounded Request Body and Threaded Handling Allow LAN Denial of Service

Content
View full analysis
Remediation
View remediation
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
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
Findings (25)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill claims secrets are collected through one-time HTTPS forms and used via an environment-injection wrapper so raw values do not enter chat context or logs, but the documented interface also includes direct secret retrieval via scripts/vault.sh get and the analysis indicates the promised collection/execution mechanisms may be absent. This is dangerous because it creates a false sense of safety: an agent may rely on protections that do not actually exist, causing direct secret disclosure to stdout, chat, or logs during normal operation.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill claims secrets are collected through one-time HTTPS forms and used via an environment-injection wrapper so raw values do not enter chat context or logs, but the documented interface also includes direct secret retrieval via scripts/vault.sh get and the analysis indicates the promised collection/execution mechanisms may be absent. This is dangerous because it creates a false sense of safety: an agent may rely on protections that do not actually exist, causing direct secret disclosure to stdout, chat, or logs during normal operation.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · references/SETUP.md (reported line 127)May include surrounding context.

scripts/vault.sh put test/secret <<< "ok" scripts/vault.sh exists test/secret scripts/run_with_secret.sh --secret test/secret --env TEST_SECRET -- sh -c 'test "$TEST_SECRET" = "ok"' scripts/vault.sh rm test/secret

text

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The payload printed to stdout always includes the full otpauth URL, which embeds the raw TOTP shared secret, and error paths also print it to stderr. In a skill explicitly intended to keep raw secrets out of chat context and logs, emitting the enrollment secret directly defeats that guarantee and can allow anyone with log or transcript access to clone the second factor.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill declares operational steps that invoke local scripts, read and write files under the user's home directory, use networked HTTPS intake flows, and execute shell commands, yet it does not define any explicit tool scope or allowed-tools boundaries. That omission increases the chance an agent will run powerful filesystem, shell, and network actions without least-privilege controls or clear user-visible constraints.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · SKILL.md (reported line 82)May include surrounding context.

md
## Non-Negotiable Guardrails

- Never ask users to paste raw secrets into chat.
- Never echo secret values back to user.
- Never store secrets in repo files, commit messages, issue comments, or transcripts.
- Never expose intake over public interfaces or tunnels.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · references/SETUP.md (reported line 29)May include surrounding context.

Debian/Ubuntu

bash
sudo apt-get update
sudo apt-get install -y pass gnupg2 openssl python3 qrencode

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · references/SETUP.md (reported line 30)May include surrounding context.

Debian/Ubuntu

bash
sudo apt-get update
sudo apt-get install -y pass gnupg2 openssl python3 qrencode

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · references/SETUP.md (reported line 36)May include surrounding context.

Debian/Ubuntu

bash
sudo apt-get update
sudo apt-get install -y pass gnupg2 openssl python3 qrencode

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · references/SETUP.md (reported line 42)May include surrounding context.

Debian/Ubuntu

bash
sudo apt-get update
sudo apt-get install -y pass gnupg2 openssl python3 qrencode

Session Persistence

Medium
Category
Rogue Agent
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.

Content

Scanner excerpt · references/SETUP.md (reported line 47)May include surrounding context.

Initialize password store

  1. Create a GPG key (if needed):
bash
gpg --full-generate-key

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/get_password_from_user.py (reported line 191)May include surrounding context.

python
raise RuntimeError("Missing required command 'ip' for Linux LAN detection")

    try:
        route_proc = subprocess.run(
            [ip_cmd, "-j", "route", "get", "1.1.1.1"],
            check=True,
            stdout=subprocess.PIPE,

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/get_password_from_user.py (reported line 215)May include surrounding context.

python
raise RuntimeError("Linux LAN detection failed: route output missing interface name")

    try:
        addr_proc = subprocess.run(
            [ip_cmd, "-j", "-f", "inet", "addr", "show", "dev", iface_name],
            check=True,
            stdout=subprocess.PIPE,

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/get_password_from_user.py (reported line 258)May include surrounding context.

python
raise RuntimeError("Missing required command 'route' for macOS LAN detection")

    try:
        route_proc = subprocess.run(
            [route_cmd, "-n", "get", "default"],
            check=True,
            stdout=subprocess.PIPE,

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/get_password_from_user.py (reported line 279)May include surrounding context.

python
raise RuntimeError("macOS LAN detection failed: default route missing interface name")

    try:
        proc = subprocess.run(
            ["ifconfig", iface_name],
            check=True,
            stdout=subprocess.PIPE,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
79% confidence
Finding

This code accepts a remotely submitted secret over the HTTPS form and forwards it directly to an external script, vault.sh, using a secret name supplied from the command line. While the subprocess call itself is not shell-injectable, the security boundary is weak because untrusted input is handed to another executable with no local validation of the secret identifier or confinement of what vault.sh may write, so a malformed or unexpected secret name could become dangerous depending on vault.sh's implementation. In this skill context, which is explicitly designed to handle secrets, this trust boundary matters more because it can lead to secret misrouting, overwrite of unintended entries, or downstream injection in the storage helper.

Content

Scanner excerpt · scripts/get_password_from_user.py (reported line 531)May include surrounding context.

python
return

        try:
            subprocess.run(
                [self.state.vault_script, "put", self.state.secret_name],
                input=secret_value.encode("utf-8"),
                check=True,

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/get_password_from_user.py (reported line 568)May include surrounding context.

python
except ValueError:
        san = f"DNS:{hostname},DNS:localhost,IP:127.0.0.1"

    subprocess.run(
        [
            openssl,
            "req",

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/setup_totp_enrollment.py (reported line 17)May include surrounding context.

python
if sys.platform == "darwin":
        return "brew install qrencode"
    if shutil.which("apt-get"):
        return "sudo apt-get install -y qrencode"
    if shutil.which("dnf"):
        return "sudo dnf install -y qrencode"
    if shutil.which("pacman"):

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/setup_totp_enrollment.py (reported line 19)May include surrounding context.

python
if sys.platform == "darwin":
        return "brew install qrencode"
    if shutil.which("apt-get"):
        return "sudo apt-get install -y qrencode"
    if shutil.which("dnf"):
        return "sudo dnf install -y qrencode"
    if shutil.which("pacman"):

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/setup_totp_enrollment.py (reported line 21)May include surrounding context.

python
if sys.platform == "darwin":
        return "brew install qrencode"
    if shutil.which("apt-get"):
        return "sudo apt-get install -y qrencode"
    if shutil.which("dnf"):
        return "sudo dnf install -y qrencode"
    if shutil.which("pacman"):

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This script introduces a new secret-management path for TOTP enrollment that is outside the skill's stated design of handling secrets via one-time HTTPS forms and pass-backed storage. In a secret-handling skill, undocumented alternate secret flows increase the attack surface, bypass expected controls, and can lead operators to assume protections exist where they do not.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script stores the TOTP shared secret directly in ~/.passwordstore-broker/totp.secret instead of using the manifest-described pass storage path. Even with chmod 0600, this creates an unmanaged plaintext secret at rest that may be copied by backups, endpoint tooling, or local compromise, undermining the broker's stated safe-secret-handling model.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

When qrencode is missing, the script prints a manual enrollment URL containing the full TOTP secret to stderr without warning. stderr is frequently captured by terminals, CI systems, wrappers, or agent logs, so this can leak the shared secret and permit unauthorized enrollment of a duplicate authenticator.

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/setup_totp_enrollment.py (reported line 101)May include surrounding context.

python
return 2

    try:
        subprocess.run(
            [qrencode, "-o", str(qr_png_path), "-t", "PNG", otpauth_url],
            check=True,
            stdout=subprocess.DEVNULL,

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

On QR generation failure, the script again prints the full otpauth enrollment URL, exposing the TOTP shared secret during an error path where users are likely to paste logs for troubleshooting. Error-path secret disclosure is especially risky because it propagates secrets into support channels and automation logs outside the intended secret boundary.

Content

No source excerpt is available for this finding.