T09 · Insecure Skill Coding Practices
- Location
scripts/generate_runbook.py:577- Finding
Shell Command Injection Through Unquoted Project Paths and systemd Unit Names
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This runbook generator is coherent, but it needs Review because it can expose sensitive configuration details and generates privileged shell commands from untrusted project names without safe quoting.
Install only if you are comfortable with the skill reading operational configuration in the target project. Prefer running it on trusted repositories, remove or replace live .env files with .env.example before generation, review Markdown and JSON output for secrets before sharing, and treat every generated shell block as a draft rather than commands to paste blindly, especially sudo/systemctl commands.
scripts/generate_runbook.py:577Shell Command Injection Through Unquoted Project Paths and systemd Unit Names
scripts/generate_runbook.py:785Sensitive Environment Values Are Exposed in Markdown and JSON Output
Referenced artifact was not completely inspected
python3 scripts/generate_runbook.py /path/to/project
Referenced artifact was not completely inspected
python3 scripts/generate_runbook.py /path/to/project
Referenced artifact was not completely inspected
python3 scripts/generate_runbook.py /path/to/project
Referenced artifact was not completely inspected
python3 scripts/generate_runbook.py /path/to/project
The skill explicitly scans .env and .env.example files, and .env files commonly contain API keys, database passwords, tokens, and other credentials. Even if the stated goal is only to extract required variable names, an implementation that reads these files can easily ingest and reproduce secret values in the generated runbook or agent context.
| systemd units (.service) | ExecStart/Stop/Reload, dependencies, restart policy |
| Makefile | Targets (build, test, deploy, clean, etc.) |
| package.json | Scripts (start, build, test, dev, deploy) |
| .env / .env.example | Required environment variables |
| nginx.conf | Upstream servers, listen ports, locations |
## Generated Sections
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"""Runbook Generator — create operational runbooks from project infrastructure files.
Scans Dockerfiles, docker-compose.yml, systemd units, Makefiles, package.json,
.env files, and nginx configs to produce step-by-step operational runbooks.
Pure Python stdlib — no external dependencies.
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"""Runbook Generator — create operational runbooks from project infrastructure files.
Scans Dockerfiles, docker-compose.yml, systemd units, Makefiles, package.json,
.env files, and nginx configs to produce step-by-step operational runbooks.
Pure Python stdlib — no external dependencies.
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"""Runbook Generator — create operational runbooks from project infrastructure files.
Scans Dockerfiles, docker-compose.yml, systemd units, Makefiles, package.json,
.env files, and nginx configs to produce step-by-step operational runbooks.
Pure Python stdlib — no external dependencies.
The dedicated .env scanner function is a credential-adjacent capability because .env files routinely store API keys, database credentials, tokens, and other secrets. Even with partial value masking, parsing these files and exposing structured results materially increases the chance of sensitive information disclosure.
def scan_env_file(path):
"""Extract environment variables from .env or .env.example."""
info = {
"type": "env_file",
"path": str(path),
The project scanner explicitly looks for a live .env file and includes it in the scan set automatically. In a runbook-generation tool, this silent access to sensitive configuration increases exposure risk and may surprise users who only expected infrastructure metadata extraction.
if f.is_file() and "[Unit]" in f.read_text()[:200]:
scanned.append(scan_systemd_unit(f))
# Scan for .env (not .example)
env_file = root / ".env"
if env_file.exists():
scanned.append(scan_env_file(env_file))
This line performs the live .env scan once the file exists, directly enabling structured extraction from a common secret store. Because the results are later surfaced in generated artifacts, the behavior can leak configuration inventory to logs, terminals, saved runbooks, or downstream consumers.
scanned.append(scan_systemd_unit(f))
# Scan for .env (not .example)
env_file = root / ".env"
if env_file.exists():
scanned.append(scan_env_file(env_file))
The code aggregates environment variables from scanned sources, including live .env files, and then renders them into the generated runbook. This is dangerous because environment variables commonly encode secrets, service endpoints, account identifiers, and other privileged configuration details that can materially aid attackers even when some values are masked.
has_npm = any(s["type"] == "package_json" for s in scanned)
has_nginx = any(s["type"] == "nginx" for s in scanned)
# Collect all env vars
all_env = {}
for s in scanned:
if s["type"] == "env_file":
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
lines.append("")
lines.append("```bash")
lines.append("# Copy .env.example to .env and fill in values")
lines.append("cp .env.example .env")
lines.append("```")
lines.append("")
lines.append("| Variable | Default/Example | Required |")
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
lines.append("")
lines.append("```bash")
lines.append("# Copy .env.example to .env and fill in values")
lines.append("cp .env.example .env")
lines.append("```")
lines.append("")
lines.append("| Variable | Default/Example | Required |")
The skill advertises and demonstrates shell execution plus reading and writing project files, but it does not declare any explicit tool scope or permissions boundaries. That makes its operational capabilities ambiguous and increases the chance an agent invokes it with broader access than intended, especially because it processes arbitrary user-supplied project paths.
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.
---
name: runbook-generator
description: Generate operational runbooks from project files. Scans Dockerfiles, docker-compose.yml, systemd units, Makefiles, package.json, and config files to produce step-by-step operational runbooks with start/stop/restart/deploy/rollback/troubleshoot procedures. Use when asked to create a runbook, generate ops docs, create operational documentation, build a deployment guide, document service procedures, or create an SRE runbook. Triggers on "create runbook", "ops documentation", "deployment guide", "operational docs", "SRE runbook", "service procedures", "how to deploy".
---
# Runbook Generator
The trigger phrases are broad and common, including terms like "deployment guide," "ops documentation," and "how to deploy," which can cause the skill to activate in contexts the user did not intend. Because the skill scans infrastructure and config files, accidental invocation can expose sensitive operational details from a repository during otherwise routine conversations.
The skill description explains that it scans project files, including configuration-related artifacts, but does not warn that these files may contain secrets, internal hostnames, tokens, or deployment details that could be surfaced in the generated runbook. Omitting that warning increases the risk of users unknowingly disclosing sensitive data into generated documentation or downstream outputs.
scan_env_file parses real .env content and returns structured variable data that is later surfaced in Markdown and JSON output. In the context of a documentation skill, this broadens the tool into configuration harvesting and can leak secret inventory, feature flags, internal hostnames, and other sensitive deployment details.
The script inspects live .env files and surfaces the resulting variable inventory without explicit disclosure or consent gating. In a skill designed to generate runbooks, silently extracting and publishing sensitive configuration metadata increases the chance of inadvertent information exposure.
The script reads a live .env file from the target project and incorporates discovered variable names and presence/status into generated output. Even though values are masked in many cases, enumerating secret-bearing variable names and configuration structure can expose sensitive operational metadata and exceed what users may expect from a runbook generator.
This code generates operational instructions such as docker compose down, docker rm, systemctl start/stop, and sudo cp into system locations, which are safety-relevant and potentially disruptive. Although the generated runbook ends with a generic review note, the script itself does not provide a clear targeted warning that the generated commands may cause downtime, replace services, or require elevated privileges.
Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.
Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
lines.append(f"### systemd Deploy ({unit_name})")
lines.append("")
lines.append("```bash")
lines.append(f"sudo cp {s['path']} /etc/systemd/system/")
lines.append("sudo systemctl daemon-reload")
lines.append(f"sudo systemctl enable {unit_name}")
lines.append(f"sudo systemctl start {unit_name}")
No suspicious patterns detected.