Back to skill

Security audit

Restic Workstation Backup

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent backup purpose, but its setup scripts contain a real command-execution flaw in configuration handling that can run with root or persistent timer privileges.

Review this before installing. Only run the scripts with trusted, literal values, and do not let an agent or untrusted user supply repository, hostname, email, path, retention, or timezone arguments. Prefer a fixed version that stops sourcing generated env files or properly validates and escapes every value, and inspect any existing /etc/home-backup/env or ~/.config/restic-home/env before enabling timers.

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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/bootstrap_restic_home.sh:221
Finding

Root Command Injection Through Unsafely Generated and Sourced Environment File

Content
View full analysis
"${ENV_FILE}" </dev/null 2>&1; then echo " ✓ Repository already initialized — skipping init" else echo " Initializing repository at ${RESTIC_REPOSITORY}..." /usr/bin/restic init 2>&1 echo " ✓ Repository initialized" fi fi ``` Generated scheduled scripts also source the same file: ```bash #!/usr/bin/env bash set -euo pipefail source /etc/home-backup/env exec /usr/local/ ...[truncated 2327 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/install_userlevel_restic.sh:166
Finding

User-Level Command Injection Through Unsafely Sourced Configuration

Content
View full analysis
"${ENV_FILE}" < "${BIN_DIR}/restic-home-backup.sh" </dev/null 2>&1; then echo "✓ Repository already initialized" else restic init && echo "✓ Repository initialized" fi fi ``` ### Technical Analysis The user-level installer repeats the system installer’s unsafe design: untrusted command-line values are serialized directly into an executable shell file and later loaded with `source`. A malicious value can alter the syntax of `~/.config/restic- ...[truncated 1476 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/validate_restic_setup.sh:52
Finding

Predictable Privileged Restore Directory in World-Writable Temporary Storage

Content
View full analysis
&1); then END_E=$(date +%s) pass "Restore completed in $(( END_E - START_E ))s" echo "${RESTORE_OUT}" | tail -10 RESTORED_HOME="${DRILL_DIR}/home/$(basename "${BACKUP_SOURCE}")" declare -A VERIFY_FILES=( [".ssh/config"]="${RESTORED_HOME}/.ssh/config" ["Documents/roadmap.md"]="${RESTORED_HOME}/Documents/roadmap.md" [".config/git/config"]="${RESTORED_HOME}/.config/git/config" ) for label in "${!VERIFY_FILES[@]}"; do path="${VERIFY_FILES[$label]}" if [[ -f "${path}" ]]; then pass " Restored: ${label}" else info " Absent in restore: ${label} (OK if not present in source)" fi done else fail "Restore failed" echo "${RESTORE_OUT}" fi info "Cleaning up ${DRILL_DIR}..." rm -rf "${DRILL_DIR}" pass "Restore drill directory cleaned up" ``` The scheduled root audit script generated by the bootstrap uses the same path: ```bash DRILL_DIR="/tmp/restore-drill" RESTORE_LOG="${BACKUP_LOG_DIR}/audit-drill.log" rm -rf "\${DRILL_DIR}" mkdir -p "\${DRILL_DIR}" /usr/bin/restic restore latest --target "\${DRILL_DIR}" 2>&1 | tee -a "\${RESTORE_LOG}" ... rm -rf "\${DRILL_DIR}" ``` ### Technical Analysis The restore drill uses the fixed path `/tmp/restore-drill` in a world-writable shared namespace. It performs separate deletion, creation, restore, inspection, and cleanup operations without ...[truncated 1770 chars]
Remediation
View remediation
Vulnerability Patterns
  • 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
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (61)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% 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/runbook.md (reported line 293)May include surrounding context.

bash
bash install_userlevel_restic.sh --remove
# Config files are preserved; to fully clean:
rm -rf ~/.config/restic-home ~/.local/share/restic-home ~/.local/bin/restic-home-*.sh

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/runbook.md (reported line 293)May include surrounding context.

bash
bash install_userlevel_restic.sh --remove
# Config files are preserved; to fully clean:
rm -rf ~/.config/restic-home ~/.local/share/restic-home ~/.local/bin/restic-home-*.sh

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% 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/runbook.md (reported line 293)May include surrounding context.

bash
bash install_userlevel_restic.sh --remove
# Config files are preserved; to fully clean:
rm -rf ~/.config/restic-home ~/.local/share/restic-home ~/.local/bin/restic-home-*.sh

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

The runbook instructs use of a dedicated passphrase-free root SSH key for unattended backups. If that key is stolen from the host, an attacker gains persistent authenticated access to the backup server path, which can enable backup exfiltration, deletion, or tampering depending on server-side restrictions. The backup context makes this more sensitive because backup infrastructure often contains broad historical data.

Content

Scanner excerpt · references/runbook.md (reported line 337)May include surrounding context.

md
- **Password file** (`/etc/home-backup/password`): root-only (0600). Auto-generated with `openssl rand -base64 48`. Never printed in logs, scripts, or this document. To rotate: delete file, re-run bootstrap with `--apply`.
- **Env file** (`/etc/home-backup/env`): root-only (0600). Contains `RESTIC_REPOSITORY` and `RESTIC_PASSWORD_FILE`. Does not contain the password itself.
- **SSH key for remote access**: root's SSH key (`~root/.ssh/id_ed25519` or similar) must be authorized on `backupsvc@10.50.8.24`. The key should be dedicated and passphrase-free for unattended operation. Restrict it on the server side with `command="rrsync /srv/backups/home/devbox17"` in `authorized_keys`.

---

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% 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 · scripts/install_userlevel_restic.sh (reported line 80)May include surrounding context.

sh
restic-home-backup.timer \
    restic-home-prune.timer \
    restic-home-check.timer 2>/dev/null || true
  rm -f "${SYSTEMD_DIR}/restic-home-backup."{service,timer}
  rm -f "${SYSTEMD_DIR}/restic-home-prune."{service,timer}
  rm -f "${SYSTEMD_DIR}/restic-home-check."{service,timer}
  systemctl --user daemon-reload 2>/dev/null || true

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% 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 · scripts/install_userlevel_restic.sh (reported line 81)May include surrounding context.

sh
restic-home-prune.timer \
    restic-home-check.timer 2>/dev/null || true
  rm -f "${SYSTEMD_DIR}/restic-home-backup."{service,timer}
  rm -f "${SYSTEMD_DIR}/restic-home-prune."{service,timer}
  rm -f "${SYSTEMD_DIR}/restic-home-check."{service,timer}
  systemctl --user daemon-reload 2>/dev/null || true
  echo "✓ Units removed. Config files retained in ${CONFIG_DIR}"

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% 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 · scripts/install_userlevel_restic.sh (reported line 82)May include surrounding context.

sh
restic-home-check.timer 2>/dev/null || true
  rm -f "${SYSTEMD_DIR}/restic-home-backup."{service,timer}
  rm -f "${SYSTEMD_DIR}/restic-home-prune."{service,timer}
  rm -f "${SYSTEMD_DIR}/restic-home-check."{service,timer}
  systemctl --user daemon-reload 2>/dev/null || true
  echo "✓ Units removed. Config files retained in ${CONFIG_DIR}"
  echo "  To fully remove: rm -rf ${CONFIG_DIR} ${LOG_DIR} ${BIN_DIR}/restic-home-*.sh"

Chaining Abuse

High
Category
Tool Misuse
Confidence
75% confidence
Finding

Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Content

Scanner excerpt · scripts/install_userlevel_restic.sh (reported line 208)May include surrounding context.

sh
pass "Expected failure: unreadable env file correctly rejected"
  echo "    Corrective: chmod 600 ${ENV_FILE} && chown root:root ${ENV_FILE}"
fi
chmod 644 "${NOREAD_ENV}" 2>/dev/null; rm -f "${NOREAD_ENV}"

# ─── Summary ──────────────────────────────────────────────────────────────────
section "Validation Summary"

Chaining Abuse

High
Category
Tool Misuse
Confidence
75% confidence
Finding

Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Content

Scanner excerpt · scripts/validate_restic_setup.sh (reported line 145)May include surrounding context.

sh
pass "Expected failure: unreadable env file correctly rejected"
  echo "    Corrective: chmod 600 ${ENV_FILE} && chown root:root ${ENV_FILE}"
fi
chmod 644 "${NOREAD_ENV}" 2>/dev/null; rm -f "${NOREAD_ENV}"

# ─── Summary ──────────────────────────────────────────────────────────────────
section "Validation Summary"

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill explicitly instructs users to run multiple shell scripts, including privileged commands, but the metadata declares no tool scope or allowed-tools restrictions. This creates an authorization and review gap: an agent or operator may treat the skill as less capable than it really is, increasing the chance of unintended command execution or unsafe automation.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% 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 42)May include surrounding context.

md
- Never print secrets or tokens in chat, log output, or scripts.
  - Never delete snapshots or repositories without explicit user confirmation.
  - Never weaken permissions on credential files (0600 minimum).
  - Never claim backup success without checking exit status and snapshot listing.
  - Default to PLAN-ONLY mode; require explicit `--apply` for system changes.
  - No snapshot deletion during initial engagement; use `--dry-run-prune` to preview.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
90% confidence
Finding

The skill instructs users to execute a local script with sudo, which grants full root privileges to whatever the script contains. In skill ecosystems, this is dangerous because the documentation may normalize privileged execution before the script has been independently reviewed, allowing a compromised or modified skill to make system-wide changes, persist services, or exfiltrate secrets.

Content

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

3) Apply system changes

bash
sudo bash scripts/bootstrap_restic_home.sh \
  --user alice \
  --repo "sftp:backupsvc@10.50.8.24:/srv/backups/home/devbox17" \
  --hostname devbox17 \

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
86% confidence
Finding

The skill recommends running a validation script with sudo, again asking users to trust and execute repository-provided code as root. Even though the stated purpose is testing backup integrity, a malicious or tampered validation script could access sensitive files, alter the system, or leak credentials under full privileges.

Content

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

5) End-to-end validation

bash
sudo bash scripts/validate_restic_setup.sh

Runs:

Session Persistence

Medium
Category
Rogue Agent
Confidence
80% 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 · _meta.json (reported line 6)May include surrounding context.

json
"slug": "restic-home-backup",
  "version": "2.0.0",
  "publishedAt": 1771188538209,
  "description": "Production-grade encrypted restic home backup with systemd timers, retry logic, user-level installs, end-to-end validation, and multi-host rollout support.",
  "keywords": ["restic", "backup", "systemd", "linux", "home", "sftp", "encryption"],
  "scripts": {
    "bootstrap": "scripts/bootstrap_restic_home.sh",

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 · references/ops-checklist.md (reported line 46)May include surrounding context.

md
### Env file unreadable
- Pattern: `permission denied` mentioning env or password path
- Fix: `chmod 600 /etc/home-backup/env /etc/home-backup/password && chown root:root ...`

### DST / time not found (legacy cron only — does not apply to systemd timers)
- Symptom: job skipped on day of spring-forward (e.g., 2026-03-08)

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

Multiple sections specify schedules in America/Los_Angeles, and later installation examples pass --timezone "America/Los_Angeles" as the assumed setting. This is a natural-language locale policy issue because the document effectively forces a specific locale/timezone rather than presenting it as a configurable operator choice or clearly justifying a region-specific constraint.

Content

No source excerpt is available for this finding.

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/runbook.md (reported line 275)May include surrounding context.

--apply --init-repo --enable-timers --run-initial-backup

Enable linger so timers fire without login (one-time, needs sudo):

sudo loginctl enable-linger bob

text

### List timers:

Session Persistence

Medium
Category
Rogue Agent
Confidence
80% 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/runbook.md (reported line 322)May include surrounding context.

Edit the OnCalendar line:

systemctl edit --full restic-home-audit.timer

Then reload:

systemctl daemon-reload && systemctl enable --now restic-home-audit.timer

text

### Run drill immediately (without waiting):

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

sh
exit 0
fi

# ─── Apply guard: must run as root ────────────────────────────────────────────
if [[ "$(id -u)" != "0" ]]; then
  echo "ERROR: --apply requires root." >&2
  exit 2

Session Persistence

Medium
Category
Rogue Agent
Confidence
85% 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 · scripts/bootstrap_restic_home.sh (reported line 645)May include surrounding context.

sh
echo "[6/9] Legacy cron archival..."
if [[ "$ARCHIVE_LEGACY_CRON" == "yes" ]]; then
  ARCHIVE_FILE="${CONFIG_DIR}/legacy-crontab-$(date +%Y%m%d-%H%M%S).txt"
  if crontab -l >/dev/null 2>&1; then
    crontab -l > "${ARCHIVE_FILE}" 2>/dev/null || true
    chmod 600 "${ARCHIVE_FILE}"
    echo "      ✓ Archived root crontab → ${ARCHIVE_FILE}"

Session Persistence

Medium
Category
Rogue Agent
Confidence
85% 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 · scripts/bootstrap_restic_home.sh (reported line 646)May include surrounding context.

sh
echo "[6/9] Legacy cron archival..."
if [[ "$ARCHIVE_LEGACY_CRON" == "yes" ]]; then
  ARCHIVE_FILE="${CONFIG_DIR}/legacy-crontab-$(date +%Y%m%d-%H%M%S).txt"
  if crontab -l >/dev/null 2>&1; then
    crontab -l > "${ARCHIVE_FILE}" 2>/dev/null || true
    chmod 600 "${ARCHIVE_FILE}"
    echo "      ✓ Archived root crontab → ${ARCHIVE_FILE}"

Session Persistence

Medium
Category
Rogue Agent
Confidence
86% confidence
Finding

The script reconstructs and reinstalls root's crontab using shell text processing and echo "${CLEANED}" | crontab -. If the grep filter removes all lines or mishandles formatting, it can unintentionally wipe or corrupt root's crontab, disabling unrelated administrative or security jobs and causing denial of service for scheduled tasks.

Content

Scanner excerpt · scripts/bootstrap_restic_home.sh (reported line 650)May include surrounding context.

sh
chmod 600 "${ARCHIVE_FILE}"
    echo "      ✓ Archived root crontab → ${ARCHIVE_FILE}"
    # Remove the legacy home-backup entry
    CLEANED=$(crontab -l 2>/dev/null | grep -v '/usr/local/bin/home-backup' || true)
    echo "${CLEANED}" | crontab -
    echo "      ✓ Removed legacy '/usr/local/bin/home-backup' entry"
  else

Session Persistence

Medium
Category
Rogue Agent
Confidence
80% 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 · scripts/bootstrap_restic_home.sh (reported line 663)May include surrounding context.

sh
# ─── 7. Enable timers ─────────────────────────────────────────────────────────
echo "[7/9] Enabling systemd timers..."
if [[ "$ENABLE_TIMERS" == "yes" ]]; then
  systemctl enable --now \
    restic-home-backup.timer \
    restic-home-prune.timer \
    restic-home-check.timer \

Session Persistence

Medium
Category
Rogue Agent
Confidence
80% 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 · scripts/install_userlevel_restic.sh (reported line 120)May include surrounding context.

sh
Retention         : ${KEEP_DAILY}d / ${KEEP_WEEKLY}w / ${KEEP_MONTHLY}m

User systemd timers (require: loginctl enable-linger ${USER_NAME})
  Daily backup    : *-*-* 04:15:00 ${TIMEZONE}  + up to 10 min jitter
  Weekly prune    : Sat *-*-* 05:10:00 ${TIMEZONE}
  Monthly check   : *-*-02 06:20:00 ${TIMEZONE}

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

sh
# ─── Secrets ──────────────────────────────────────────────────────────────────
mkdir -p "${CONFIG_DIR}"
chmod 700 "${CONFIG_DIR}"

if [[ ! -s "${PASS_FILE}" ]]; then
  if command -v openssl >/dev/null 2>&1; then

Static analysis

No suspicious patterns detected.