Back to skill

Security audit

Debugger

Security checks for vulnerabilities and agentic risk

Overview

This debugging helper appears purpose-built and local-only, but its script uses an unsafe predictable temporary file that could overwrite user-writable files on shared systems.

Review this skill before installing on shared machines or privileged accounts. It appears to keep analysis local and does not run the suggested fixes, but users should avoid feeding it sensitive logs unless they are comfortable with local processing, and the publisher should replace the fixed /tmp file with in-memory patterns or a private temporary directory.

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/script.sh:35
Finding

Predictable Shared Temporary File Allows Symlink-Based File Overwrite

Content
View full analysis

Vulnerability Details

File Location: scripts/script.sh, lines 8, 35-36, 72, 101, and 132
Vulnerability Type: Predictable and unsafe temporary-file handling
Risk Level: Medium

The script stores its diagnostic pattern database at the fixed, globally predictable path /tmp/debug-patterns.json. It opens this path for writing on every invocation without securely creating the file, verifying ownership, or rejecting symbolic links.

bash
PATTERNS_FILE="/tmp/debug-patterns.json"

init_patterns() {
python3 << 'PYEOF'
import json
patterns = [
    # Static diagnostic patterns omitted for brevity
]
with open("/tmp/debug-patterns.json", "w") as f:
    json.dump(patterns, f)
print(f"Loaded {len(patterns)} error patterns")
PYEOF
}

The same shared path is subsequently opened for reading in all three processing functions:

python
with open("/tmp/debug-patterns.json") as f:
    patterns = json.load(f)

Technical Analysis

/tmp is commonly writable by every local user. Although its sticky bit normally prevents users from deleting one another's files, it does not make a predictable filename safe. An attacker who creates /tmp/debug-patterns.json before the victim runs the Skill can control what filesystem object that path references.

Python's open("/tmp/debug-patterns.json", "w") follows symbolic links and truncates the resolved target before writing. The script does not use exclusive creation, inspect the path with lstat, verify file ownership, or place the file in a private per-process directory. Consequently, a malicious local user can create the predictable path as a symbolic link to another file writable by the victim. When the victim invokes any command, init_patterns follows that link, truncates the target, and replaces its contents with JSON.

The shared path also creates a race condition between concurrent invocations. One process may truncate or rewrite the file whi ...[truncated 1736 chars]

Remediation
View remediation

Remediation Suggestions

Prefer eliminating the temporary file entirely. The patterns are static and can remain in memory within each Python invocation or be stored as a read-only resource inside the Skill package.

If a temporary file is required:

  1. Create a private, unpredictable directory using mktemp -d.
  2. Set a restrictive umask, such as umask 077, before creating files.
  3. Store the JSON file inside that private directory.
  4. Register a shell trap to remove the directory on normal exit and interruption.
  5. Pass the generated path explicitly to Python rather than embedding a fixed /tmp path.
  6. Use exclusive file creation where appropriate and reject symbolic links.
  7. Ensure every read and write uses the same private path.
  8. Avoid sharing mutable temporary state between concurrent invocations.

Example hardening approach:

bash
umask 077
TMP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/debugger.XXXXXXXX")"
PATTERNS_FILE="$TMP_DIR/debug-patterns.json"
trap 'rm -rf -- "$TMP_DIR"' EXIT HUP INT TERM

export PATTERNS_FILE

The Python code should then retrieve the private path from the environment:

python
import json
import os

patterns_file = os.environ["PATTERNS_FILE"]
with open(patterns_file, "x", encoding="utf-8") as f:
    json.dump(patterns, f)

For later reads, open that same private path in read-only mode. Keeping the patterns entirely in memory remains the safest and simplest solution.

Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (3)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding

The skill describes command-style operations over user-supplied error text or files and the analyzer detected shell, environment, and file-write capabilities, but the manifest does not declare any explicit tool scope or permissions boundaries. That creates an avoidable trust gap: a consumer cannot tell whether the skill may read local files, inspect secrets from environment variables, or invoke shell commands during debugging, which is especially risky because logs and stack traces often contain credentials, tokens, internal paths, and service metadata.

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 · scripts/script.sh (reported line 22)May include surrounding context.

sh
{"pattern": "ImportError", "lang": "Python", "cause": "Cannot import name from module", "fix": "Check spelling, ensure package is installed, check __init__.py"},
    {"pattern": "ECONNREFUSED", "lang": "Node/System", "cause": "Connection refused — target service is not running or wrong port", "fix": "Check the service is running: systemctl status <service> or netstat -tlnp"},
    {"pattern": "ENOENT", "lang": "Node/System", "cause": "File or directory does not exist", "fix": "Check the path exists: ls -la <path>. Check for typos in the filename"},
    {"pattern": "EACCES", "lang": "Node/System", "cause": "Permission denied", "fix": "Check file permissions: chmod 644 <file> or run with appropriate user"},
    {"pattern": "Cannot find module", "lang": "Node", "cause": "npm module not installed", "fix": "Run: npm install <module> or npm install in project root"},
    {"pattern": "SyntaxError: Unexpected token", "lang": "Node/JS", "cause": "JavaScript syntax error", "fix": "Check for missing brackets, commas, or semicolons near the indicated line"},
    {"pattern": "panic: runtime error", "lang": "Go", "cause": "Runtime panic — nil pointer or index out of bounds", "fix": "Add nil checks before dereferencing pointers. Check slice bounds"},

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/script.sh (reported line 29)May include surrounding context.

sh
{"pattern": "undefined: ", "lang": "Go", "cause": "Symbol not defined in scope", "fix": "Check import paths, spelling, and that the package is in go.mod"},
    {"pattern": "command not found", "lang": "Bash", "cause": "Command not installed or not in PATH", "fix": "Install the command or add its directory to PATH: export PATH=$PATH:/path/to/bin"},
    {"pattern": "No such file or directory", "lang": "Bash", "cause": "File or path does not exist", "fix": "Check the path with: ls -la <path>. Ensure working directory is correct"},
    {"pattern": "Permission denied", "lang": "Bash", "cause": "Insufficient permissions to access file or execute command", "fix": "Use chmod to fix permissions or prefix with sudo if appropriate"},
    {"pattern": "OOMKilled", "lang": "Docker/K8s", "cause": "Container killed due to out of memory", "fix": "Increase memory limits in container spec or optimize application memory usage"},
    {"pattern": "CrashLoopBackOff", "lang": "Kubernetes", "cause": "Container keeps crashing and restarting", "fix": "Check logs: kubectl logs <pod> --previous. Fix the application startup error"},
    {"pattern": "ImagePullBackOff", "lang": "Kubernetes", "cause": "Cannot pull container image", "fix": "Check image name/tag, registry credentials: kubectl describe pod <pod>"},

Static analysis

No suspicious patterns detected.