Back to skill

Security audit

Cloud Backup [S3, R2, B2, MinIO & more]

Security checks for vulnerabilities and agentic risk

Overview

This backup skill mostly matches its stated purpose, but it contains an under-disclosed plaintext bypass that can publish sensitive OpenClaw backups without encryption.

Review this skill before installing. Its backup and restore flows are mostly explicit and purpose-aligned, but do not rely on its stated guarantee that sensitive backups can never be plaintext until the --force-plaintext path is removed or blocked. Use only bucket-scoped credentials, keep passphrase files owner-only, avoid plaintext OpenClaw config secrets, and treat prune/retention as capable of deleting backup objects.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/cloud-backup.sh:747
Finding

Encryption Policy Bypass Allows Plaintext Secret-Bearing Backups

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/cloud-backup.sh:333
Finding

Group-Readable GPG Passphrase Files Are Accepted

Content
View full analysis
/dev/null || stat -f %Lp "$PASSFILE" 2>/dev/null || echo "")" if [ -n "$mode" ]; then perm=$(( 8#$mode )) if (( perm & 0007 )); then PASS_ERROR="passphrase file is world-readable — refusing. Fix: chmod 600 $PASSFILE" [ "${1:-}" = "soft" ] && return 1 fail "$E_PASSPHRASE" "$PASS_ERROR" elif (( perm & 0070 )); then warn "passphrase file $PASSFILE has mode $mode; expected 600" fi fi PASSPHRASE="$(cat "$PASSFILE")" ``` ### Technical Analysis The implementation rejects files with permissions granted to “other” users, but files accessible by the owning group only generate a warning. The script then reads and uses the passphrase normally. Consequently, modes such as `0640`, `0660`, or `0440` are accepted even though group members can read the encryption key. This conflicts with the project’s documented requirement that the passphrase file be mode `0600`. The passphrase protects all archives created with it. Access by one unintended local group member therefore compromises every retained local and remote backup encrypted under that passphrase. The implementation also does not verify that the passphrase file is owned by the effective user. Permission checks alone are insufficient if the file is owned or controlled by another account. ### Attack Path 1. The configured passphrase file has group-readable permissions, such as: ```bash chmod 0640 ~/.openclaw/credentials/cloud-backup.passphrase ``` 2. Another local user belongs to the file’s group. 3. The script warns about the mode but still reads and uses the file. 4. The other group member reads the same passphrase file. 5. The attacker obtains an encrypted archive from the local backup directory, the configured bucket, or an ...[truncated 637 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (40)

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SECURITY.md (reported line 10)May include surrounding context.

md
It does not protect against host compromise — a shell on the host already
reads `~/.openclaw` directly. Consequences:

- Host-side mode-600 secret files (`~/.aws/credentials`, the passphrase
  file) are acceptable storage.
- Secrets inside `openclaw.json` are not: **this skill archives that file**,
  so a credential stored there is replicated into every backup it protects —

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/credentials.md (reported line 12)May include surrounding context.

md
It does not protect against host compromise — a shell on the host already
reads `~/.openclaw` directly. Consequences:

- Host-side mode-600 secret files (`~/.aws/credentials`, the passphrase
  file) are acceptable storage.
- Secrets inside `openclaw.json` are not: **this skill archives that file**,
  so a credential stored there is replicated into every backup it protects —

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/credentials.md (reported line 26)May include surrounding context.

md
It does not protect against host compromise — a shell on the host already
reads `~/.openclaw` directly. Consequences:

- Host-side mode-600 secret files (`~/.aws/credentials`, the passphrase
  file) are acceptable storage.
- Secrets inside `openclaw.json` are not: **this skill archives that file**,
  so a credential stored there is replicated into every backup it protects —

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/credentials.md (reported line 113)May include surrounding context.

md
It does not protect against host compromise — a shell on the host already
reads `~/.openclaw` directly. Consequences:

- Host-side mode-600 secret files (`~/.aws/credentials`, the passphrase
  file) are acceptable storage.
- Secrets inside `openclaw.json` are not: **this skill archives that file**,
  so a credential stored there is replicated into every backup it protects —

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/providers/aws-s3.md (reported line 34)May include surrounding context.

md
It does not protect against host compromise — a shell on the host already
reads `~/.openclaw` directly. Consequences:

- Host-side mode-600 secret files (`~/.aws/credentials`, the passphrase
  file) are acceptable storage.
- Secrets inside `openclaw.json` are not: **this skill archives that file**,
  so a credential stored there is replicated into every backup it protects —

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/providers/backblaze-b2.md (reported line 20)May include surrounding context.

md
It does not protect against host compromise — a shell on the host already
reads `~/.openclaw` directly. Consequences:

- Host-side mode-600 secret files (`~/.aws/credentials`, the passphrase
  file) are acceptable storage.
- Secrets inside `openclaw.json` are not: **this skill archives that file**,
  so a credential stored there is replicated into every backup it protects —

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/providers/cloudflare-r2.md (reported line 21)May include surrounding context.

