Back to skill

Security audit

Canary Deploy

Security checks for vulnerabilities and agentic risk

Overview

The skill is meant to make risky system changes safer, but its rollback and command wrapper can affect privileged system files in unsafe, under-scoped ways.

Review this skill carefully before installing. It should only be used by a trusted operator on systems where they understand the sudo impact, and it should not be treated as reliable protection against remote lockout. Do not run rollback unless the backup directory and path metadata are trusted, and avoid feeding generated, remote, or partially trusted text into the command or validation arguments.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (2)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/canary-test.sh:141
Finding
Privileged Arbitrary File Overwrite Through Predictable Temporary Storage<![CDATA[ ## Vulnerability Details **File Location**: `scripts/canary-test.sh:14-20, 141-147`; `scripts/critical-update.sh:11-12, 39, 53-56` **Vulnerability Type**: Predictable temporary directory, untrusted rollback metadata, and privileged file overwrite **Risk Level**: High ### Vulnerable Code ```bash CANARY_DIR="${CANARY_DIR:-/tmp/canary-deploy}" BASELINE_FILE="$CANARY_DIR/baseline.json" BACKUP_DIR="$CANARY_DIR/backups" ACTION="${1:-help}" mkdir -p "$CANARY_DIR" "$BACKUP_DIR" ``` ```bash if [ -d "$BACKUP_DIR" ] && [ "$(ls -A "$BACKUP_DIR" 2>/dev/null)" ]; then for f in "$BACKUP_DIR"/*; do ORIGINAL=$(cat "$f.path" 2>/dev/null || echo "") if [ -n "$ORIGINAL" ] && [ -f "$f" ]; then sudo cp "$f" "$ORIGINAL" echo " ✅ Restored: $ORIGINAL" fi done ``` The corresponding backup creation logic is: ```bash CANARY_DIR="${CANARY_DIR:-/tmp/canary-deploy}" BACKUP_DIR="$CANARY_DIR/backups" mkdir -p "$CANARY_DIR" "$BACKUP_DIR" for f in "${BACKUP_FILES[@]}"; do if [ -f "$f" ]; then SAFE_NAME=$(echo "$f" | tr '/' '_') cp "$f" "$BACKUP_DIR/$SAFE_NAME" echo "$f" > "$BACKUP_DIR/$SAFE_NAME.path" echo " ✅ Backed up: $f" else echo " ⚠️ File not found: $f" fi done ``` ### Technical Analysis The scripts use the fixed, globally predictable path `/tmp/canary-deploy` for backup data and destination metadata. They create this path with `mkdir -p` but do not verify: - Whether the directory existed before execution. - Whether it is owned by the current trusted user. - Whether its permissions prevent modification by other local users. - Whether any component is a symbolic link. - Whether backup files and `.path` metadata are regular, trusted files. - Whether a rollback destination belongs to the set of files backed up during the current operation. Rollback treats the contents of `"$f.path"` as an authoritative destination and passes that value to `sudo cp`. This creates ...[truncated 2289 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the predictable directory with a private directory created using `mktemp -d`: ```bash CANARY_DIR="$(mktemp -d "${TMPDIR:-/tmp}/canary-deploy.XXXXXXXX")" chmod 700 "$CANARY_DIR" ``` 2. If rollback state must survive between invocations, use a dedicated state directory owned by the trusted operator, such as a directory under `/var/lib` or `$XDG_STATE_HOME`, and verify: - Expected owner UID. - Mode `0700`. - No symbolic links in any path component. - The directory is not group- or world-writable. 3. Reject pre-existing storage whose ownership or permissions are unsafe: ```bash [ "$(stat -c '%u' "$CANARY_DIR")" -eq "$(id -u)" ] || exit 1 [ "$(stat -c '%a' "$CANARY_DIR")" = "700" ] || exit 1 ``` 4. Do not trust a standalone `.path` file to select an unrestricted privileged destination. Maintain an authenticated manifest created during the current transaction and only restore destinations explicitly included in that manifest. 5. Canonicalize and validate every destination with `realpath` before restoration. Reject destinations outside an explicit allowlist established from the original `--backup` arguments. 6. Open files defensively and reject symbolic links. Use checks such as `test -f`, `test ! -L`, owner validation, and secure file descriptors where practical. 7. Avoid invoking `sudo` internally. Require the complete script to run under a clearly documented privilege model, or use a narrowly scoped privileged helper that only restores previously registered files. 8. Give each update transaction a unique backup directory to prevent stale or attacker-injected files from being included in a later rollback. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/critical-update.sh:79
Finding
Arbitrary Shell Command Execution Through eval-Based Command Processing<![CDATA[ ## Vulnerability Details **File Location**: `scripts/critical-update.sh:24-29, 79-86, 106-116` **Vulnerability Type**: Shell command injection through `eval` **Risk Level**: Medium ### Vulnerable Code ```bash while [[ $# -gt 0 ]]; do case $1 in --name) NAME="$2"; shift 2;; --backup) BACKUP_FILES+=("$2"); shift 2;; --command) COMMAND="$2"; shift 2;; --validate) VALIDATE_CMD="$2"; shift 2;; --dry-run) DRY_RUN=true; shift;; *) echo "Unknown option: $1"; exit 1;; esac done ``` ```bash echo "🏃 Step 3: Applying change..." echo " Command: $COMMAND" if eval "$COMMAND"; then echo " ✅ Command executed successfully" else echo " ❌ Command FAILED (exit code $?)" echo " ⏪ Auto-rolling back..." bash "$SCRIPT_DIR/canary-test.sh" rollback exit 1 fi ``` ```bash if [ -n "$VALIDATE_CMD" ]; then echo " Running custom validation: $VALIDATE_CMD" if eval "$VALIDATE_CMD"; then echo " ✅ Custom validation passed" else echo " ❌ Custom validation FAILED" echo " ⏪ Auto-rolling back..." bash "$SCRIPT_DIR/canary-test.sh" rollback echo " ❌ Change reverted. System restored to baseline." exit 1 fi fi ``` ### Technical Analysis The `--command` and `--validate` arguments are stored as strings and then passed to `eval`. The `eval` builtin reparses its argument as shell source code. Consequently, all shell syntax embedded in either value is active, including: - Command substitution. - Command chaining. - Redirection. - Pipelines. - Variable expansion. - Subshells. - Additional shell control operators. The interface intentionally accepts commands, so a fully trusted interactive caller already has the ability to execute commands. The security flaw arises when another application, automation system, AI-generated workflow, configuration value, or partially trusted user constructs either argument while assuming it represents a single comman ...[truncated 1925 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove both uses of `eval`. 2. Accept the change command as an argument array after a `--` separator and execute it without reparsing: ```bash command_args=("$@") "${command_args[@]}" ``` 3. Apply the same design to validation commands. If two commands are required, accept reviewed executable paths and separate argument arrays rather than shell source strings. 4. If complex shell syntax is genuinely required, require a separately stored script file that: - Is owned by a trusted user. - Is not group- or world-writable. - Has been reviewed before privileged execution. - Is invoked directly rather than through `eval`. 5. Do not construct command arguments by concatenating user-controlled strings. Preserve every argument as a distinct array element. 6. Document that all command inputs are security-sensitive executable content and must never originate from untrusted task names, remote requests, configuration fields, or generated text without explicit approval. 7. Run update and validation operations with the minimum required privileges. Use narrowly scoped `sudoers` rules for specific executables rather than granting unrestricted shell or command execution. 8. Consider defining supported critical changes as explicit subcommands with validated parameters instead of exposing a generic shell execution interface. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (9)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The skill markets itself as a safety mechanism for risky infrastructure changes, but the documented behavior appears to overclaim what it actually verifies and restores. That mismatch is dangerous because operators may rely on it to prevent lockout or enable rollback during SSH, firewall, or network changes when it may only capture local state and restore limited files, creating a false sense of safety during high-risk operations.

Chaining Abuse

High
Category
Tool Misuse
Content
bash scripts/critical-update.sh \
  --name "SSH hardening" \
  --backup "/etc/ssh/sshd_config" \
  --command "sudo sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config && sudo systemctl reload sshd" \
  --validate "ssh -o ConnectTimeout=5 localhost echo ok"
```
Confidence
84% confidence
Finding
The example chains multiple privileged operations with shell control operators inside a single command string. This increases blast radius and makes failures, quoting mistakes, and injection opportunities harder to reason about, especially if any part of the command is assembled dynamically by users or calling agents.

Intent-Code Divergence

High
Confidence
98% confidence
Finding
The script advertises rollback support and references backup/path metadata, but it never creates those backups or the corresponding .path files. In a tool intended to protect critical infrastructure changes, this creates a dangerous false sense of safety: operators may proceed with risky SSH, firewall, or network modifications believing recovery is available when it is not.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
bash scripts/canary-test.sh baseline

# Make your change
sudo nano /etc/ssh/sshd_config

# Validate change didn't break anything
bash scripts/canary-test.sh validate
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
bash scripts/canary-test.sh baseline

# Make your change
sudo nano /etc/ssh/sshd_config

# Validate change didn't break anything
bash scripts/canary-test.sh validate
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
bash scripts/critical-update.sh \
  --name "SSH hardening" \
  --backup "/etc/ssh/sshd_config" \
  --command "sudo sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config && sudo systemctl reload sshd" \
  --validate "ssh -o ConnectTimeout=5 localhost echo ok"
```
Confidence
82% confidence
Finding
The skill encourages passing a root-level shell command as a quoted --command argument, which is a dangerous execution pattern because it normalizes arbitrary privileged command strings inside an automation wrapper. If untrusted input reaches that argument or users copy-modify examples unsafely, it can result in unintended command execution as root and destructive system changes.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The skill claims to prevent lockouts by validating connectivity before and after changes, but it only tests localhost SSH and external DNS resolution. Those checks do not validate actual remote reachability from the operator's network path, so a change can still break inbound SSH/VPN access while the script reports success.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
for f in "$BACKUP_DIR"/*; do
                ORIGINAL=$(cat "$f.path" 2>/dev/null || echo "")
                if [ -n "$ORIGINAL" ] && [ -f "$f" ]; then
                    sudo cp "$f" "$ORIGINAL"
                    echo "  ✅ Restored: $ORIGINAL"
                fi
            done
Confidence
88% confidence
Finding
The script restores arbitrary backup files to paths read from sidecar metadata and performs the copy with sudo. Because the backup directory is under /tmp, a writable and commonly shared location, local tampering with backup contents or .path metadata could turn rollback into a privileged arbitrary file overwrite, potentially leading to system compromise or denial of service.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
Rollback copies files into privileged system locations via sudo without a confirmation prompt, dry-run, destination validation, or explicit warning about overwriting active configs. In a recovery script for critical systems, this increases the chance of accidental destructive changes or restoration of stale/untrusted content.

Static analysis

No suspicious patterns detected.