T06 · System Persistence
- Location
scripts/generate_runbook.py:571- Finding
Unvalidated generation of privileged systemd installation and persistence commands
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This runbook skill is mostly coherent, but it automatically reads sensitive project files and generates privileged service-install commands that need careful review before use.
Install only if you are comfortable with the skill reading infrastructure files in the project you point it at, including live .env metadata. Run it only on trusted project directories, review generated runbooks before executing any commands, and treat sudo, systemctl, docker stop/remove, and deployment steps as manual procedures requiring separate approval.
scripts/generate_runbook.py:571Unvalidated generation of privileged systemd installation and persistence commands
scripts/generate_runbook.py:369Project scan boundary can be bypassed through symbolic links
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
Including '.env / .env.example' in the scan target list is a direct credential-access risk because .env files commonly store API keys, database passwords, tokens, and other secrets. In the context of a runbook generator, these secrets could be unintentionally surfaced in generated operational documentation, substantially increasing exposure.
| 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.
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.
At this point the script explicitly targets the live .env file in the project root and scans it. In an agent skill context, accessing a live secret-bearing file for a documentation task is a significant credential-exposure risk because even metadata about required secrets can leak sensitive architecture and secret inventory.
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))
The existence check precedes ingestion of a live secret file, enabling opportunistic harvesting whenever .env is present. This broadens the scan surface beyond safe templates and makes accidental disclosure likely in generated artifacts.
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 generator deliberately aggregates environment-variable data from scanned files, including live .env content, into a single structure that is then rendered into output. In the context of an agent skill that may run over arbitrary projects and share results broadly, this is a genuine data-harvesting behavior that can expose secret inventory, service names, auth integrations, and deployment-sensitive metadata.
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 capabilities that imply reading project files, writing output files, and invoking a shell command, but it declares no explicit tool restrictions such as permissions or allowed-tools. In an agent setting, missing scope boundaries can allow broader-than-intended tool use and make it easier for the skill to be invoked with dangerous file paths or command execution context.
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 skill explicitly scans .env files and environment variables to generate documentation, but it does not warn that secrets may be ingested and reproduced in the generated runbook. This creates a realistic risk of credential disclosure into markdown, JSON output, chat responses, logs, or version control, especially because runbooks are often widely shared.
The skill scans a live .env file and incorporates discovered variable names and placeholder state into generated output. Even though it masks many values, enumerating secret-bearing variable names and configuration shape can disclose sensitive operational details beyond what users may expect from a runbook generator.
The tool inspects live .env files without clear user-facing notice at the point of use, then reflects derived information into the generated artifact. In a documentation-generation context, that silent expansion of scan scope can surprise users and expose sensitive config metadata in shared runbooks.
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.
The script auto-generates commands such as sudo cp into /etc/systemd/system/, systemctl enable/start, docker compose down, and docker rm, which can alter system state or stop running services. While the final footer advises review before production use, there is no specific warning adjacent to these safety-critical operations about service disruption, privilege requirements, or irreversible effects.
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}")
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}")
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}")