md
It does not protect against host compromise — a shell on the host already
reads `~/.openclaw` directly. Consequences:

- Host-side mode-600 secret files (`~/.aws/credentials`, the passphrase
  file) are acceptable storage.
- Secrets inside `openclaw.json` are not: **this skill archives that file**,
  so a credential stored there is replicated into every backup it protects —

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/providers/digitalocean-spaces.md (reported line 24)May include surrounding context.

md
It does not protect against host compromise — a shell on the host already
reads `~/.openclaw` directly. Consequences:

- Host-side mode-600 secret files (`~/.aws/credentials`, the passphrase
  file) are acceptable storage.
- Secrets inside `openclaw.json` are not: **this skill archives that file**,
  so a credential stored there is replicated into every backup it protects —

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/providers/minio.md (reported line 32)May include surrounding context.

md
It does not protect against host compromise — a shell on the host already
reads `~/.openclaw` directly. Consequences:

- Host-side mode-600 secret files (`~/.aws/credentials`, the passphrase
  file) are acceptable storage.
- Secrets inside `openclaw.json` are not: **this skill archives that file**,
  so a credential stored there is replicated into every backup it protects —

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/providers/other.md (reported line 28)May include surrounding context.

md
It does not protect against host compromise — a shell on the host already
reads `~/.openclaw` directly. Consequences:

- Host-side mode-600 secret files (`~/.aws/credentials`, the passphrase
  file) are acceptable storage.
- Secrets inside `openclaw.json` are not: **this skill archives that file**,
  so a credential stored there is replicated into every backup it protects —

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/security.md (reported line 12)May include surrounding context.

md
It does not protect against host compromise — a shell on the host already
reads `~/.openclaw` directly. Consequences:

- Host-side mode-600 secret files (`~/.aws/credentials`, the passphrase
  file) are acceptable storage.
- Secrets inside `openclaw.json` are not: **this skill archives that file**,
  so a credential stored there is replicated into every backup it protects —

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/setup-flow.md (reported line 31)May include surrounding context.

md
It does not protect against host compromise — a shell on the host already
reads `~/.openclaw` directly. Consequences:

- Host-side mode-600 secret files (`~/.aws/credentials`, the passphrase
  file) are acceptable storage.
- Secrets inside `openclaw.json` are not: **this skill archives that file**,
  so a credential stored there is replicated into every backup it protects —

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/cloud-backup.sh (reported line 1184)May include surrounding context.

sh
It does not protect against host compromise — a shell on the host already
reads `~/.openclaw` directly. Consequences:

- Host-side mode-600 secret files (`~/.aws/credentials`, the passphrase
  file) are acceptable storage.
- Secrets inside `openclaw.json` are not: **this skill archives that file**,
  so a credential stored there is replicated into every backup it protects —

Anti-Refusal Statement

High
Category
Anti-Refusal
Confidence
80% confidence
Finding

Skill instructs the agent to omit warnings, disclaimers, or ethical commentary. Stripping safety caveats hides risk from the user and is a common jailbreak preamble.

Content

Scanner excerpt · SECURITY.md (reported line 26)May include surrounding context.

md
|---|---|---|
| **SQP-1** — activation description broad enough to trigger on generic "backup"/"restore" phrases, on a skill that archives, uploads, mutates config, and schedules | `SKILL.md:3` — "Use when the user says 'backup' …" | Description names OpenClaw state + S3 cloud and requires explicit intent; SKILL.md adds a "When to use — and when not to" section, per-action confirmation gates (config writes, first upload, credential storage, restore, prune, scheduling), and an unattended-runs policy restricting cron payloads to `backup`/`prune` |
| **SQP-2 (cron)** — daily cron job created by default without user opt-in | `SKILL.md:61-75` — "This step should be executed by default unless user asked not to do it" | Scheduling is strictly opt-in: offered once, after the first successful manual backup, with the exact `openclaw cron add` command and full payload shown; never created by default; never re-offered after a decline; the `schedule` subcommand only prints |
| **SQP-2 (credentials)** — provider docs instructed storing long-lived access keys in plaintext OpenClaw config without warnings | `references/providers/aws-s3.md:59-61`, `backblaze-b2.md:28-29`, `digitalocean-spaces.md:27-28`, `cloudflare-r2.md:28-29`, `minio.md:37-38`, `other.md:27-28`, `scripts/cloud-backup.sh:43-47`, and `SKILL.md:33-35` even instructed the agent to write the GPG passphrase into config | All six provider docs lead with least-privilege bucket-scoped keys stored in AWS named profiles (run by the user, outside the chat); the passphrase lives in a chmod-600 file or an OpenClaw SecretRef (`apiKey` + `primaryEnv`); every doc carries an identical "Credential safety" warning block including the amplifier; plaintext config keys still resolve (lowest priority) but emit loud DEPRECATED warnings on every run and are removed in v3 |

Beyond the findings, v2 also fixes two security defects the scanners did not
see:

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/cloud-backup.sh (reported line 422)May include surrounding context.

