Back to skill

Security audit

Synology Backup

Security checks for vulnerabilities and agentic risk

Overview

This backup skill mostly matches its purpose, but it can copy secrets to the NAS outside the documented opt-in boundary and can follow symlinks out of approved folders.

Review and harden this skill before installing. Remove rsync --copy-links or enforce canonical symlink containment, and change restore.sh so .env is copied only with explicit opt-in and restrictive permissions. Use a dedicated low-privilege NAS user, restrict and encrypt the backup share, run dry-run first, and review cron settings before enabling automated backups.

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/restore.sh:78
Finding
Restore Safety Snapshot Copies API Secrets Without Explicit Opt-In<![CDATA[ ## Vulnerability Details **File Location**: `scripts/restore.sh:78-82` **Vulnerability Type**: Secret exposure caused by violation of the documented opt-in boundary **Risk Level**: High ### Vulnerable Code ```bash for src_file in openclaw.json .env; do if [[ -f "$HOME/.openclaw/${src_file}" ]]; then cp -- "$HOME/.openclaw/${src_file}" "${PRE_SNAP}/${src_file}" echo " saved: $src_file" fi done ``` ### Technical Analysis The restore workflow unconditionally includes `$HOME/.openclaw/.env` in the pre-restore safety snapshot whenever that file exists. This behavior does not check whether `.env` was explicitly included in the configured `backupPaths`. This conflicts with the documented security boundary in `SKILL.md`, which states that `.env` contains API keys, is excluded by default, and must be backed up only through an explicit opt-in. Running a restore therefore causes a secret-bearing file to be copied to the backup destination even when the user deliberately omitted it from normal backups. For SMB operation, `PRE_SNAP` is located below the mounted NAS backup directory. The copied `.env` can consequently enter NAS snapshots, replication systems, external backup media, or retention processes. The copy also preserves no explicit restrictive destination mode. ### Attack Path 1. The user keeps API keys in `$HOME/.openclaw/.env`. 2. The user does not add `.env` to `backupPaths`, relying on the documented default exclusion. 3. An SMB backup share is mounted and contains a snapshot eligible for restoration. 4. The user invokes `restore.sh` and confirms the restore. 5. The script creates a pre-restore safety snapshot on the NAS. 6. The script copies the live `.env` into that snapshot without a separate warning or opt-in check. 7. A NAS user, compromised NAS account, replication target, or other principal with snapshot access obtains the API keys. ### Impact Assessment This issue can disclose every secret stored in `.env`, ...[truncated 542 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Include `.env` in a safety snapshot only if its normalized path is explicitly present in `backupPaths`. 2. Add a dedicated configuration option such as `includeSecretsInSafetySnapshots`, defaulting to `false`. 3. Before copying `.env`, display a separate warning identifying the destination and require explicit confirmation. 4. Create secret-bearing destination files with restrictive permissions, such as mode `0600`, where the destination filesystem supports Unix permissions. 5. Document how NAS snapshots, replication, encryption at rest, and retention apply to secret-bearing backups. 6. Consider excluding `.env` from automated safety snapshots entirely and instead instruct users to recover API keys from a dedicated secrets manager. Example hardened logic: ```bash include_env=false while IFS= read -r configured_path; do expanded_path="${configured_path/#\~/$HOME}" if [[ "$expanded_path" == "$HOME/.openclaw/.env" ]]; then include_env=true break fi done < <(jq -r '.backupPaths[]' "$CONFIG") if [[ -f "$HOME/.openclaw/openclaw.json" ]]; then cp -- "$HOME/.openclaw/openclaw.json" "$PRE_SNAP/openclaw.json" fi if [[ "$include_env" == "true" && -f "$HOME/.openclaw/.env" ]]; then install -m 600 -- "$HOME/.openclaw/.env" "$PRE_SNAP/.env" fi ``` ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/backup.sh:101
Finding
Symlink Dereferencing Allows Backup Paths to Escape Approved Roots<![CDATA[ ## Vulnerability Details **File Locations**: `scripts/backup.sh:101-109`, `scripts/backup.sh:159-178`, and `scripts/lib.sh:255-269` **Vulnerability Type**: Out-of-scope file disclosure through unsafe symlink dereferencing **Risk Level**: High ### Vulnerable Code The directory backup helper dereferences symlinks for both SSH and SMB destinations: ```bash if [[ "$TRANSPORT" == "ssh" ]]; then rsync -a --copy-links --delete \ -e "ssh -p ${SSH_PORT} -o BatchMode=yes -o StrictHostKeyChecking=yes" \ "${EXCLUDE_ARGS[@]}" -- \ "$src" "$(remote_path "$dest")" || rc=$? else rsync -a --copy-links --delete \ "${EXCLUDE_ARGS[@]}" -- \ "$src" "$dest" || rc=$? fi ``` Single-file backups also dereference links: ```bash # Single file — use cp for local, rsync for SSH if [[ "$TRANSPORT" == "ssh" ]]; then if rsync -a --copy-links \ -e "ssh -p ${SSH_PORT} -o BatchMode=yes -o StrictHostKeyChecking=yes" \ -- "$path" "$(remote_path "backups/$TIMESTAMP/$name")" 2>/dev/null; then echo "✓ $name" (( backed_up++ )) || true else echo "❌ Failed to copy file: $name" >&2 (( failed++ )) || true failed_paths+=("$name") fi else if rsync -a --copy-links \ -- "$path" "${SNAP_DIR}/${name}" 2>/dev/null; then echo "✓ $name" (( backed_up++ )) || true else echo "❌ Failed to copy file: $name" >&2 (( failed++ )) || true failed_paths+=("$name") fi fi ``` The shared rsync helper repeats the same behavior: ```bash rsync_to_dest() { local src="$1" local dest_subpath="$2" local -a exclude_args mapfile -t exclude_args < <(build_exclude_args) if [[ "$TRANSPORT" == "ssh" ]]; then rsync -a --copy-links --delete -e "ssh -p ${SSH_PORT} -o BatchMode=yes -o StrictHostKeyChecking=yes" \ "${exclude_args[@]}" -- \ "$src" "$(remote_path "$dest_subpath")" else rsync - ...[truncated 2661 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `--copy-links` from all rsync invocations. Archive mode already preserves symbolic links as links by default. 2. If following selected symlinks is an essential feature, make it disabled by default and require an explicit configuration option. 3. Before dereferencing any symlink, resolve it with `realpath` and verify that the resolved target remains below an approved canonical backup root. 4. Reject links whose targets do not exist, cannot be canonicalized, or point to known credential locations. 5. Apply the same canonical-path policy to explicitly configured single-file backup paths. 6. Add automated tests covering: - Relative symlinks that remain inside the backup root - Absolute symlinks outside the root - Chained symlinks - Links to `.env`, `.ssh`, and cloud credential directories - Symlink replacement during backup 7. Run backups under a dedicated account that cannot read unrelated user credentials where operationally possible. The preferred safe rsync form is: ```bash if [[ "$TRANSPORT" == "ssh" ]]; then rsync -a --delete \ -e "ssh -p ${SSH_PORT} -o BatchMode=yes -o StrictHostKeyChecking=yes" \ "${EXCLUDE_ARGS[@]}" -- \ "$src" "$(remote_path "$dest")" else rsync -a --delete \ "${EXCLUDE_ARGS[@]}" -- \ "$src" "$dest" fi ``` If links must be followed, canonical target enforcement should occur before transfer and should fail closed whenever containment cannot be proven. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
Findings (21)

Credential Access

High
Category
Privilege Escalation
Content
**SSH transport (recommended):** Set `"transport": "ssh"` and add `"sshUser": "your-user"`. No credentials file needed — uses SSH key auth. Requires rsync + SSH access to the Synology.

> ⚠️ **SSH host key warning:** Scripts use `StrictHostKeyChecking=yes`. Add your NAS host key to `~/.ssh/known_hosts` first by connecting manually once (`ssh user@nas-ip`) before automation.

**Sensitive files:** The `.env` file (containing API keys) is **excluded by default**. Only add it to `backupPaths` if your NAS share is restricted to a dedicated low-privilege user and encrypted at rest. When in doubt, leave it out — you can always re-enter API keys from scratch.
Confidence
90% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
**SSH transport (recommended):** Set `"transport": "ssh"` and add `"sshUser": "your-user"`. No credentials file needed — uses SSH key auth. Requires rsync + SSH access to the Synology.

> ⚠️ **SSH host key warning:** Scripts use `StrictHostKeyChecking=yes`. Add your NAS host key to `~/.ssh/known_hosts` first by connecting manually once (`ssh user@nas-ip`) before automation.

**Sensitive files:** The `.env` file (containing API keys) is **excluded by default**. Only add it to `backupPaths` if your NAS share is restricted to a dedicated low-privilege user and encrypted at rest. When in doubt, leave it out — you can always re-enter API keys from scratch.
Confidence
90% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Ae1

High
Category
analysis-evasion
Content
scripts/backup.sh
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
scripts/backup.sh
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
scripts/backup.sh
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Tool Parameter Abuse

High
Category
Tool Misuse
Content
send_telegram "⚠️ Synology backup FAILED on $(hostname) — snapshot dir not writable: $SNAP_DIR"
        exit 1
    fi
    rm -f -- "${SNAP_DIR}/.ping"
fi

# ---------------------------------------------------------------------------
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).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
fi

            # Health check: verify the NAS is actually responsive
            if touch "$MOUNT/.ping" 2>/dev/null && rm -f "$MOUNT/.ping" 2>/dev/null; then
                echo "Mount health check passed"
                return 0
            else
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).

Chaining Abuse

High
Category
Tool Misuse
Content
fi

            # Health check: verify the NAS is actually responsive
            if touch "$MOUNT/.ping" 2>/dev/null && rm -f "$MOUNT/.ping" 2>/dev/null; then
                echo "Mount health check passed"
                return 0
            else
Confidence
75% confidence
Finding
Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Self-Modification

High
Category
Rogue Agent
Content
exit 1
fi

echo "⚠️  This will overwrite current files with snapshot from $DATE"
echo "   Source: $SNAP_DIR"
echo ""
read -r -p "Continue? [y/N] " confirm
Confidence
85% confidence
Finding
Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The README promotes restore capability as 'safe' but does not prominently warn that a restore can overwrite the current workspace, configuration, and agent data. Even with pre-restore snapshots, users may trigger destructive replacement without understanding the operational risk, leading to accidental data loss or rollback to stale state.

Session Persistence

Medium
Category
Rogue Agent
Content
## Quick Setup

1. Install dependencies: `apt-get install -y cifs-utils rsync`
2. Create a dedicated Synology user with access to one share only
3. Create credentials file: `touch ~/.openclaw/.smb-credentials && chmod 600 ~/.openclaw/.smb-credentials`
4. Create config at `~/.openclaw/synology-backup.json` (see SKILL.md for full reference)
5. Test: `bash scripts/backup.sh --dry-run`
Confidence
60% 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.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
- rsync
        - jq
        - cifs-utils
      notes: "SSH transport requires SSH key auth to Synology. SMB transport requires cifs-utils and a chmod 600 credentials file. Cron/session layer should own notifications explicitly."
---

# Synology Backup
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
- rsync
        - jq
        - cifs-utils
      notes: "SSH transport requires SSH key auth to Synology. SMB transport requires cifs-utils and a chmod 600 credentials file. Cron/session layer should own notifications explicitly."
---

# Synology Backup
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
- rsync
        - jq
        - cifs-utils
      notes: "SSH transport requires SSH key auth to Synology. SMB transport requires cifs-utils and a chmod 600 credentials file. Cron/session layer should own notifications explicitly."
---

# Synology Backup
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
- rsync
        - jq
        - cifs-utils
      notes: "SSH transport requires SSH key auth to Synology. SMB transport requires cifs-utils and a chmod 600 credentials file. Cron/session layer should own notifications explicitly."
---

# Synology Backup
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
- rsync
        - jq
        - cifs-utils
      notes: "SSH transport requires SSH key auth to Synology. SMB transport requires cifs-utils and a chmod 600 credentials file. Cron/session layer should own notifications explicitly."
---

# Synology Backup
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Session Persistence

Medium
Category
Rogue Agent
Content
### 2. Synology Preparation

1. Create a dedicated user on the Synology (e.g., `openclaw-backup`) with minimal permissions
2. Create or choose a shared folder (e.g., `backups`)
3. Grant the user read/write access to **only** that folder — not admin access
Confidence
60% 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.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
```bash
touch ~/.openclaw/.smb-credentials
chmod 600 ~/.openclaw/.smb-credentials
# Add two lines:
# username=<your-synology-user>
# password=<your-synology-password>
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Missing User Warnings

Low
Confidence
82% confidence
Finding
The cron setup example enables unattended recurring backup and verification, which results in regular automated transfer of workspace and agent data to the NAS. Without an explicit warning, users may not realize they are establishing persistent scheduled exfiltration of potentially sensitive data beyond the local host.

Intent-Code Divergence

Low
Confidence
77% confidence
Finding
The security notes assert that all config values are validated before use and that restore is constrained by an explicit allowlist. In the provided file, those are intent-level guarantees rather than demonstrated behavior, so the documentation overclaims safety properties the reader cannot verify here.

Intent-Code Divergence

Low
Confidence
85% confidence
Finding
The comment says the function verifies the NAS is responsive 'with a write test' after a successful mount, implying a meaningful backup-target health validation. In practice, the code only does a simple touch/remove of .ping on the mounted path, which checks basic writability but not broader backup integrity or responsiveness semantics suggested by the comment.

Static analysis

No suspicious patterns detected.