Back to skill

Security audit

🛡️ Credential Vault / 凭证保险箱

Security checks for vulnerabilities and agentic risk

Overview

This credential vault is mostly clear about its purpose, but its shell helper has a real code-injection risk while handling decrypted secrets.

Review before installing. Do not use the Bash helper with untrusted service or field names, and prefer the Python CLI/API path until the helper passes arguments as data rather than interpolating them into Python source. Avoid keeping CRED_MASTER_PASS in a long-lived environment and be aware that retrieved secrets are printed in plaintext.

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

Error
Location
scripts/cred_helper.sh:40
Finding

Python Code Injection Through Shell Helper Arguments

Content
View full analysis

Vulnerability Details

File Location: scripts/cred_helper.sh, lines 40–41
Vulnerability Type: Python code injection caused by unsafe interpolation into a python3 -c program
Risk Level: High

Vulnerable Code

bash
echo "$CRED_MASTER_PASS" | gpg --batch --yes --passphrase-fd 0 --decrypt "$CRED_FILE" 2>/dev/null | \
    python3 -c "import sys,json; d=json.load(sys.stdin); print(d['$service']['$key'])" 2>/dev/null

Technical Analysis

The cred_get function obtains service and key from its first and second arguments and interpolates them directly into Python source code passed to python3 -c.

Shell quoting does not make these values safe within the generated Python program. An argument containing Python quote delimiters and additional expressions can terminate the intended dictionary index and alter the program evaluated by Python. Consequently, an attacker who controls either argument can execute arbitrary Python code instead of merely selecting a credential field.

Although the shell invokes Python rather than evaluating the arguments as shell syntax directly, arbitrary Python execution can invoke operating-system commands through modules such as os or subprocess. The vulnerability therefore results in arbitrary code execution with the privileges of the user who sourced and called the helper.

Attack Path

  1. A user sources scripts/cred_helper.sh, making cred_get available in the current shell.
  2. The user or another script supplies an attacker-controlled service name or field name to cred_get.
  3. The function decrypts credentials.json.gpg and pipes the complete plaintext credential document to Python through standard input.
  4. The attacker-controlled value is inserted into the source string supplied to python3 -c.
  5. A crafted value breaks out of the intended dictionary lookup and introduces additional Python expressions or statements.
  6. Python evaluates the injected code with the invoking user's permiss ...[truncated 991 chars]
Remediation
View remediation

Remediation Suggestions

Do not construct Python source code using caller-controlled values. Pass the service and key as separate positional arguments and retrieve them through sys.argv:

bash
echo "$CRED_MASTER_PASS" |
    gpg --batch --yes --passphrase-fd 0 --decrypt "$CRED_FILE" 2>/dev/null |
    python3 -c '
import json
import sys

data = json.load(sys.stdin)
print(data[sys.argv[1]][sys.argv[2]])
' "$service" "$key"

Additional hardening measures should include:

  1. Validate that exactly two non-empty arguments are supplied.
  2. Preserve strict quoting around "$service" and "$key".
  3. Add controlled handling for missing services, missing fields, malformed JSON, and GPG failures without revealing unrelated secrets.
  4. Enable pipeline failure propagation, preferably in a dedicated executable script using set -o pipefail, so a decryption failure cannot be mistaken for a successful lookup.
  5. Add regression tests using arguments containing single quotes, double quotes, brackets, semicolons, newlines, and Python expressions to confirm they are treated exclusively as data.
  6. Consider replacing the inline Python implementation with a call to cred_manager.py so lookup and error-handling logic are maintained in one implementation.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (20)

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
# Dependencies / 依赖: GPG (gnupg), Python 3.8+

CRED_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CRED_FILE="$CRED_DIR/credentials.json.gpg"