sh
# --- staging / lock / sweep ------------------------------------------------------
STAGING=""
cleanup_staging() { [ -n "$STAGING" ] && rm -rf "$STAGING"; }

sweep_stale_staging() {
  local d pid

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/cloud-backup.sh (reported line 868)May include surrounding context.

sh
size_remote="$(jq -r '.ContentLength // 0' <<<"$head")"
    sha_remote="$(jq -r '.Metadata.sha256 // empty' <<<"$head")"
    if [ "$size_remote" != "$size_local" ] || { [ -n "$sha_remote" ] && [ "$sha_remote" != "$sha" ]; }; then
      s3 rm "s3://$BUCKET/$remote_key" >/dev/null 2>&1 || true
      fail "$E_REMOTE_VERIFY" "remote object mismatch (size $size_remote vs $size_local)"
    fi
  fi

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/cloud-backup.sh (reported line 993)May include surrounding context.

sh
local n=$(( ${#rk[@]} - KEEP )) i
    info "Remote retention: pruning $n $1 archive(s) (keep $KEEP)"
    for ((i = 0; i < n; i++)); do
      s3 rm "s3://$BUCKET/${rk[$i]}" >/dev/null
      s3 rm "s3://$BUCKET/${rk[$i]}.sha256" >/dev/null 2>&1 || true
    done
  fi

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/cloud-backup.sh (reported line 994)May include surrounding context.

sh
info "Remote retention: pruning $n $1 archive(s) (keep $KEEP)"
    for ((i = 0; i < n; i++)); do
      s3 rm "s3://$BUCKET/${rk[$i]}" >/dev/null
      s3 rm "s3://$BUCKET/${rk[$i]}.sha256" >/dev/null 2>&1 || true
    done
  fi

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/cloud-backup.sh (reported line 1007)May include surrounding context.

sh
for key in "${rk[@]}"; do
      ts="$(arc_ts "$key")"; [ -n "$ts" ] || continue
      if [ "$ts" -lt "$cutoff" ]; then
        s3 rm "s3://$BUCKET/$key" >/dev/null
        s3 rm "s3://$BUCKET/$key.sha256" >/dev/null 2>&1 || true
      fi
    done

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/cloud-backup.sh (reported line 1008)May include surrounding context.

sh
ts="$(arc_ts "$key")"; [ -n "$ts" ] || continue
      if [ "$ts" -lt "$cutoff" ]; then
        s3 rm "s3://$BUCKET/$key" >/dev/null
        s3 rm "s3://$BUCKET/$key.sha256" >/dev/null 2>&1 || true
      fi
    done
  fi

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill invokes shell commands (bash ..., aws, gpg) but does not declare an explicit tool scope such as permissions or allowed-tools. That means an agent/runtime may permit broader command execution than intended or fail to constrain this skill to its minimal required capabilities, increasing the chance of misuse or unsafe invocation in a sensitive backup/restore workflow.

Content

No source excerpt is available for this finding.

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

md
| Secret | Home | How |
|---|---|---|
| S3 key pair | AWS named profile (`~/.aws/credentials`) | `aws configure --profile openclaw-backup && chmod 600 ~/.aws/credentials`, then set `config.profile` |
| GPG passphrase | passphrase file | `umask 077 && openssl rand -base64 32 > ~/.openclaw/credentials/cloud-backup.passphrase`, then set `config.passphraseFile` |

## Resolution order (what the script actually does)

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/cloud-backup.sh (reported line 338)May include surrounding context.

sh
| Secret | Home | How |
|---|---|---|
| S3 key pair | AWS named profile (`~/.aws/credentials`) | `aws configure --profile openclaw-backup && chmod 600 ~/.aws/credentials`, then set `config.profile` |
| GPG passphrase | passphrase file | `umask 077 && openssl rand -base64 32 > ~/.openclaw/credentials/cloud-backup.passphrase`, then set `config.passphraseFile` |

## Resolution order (what the script actually does)

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/cloud-backup.sh (reported line 1184)May include surrounding context.

sh
| Secret | Home | How |
|---|---|---|
| S3 key pair | AWS named profile (`~/.aws/credentials`) | `aws configure --profile openclaw-backup && chmod 600 ~/.aws/credentials`, then set `config.profile` |
| GPG passphrase | passphrase file | `umask 077 && openssl rand -base64 32 > ~/.openclaw/credentials/cloud-backup.passphrase`, then set `config.passphraseFile` |

## Resolution order (what the script actually does)

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
70% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · references/credentials.md (reported line 45)May include surrounding context.

md
3. **OpenClaw secret ref** — `config.passphraseRef` (below). Works from any
   shell; aborts with exit 14 if configured but unresolvable.
4. `config.passphraseFile` — path to a mode-600 file. **Recommended simple
   default.** The script refuses world-readable files and warns on group
   access. The passphrase is passed to gpg over a file descriptor — never on
   a command line (v1 leaked it into `ps`/`/proc/*/cmdline`).
5. DEPRECATED: `skills.entries.cloud-backup.env.GPG_PASSPHRASE` plaintext in

Static analysis

No suspicious patterns detected.