cred_get() {
    local service="$1"

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
# Dependencies / 依赖: GPG (gnupg), Python 3.8+

CRED_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CRED_FILE="$CRED_DIR/credentials.json.gpg"

cred_get() {
    local service="$1"

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/cred_helper.sh (reported line 16)May include surrounding context.

sh
# Dependencies / 依赖: GPG (gnupg), Python 3.8+

CRED_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CRED_FILE="$CRED_DIR/credentials.json.gpg"

cred_get() {
    local service="$1"

Credential Access

High
Category
Privilege Escalation
Confidence
84% confidence
Finding

This skill is explicitly designed to store and retrieve credentials, so it necessarily provides a credential-access capability. In the context of an agent skill, exposing generic functions like get_service() and get_credential() without any authorization boundary, scoping, or audit controls increases the risk that other code paths or prompts could retrieve all stored secrets once the master password is available in the environment or process context.

Content

Scanner excerpt · scripts/cred_manager.py (reported line 41)May include surrounding context.

python
# ═══════════════════════════════════════════════════════════

# Encrypted file path / 加密文件路径
CRED_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'credentials.json.gpg')

# Master password: read from env var, never hardcode
# 主密码:从环境变量读取,不硬编码

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill explicitly depends on shell execution and environment-variable access, but it does not declare any tool scope such as permissions or allowed-tools. That creates an authorization mismatch where an agent may invoke shell/env capabilities without clear policy constraints, increasing the chance of unintended secret exposure or command execution.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The invocation guidance describes when to use the skill but does not provide explicit exclusions or negative examples for when it should not activate. Without those guardrails, an agent may invoke a sensitive credential-management skill for adjacent requests that do not require secret storage or retrieval.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

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

Content

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

md
During save/encrypt operations, plaintext JSON briefly exists as a temporary file:  
在保存/加密操作期间,明文 JSON 会短暂存在于临时文件中:

- Created with `mkstemp` + `fchmod 600` (owner-only read/write) / 使用 `mkstemp` + `fchmod 600` 创建(仅所有者可读写)
- Exists for milliseconds (only during GPG subprocess execution) / 仅存在毫秒级(GPG 子进程执行期间)
- Securely deleted: zero-overwrite → fsync → unlink / 安全删除:零覆写 → fsync → unlink
- **Risk / 风险**: on some systems, temp file contents may be recoverable from disk. For higher security, use a tmpfs/ramfs mount or a dedicated secrets manager.

Session Persistence

Medium
Category
Rogue Agent
Confidence
92% confidence
Finding

This is effectively the same real issue as the duplicate RA2 finding: plaintext credentials can transiently persist on disk despite overwrite and unlink attempts. Secure deletion is not reliable across modern filesystems and storage layers, so sensitive material may remain recoverable.

Content

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

md
- Created with `mkstemp` + `fchmod 600` (owner-only read/write) / 使用 `mkstemp` + `fchmod 600` 创建(仅所有者可读写)
- Exists for milliseconds (only during GPG subprocess execution) / 仅存在毫秒级(GPG 子进程执行期间)
- Securely deleted: zero-overwrite → fsync → unlink / 安全删除:零覆写 → fsync → unlink
- **Risk / 风险**: on some systems, temp file contents may be recoverable from disk. For higher security, use a tmpfs/ramfs mount or a dedicated secrets manager.  
  在某些系统上,临时文件内容可能可从磁盘恢复。如需更高安全性,请使用 tmpfs/ramfs 挂载或专用密钥管理器。

Session Persistence

Medium
Category
Rogue Agent
Confidence
92% confidence
Finding

This is effectively the same real issue as the duplicate RA2 finding: plaintext credentials can transiently persist on disk despite overwrite and unlink attempts. Secure deletion is not reliable across modern filesystems and storage layers, so sensitive material may remain recoverable.

Content

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

md
- Created with `mkstemp` + `fchmod 600` (owner-only read/write) / 使用 `mkstemp` + `fchmod 600` 创建(仅所有者可读写)
- Exists for milliseconds (only during GPG subprocess execution) / 仅存在毫秒级(GPG 子进程执行期间)
- Securely deleted: zero-overwrite → fsync → unlink / 安全删除:零覆写 → fsync → unlink
- **Risk / 风险**: on some systems, temp file contents may be recoverable from disk. For higher security, use a tmpfs/ramfs mount or a dedicated secrets manager.  
  在某些系统上,临时文件内容可能可从磁盘恢复。如需更高安全性,请使用 tmpfs/ramfs 挂载或专用密钥管理器。

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

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

Content

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

md
2. **Runtime injection / 运行时注入** — set via a secrets manager or session-scoped `read -s` prompt / 通过密钥管理器或会话级 `read -s` 提示设置
3. **Environment variable / 环境变量** — `export CRED_MASTER_PASS="..."` in current shell (convenient but less secure) / 在当前 shell 中设置(方便但安全性较低)

**Avoid / 避免:** persisting the master password in plaintext files (e.g., `~/.bashrc`). If you must, ensure `chmod 600` and understand the trade-off.  
不要将主密码明文写入文件(如 `~/.bashrc`)。如必须,请确保 `chmod 600` 并了解风险。

---

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

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

Content

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

md
2. **Runtime injection / 运行时注入** — set via a secrets manager or session-scoped `read -s` prompt / 通过密钥管理器或会话级 `read -s` 提示设置
3. **Environment variable / 环境变量** — `export CRED_MASTER_PASS="..."` in current shell (convenient but less secure) / 在当前 shell 中设置(方便但安全性较低)

**Avoid / 避免:** persisting the master password in plaintext files (e.g., `~/.bashrc`). If you must, ensure `chmod 600` and understand the trade-off.  
不要将主密码明文写入文件(如 `~/.bashrc`)。如必须,请确保 `chmod 600` 并了解风险。

---

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The usage text states that cred_get outputs passwords and tokens, and the implementation decrypts and prints them directly, but there is no explicit warning that this may expose secrets in terminal history, logs, or downstream command substitution. For a code file handling sensitive credentials, this disclosure is safety-relevant and should be called out to the user.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The script instructs users to export the master password in the CRED_MASTER_PASS environment variable, which is a sensitive credential handling operation. Although the code comments explain avoiding ps output leakage, there is no user-facing warning in the script comments or usage text about the security implications of storing a master password in an environment variable or that decrypted secrets will be output to stdout.

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

python
GPG 解密,通过 --passphrase-fd 从 stdin 传入密码。
    避免密码出现在命令行参数中。
    """
    proc = subprocess.Popen(
        ['gpg', '--batch', '--yes', '--passphrase-fd', '0',
         '--decrypt', input_file],
        stdin=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/cred_manager.py (reported line 87)May include surrounding context.

python
GPG encrypt via --passphrase-fd (stdin pipe).
    GPG 加密,通过 --passphrase-fd 从 stdin 传入密码。
    """
    proc = subprocess.Popen(
        ['gpg', '--batch', '--yes', '--passphrase-fd', '0',
         '--symmetric', '--cipher-algo', 'AES256',
         '-o', output_file, input_file],

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

python
if cmd == 'init':
        # Check GPG availability / 检查 GPG 是否可用
        try:
            subprocess.run(['gpg', '--version'], capture_output=True, check=True)
        except (FileNotFoundError, subprocess.CalledProcessError):
            print("❌ GPG not found. Please install first / 未找到 GPG,请先安装:")
            print("   Linux (Debian/Ubuntu): sudo apt install gnupg")

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

python
subprocess.run(['gpg', '--version'], capture_output=True, check=True)
        except (FileNotFoundError, subprocess.CalledProcessError):
            print("❌ GPG not found. Please install first / 未找到 GPG,请先安装:")
            print("   Linux (Debian/Ubuntu): sudo apt install gnupg")
            print("   Linux (RHEL/CentOS):   sudo yum install gnupg2")
            print("   macOS:                 brew install gnupg")
            print("   Windows:               https://gpg4win.org")

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

python
subprocess.run(['gpg', '--version'], capture_output=True, check=True)
        except (FileNotFoundError, subprocess.CalledProcessError):
            print("❌ GPG not found. Please install first / 未找到 GPG,请先安装:")
            print("   Linux (Debian/Ubuntu): sudo apt install gnupg")
            print("   Linux (RHEL/CentOS):   sudo yum install gnupg2")
            print("   macOS:                 brew install gnupg")
            print("   Windows:               https://gpg4win.org")

Vague Triggers

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

The invocation guidance describes when to use the skill but does not provide explicit exclusions or negative examples for when it should not activate. Without those guardrails, an agent may invoke a sensitive credential-management skill for adjacent requests that do not require secret storage or retrieval.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The module docstring consistently presents content in both Chinese and English and establishes that style as the default interaction pattern. This is a natural-language locale choice embedded in the skill without any indication that users can opt for a preferred language or a single-language mode.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.