Back to skill

Security audit

Workspace Git Backup

Security checks for vulnerabilities and agentic risk

Overview

This backup skill does what it says, but it installs recurring jobs that push broad local directory contents to a remote Git repository and has unsafe schedule handling.

Install only after choosing a narrow backup folder, reviewing it for secrets and private data, adding exclusions such as .gitignore, confirming the exact private remote repository, and understanding that cron or launchd will keep pushing changes on a schedule. Avoid using editable or untrusted schedule values until validation is added.

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/install-cron.sh:16
Finding

Persistent command injection through an unvalidated cron schedule

Content
View full analysis
/dev/null | grep -v "github-backup.sh") | crontab - # Add the new entry (crontab -l 2>/dev/null; echo "$SCHEDULE $BACKUP_SCRIPT >> $LOG_FILE 2>&1") | crontab - echo "cron task installed: $SCHEDULE" ``` ### Technical Analysis The `schedule` property is read from `.backup-config.json` using `grep` and `sed`, then inserted directly at the beginning of a crontab entry. The installer does not verify that the value contains exactly five valid cron timing fields. A crontab entry treats everything after the five schedule fields as the command to execute. Consequently, a value containing five timing fields followed by an attacker-selected command changes the effective command registered by the installer. For example, a schedule conceptually equivalent to the following would cause the injected command to become the cron command: ```text * * * * * attacker-command # ``` The fixed backup script path appended by the installer would be commented out. This is not shell evaluation during installation; it is injection into the syntax of the generated crontab, which cron subsequently interprets and executes. Exploitation requires an attacker to modify the configuration file or induce the user or Agent to create a malicious `schedule` value and then run the documented installer. ### Attack Path 1. The attacker gains influence over `~/.openclaw/workspace/.backup-config.json`, such as through a malicious workspace file, repository content, or deceptive setup instructions. 2. The attacker sets `schedule` to five valid cron fields followed by an arbitrary shell command and a comment marker. 3. The user invokes `scrip ...[truncated 819 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/install-launchd.sh:16
Finding

Launchd plist injection through unescaped schedule fields

Content
View full analysis
" IFS=',' read -ra HOUR_ARRAY <<< "$HOURS" for HOUR in "${HOUR_ARRAY[@]}"; do INTERVAL+=" Hour $HOUR Minute $MINUTE " done INTERVAL+=" " ``` The resulting unescaped content is inserted into a plist and loaded: ```bash cat > "$PLIST" << EOF Label com.openclaw.github-backup ProgramArguments /bin/bash $BACKUP_SCRIPT StartCalendarInterval $INTERVAL StandardOutPath $LOG_FILE StandardErrorPath $LOG_FILE RunAtLoad EOF launchctl unload "$PLIST" 2>/dev/null || true launchctl load "$PLIST" ``` ### Technical Analysis The installer extracts the first two whitespace-delimited schedule fields and interpolates them directly into XML `` elements. It does not: - Verify that the minute is an integer from 0 through 59. - Verify that each hour is an integer from 0 through 23. - Reject XML metacharacters. - Escape configuration values before embedding them in XML. - Validate the finished plist before loading it. A crafted value containing c ...[truncated 1650 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/install-cron.sh:20
Finding

Unscoped cron cleanup can delete unrelated scheduled jobs

Content
View full analysis
/dev/null | grep -v "github-backup.sh") | crontab - ``` During uninstallation: ```bash if crontab -l 2>/dev/null | grep -q "github-backup.sh"; then (crontab -l 2>/dev/null | grep -v "github-backup.sh") | crontab - info "Removed cron task" else warn "Cron task does not exist" fi ``` ### Technical Analysis The Skill identifies its cron entry using an unanchored substring search for `github-backup.sh`. It does not require the exact installed path, an exact command, or a unique ownership marker. As a result, every line in the user's crontab containing that substring is removed. This can affect unrelated jobs whose script name, argument, comment, log path, or command text happens to include `github-backup.sh`. The behavior occurs both when installing a replacement entry and when uninstalling the Skill, so even an installation operation can silently remove another scheduled task. ### Attack Path 1. The user already has an unrelated crontab entry containing the text `github-backup.sh`, or an attacker causes such an entry to exist. 2. The user runs `scripts/install-cron.sh` or `scripts/manage.sh uninstall`. 3. `grep -v "github-backup.sh"` removes every matching line. 4. The filtered crontab replaces the user's original crontab. 5. The unrelated scheduled job is permanently removed unless restored from another source. ### Impact Assessment The issue can disable unrelated user-level scheduled jobs, including maintenance, monitoring, synchronization, or backup tasks. The principal impact is availability and configuration integrity. The operation only modifies the invoking user's crontab and does not directly affect system-wide cron configuration or grant additional privileges. ]]>
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (36)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill sets up automatic backups to GitHub or GitLab but does not clearly warn the user that files will be transmitted to a third-party remote on an ongoing schedule. In this context, the default backup target is a workspace directory that may contain source code, secrets, tokens, notes, or other sensitive material, so lack of explicit disclosure materially increases the risk of unintended data exfiltration.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The instructions specify agent prompts in Chinese and the example interaction is also written in Chinese, with no indication that language should match user preference. This can violate language/locale policy when used with users who have not opted into Chinese.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
90% confidence
Finding

The skill instructs the agent to create a remote repository and attach it to the local workspace, establishing a persistent path for future pushes. In context, this is not covert malware persistence, but it does create durable synchronization state that can continuously export workspace contents if the user does not fully understand the scope.

Content

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

New repo:

bash
gh repo create <name> --private --source=<backup-path> --remote=origin

Existing repo:

Session Persistence

Medium
Category
Rogue Agent
Confidence
93% confidence
Finding

The documented files created include a launchd plist or crontab entry, which are classic persistence mechanisms that cause code to run on a schedule after setup. In this skill's context the persistence is intended for backups, but without strong disclosure and consent it still represents a real security concern because it enables recurring unattended execution and network transmission.

Content

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

md
| Backup script | `~/.openclaw/scripts/github-backup.sh` |
| Config | `~/.openclaw/workspace/.backup-config.json` |
| Log | `~/.openclaw/logs/github-backup.log` |
| launchd plist | `~/Library/LaunchAgents/com.openclaw.github-backup.plist` |
| cron entry | Via crontab |

## Example Dialog

Session Persistence

Medium
Category
Rogue Agent
Confidence
86% confidence
Finding

The example dialog normalizes creating a GitHub repo from the workspace and wiring it for automated backup, reinforcing persistent remote publication of local data. Because the example is prescriptive and omits safety checks about sensitive files and continued syncing, it can lead users to enable exfiltration-like behavior unintentionally.

Content

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

md
2. "新建仓库还是用已有的?" → "新建"
3. "仓库名称?" → "openclaw-backup"
4. "公开还是私有?" → "私有"
5. 执行: gh repo create openclaw-backup --private --source=~/.openclaw/workspace --remote=origin
6. 创建配置文件
7. 安装定时任务
8. "安装完成,每天 12:00 和 00:00 自动备份"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The script automatically runs git add ., git commit, and git push on the configured backup path without any execution-time confirmation, dry-run, or path safety guard. In the context of a scheduled backup skill, this can unintentionally capture and exfiltrate newly added secrets, personal files, or unrelated workspace changes to a remote repository, especially because it stages all changes recursively.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This shell script performs persistent system configuration changes by deleting existing crontab entries matching github-backup.sh and installing a new scheduled task. Although it prints a success message afterward, there is no advance user-facing warning, confirmation prompt, or explanatory comment disclosing that the script will alter cron configuration.

Content

No source excerpt is available for this finding.

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/install-cron.sh (reported line 20)May include surrounding context.

sh
SCHEDULE=$(grep -o '"schedule"[[:space:]]*:[[:space:]]*"[^"]*"' "$CONFIG_FILE" | sed 's/"schedule"[[:space:]]*:[[:space:]]*"\([^"]*\)"/\1/')

# 移除旧条目
(crontab -l 2>/dev/null | grep -v "github-backup.sh") | crontab -

# 添加新条目
(crontab -l 2>/dev/null; echo "$SCHEDULE $BACKUP_SCRIPT >> $LOG_FILE 2>&1") | crontab -

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

sh
SCHEDULE=$(grep -o '"schedule"[[:space:]]*:[[:space:]]*"[^"]*"' "$CONFIG_FILE" | sed 's/"schedule"[[:space:]]*:[[:space:]]*"\([^"]*\)"/\1/')

# 移除旧条目
(crontab -l 2>/dev/null | grep -v "github-backup.sh") | crontab -

# 添加新条目
(crontab -l 2>/dev/null; echo "$SCHEDULE $BACKUP_SCRIPT >> $LOG_FILE 2>&1") | crontab -

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

sh
SCHEDULE=$(grep -o '"schedule"[[:space:]]*:[[:space:]]*"[^"]*"' "$CONFIG_FILE" | sed 's/"schedule"[[:space:]]*:[[:space:]]*"\([^"]*\)"/\1/')

# 移除旧条目
(crontab -l 2>/dev/null | grep -v "github-backup.sh") | crontab -

# 添加新条目
(crontab -l 2>/dev/null; echo "$SCHEDULE $BACKUP_SCRIPT >> $LOG_FILE 2>&1") | crontab -

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

sh
SCHEDULE=$(grep -o '"schedule"[[:space:]]*:[[:space:]]*"[^"]*"' "$CONFIG_FILE" | sed 's/"schedule"[[:space:]]*:[[:space:]]*"\([^"]*\)"/\1/')

# 移除旧条目
(crontab -l 2>/dev/null | grep -v "github-backup.sh") | crontab -

# 添加新条目
(crontab -l 2>/dev/null; echo "$SCHEDULE $BACKUP_SCRIPT >> $LOG_FILE 2>&1") | crontab -

Session Persistence

Medium
Category
Rogue Agent
Confidence
85% confidence
Finding

The cron entry is built from the schedule value parsed out of a user-writable JSON file and inserted into crontab without validation. If an attacker or another local process can modify that config, they can inject a malformed or additional cron payload, causing unintended command execution whenever cron parses or runs the entry.

Content

Scanner excerpt · scripts/install-cron.sh (reported line 23)May include surrounding context.

sh
(crontab -l 2>/dev/null | grep -v "github-backup.sh") | crontab -

# 添加新条目
(crontab -l 2>/dev/null; echo "$SCHEDULE $BACKUP_SCRIPT >> $LOG_FILE 2>&1") | crontab -

echo "cron 任务已安装: $SCHEDULE"

Session Persistence

Medium
Category
Rogue Agent
Confidence
83% confidence
Finding

The script writes XML using unescaped values derived from the config file, specifically schedule components inserted into the plist via the here-document. Because HOUR and MINUTE are taken from a loosely parsed JSON string and embedded directly into XML, a crafted config could produce malformed or attacker-controlled plist content, potentially altering job behavior or causing denial of service in the scheduled task setup.

Content

Scanner excerpt · scripts/install-launchd.sh (reported line 40)May include surrounding context.

sh
</array>"

# 创建 plist
mkdir -p "$(dirname "$PLIST")"

cat > "$PLIST" << EOF
<?xml version="1.0" encoding="UTF-8"?>

Session Persistence

Medium
Category
Rogue Agent
Confidence
86% confidence
Finding

The script immediately loads and enables a per-user LaunchAgent without any confirmation or safety checks on the generated plist contents. If the config file or referenced backup script has been tampered with, this turns that tampering into persistent execution at future scheduled times, increasing the blast radius from a local modification to recurring code execution.

Content

Scanner excerpt · scripts/install-launchd.sh (reported line 75)May include surrounding context.

sh
launchctl unload "$PLIST" 2>/dev/null || true

# 加载新任务
launchctl load "$PLIST"

echo "launchd 任务已安装: $PLIST"

Session Persistence

Medium
Category
Rogue Agent
Confidence
86% confidence
Finding

The script immediately loads and enables a per-user LaunchAgent without any confirmation or safety checks on the generated plist contents. If the config file or referenced backup script has been tampered with, this turns that tampering into persistent execution at future scheduled times, increasing the blast radius from a local modification to recurring code execution.

Content

Scanner excerpt · scripts/install-launchd.sh (reported line 75)May include surrounding context.

sh
launchctl unload "$PLIST" 2>/dev/null || true

# 加载新任务
launchctl load "$PLIST"

echo "launchd 任务已安装: $PLIST"

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This shell script's natural-language interface, help text, warnings, and status messages are entirely in Chinese, including usage output and error messages. The policy requires flagging language or locale constraints when the skill forces a specific language without user opt-in or an explicitly justified regional scope.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% 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-launchd.sh (reported line 10)May include surrounding context.

sh
CONFIG_FILE="$HOME/.openclaw/workspace/.backup-config.json"
BACKUP_SCRIPT="$HOME/.openclaw/scripts/github-backup.sh"
LOG_FILE="$HOME/.openclaw/logs/github-backup.log"
PLIST="$HOME/Library/LaunchAgents/com.openclaw.github-backup.plist"

# 颜色输出
RED='\033[0;31m'

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% 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-launchd.sh (reported line 42)May include surrounding context.

sh
CONFIG_FILE="$HOME/.openclaw/workspace/.backup-config.json"
BACKUP_SCRIPT="$HOME/.openclaw/scripts/github-backup.sh"
LOG_FILE="$HOME/.openclaw/logs/github-backup.log"
PLIST="$HOME/Library/LaunchAgents/com.openclaw.github-backup.plist"

# 颜色输出
RED='\033[0;31m'

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% 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-launchd.sh (reported line 44)May include surrounding context.

sh
CONFIG_FILE="$HOME/.openclaw/workspace/.backup-config.json"
BACKUP_SCRIPT="$HOME/.openclaw/scripts/github-backup.sh"
LOG_FILE="$HOME/.openclaw/logs/github-backup.log"
PLIST="$HOME/Library/LaunchAgents/com.openclaw.github-backup.plist"

# 颜色输出
RED='\033[0;31m'

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% 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-launchd.sh (reported line 72)May include surrounding context.

sh
CONFIG_FILE="$HOME/.openclaw/workspace/.backup-config.json"
BACKUP_SCRIPT="$HOME/.openclaw/scripts/github-backup.sh"
LOG_FILE="$HOME/.openclaw/logs/github-backup.log"
PLIST="$HOME/Library/LaunchAgents/com.openclaw.github-backup.plist"

# 颜色输出
RED='\033[0;31m'

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% 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-launchd.sh (reported line 77)May include surrounding context.

sh
CONFIG_FILE="$HOME/.openclaw/workspace/.backup-config.json"
BACKUP_SCRIPT="$HOME/.openclaw/scripts/github-backup.sh"
LOG_FILE="$HOME/.openclaw/logs/github-backup.log"
PLIST="$HOME/Library/LaunchAgents/com.openclaw.github-backup.plist"

# 颜色输出
RED='\033[0;31m'

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% 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/manage.sh (reported line 10)May include surrounding context.

sh
CONFIG_FILE="$HOME/.openclaw/workspace/.backup-config.json"
BACKUP_SCRIPT="$HOME/.openclaw/scripts/github-backup.sh"
LOG_FILE="$HOME/.openclaw/logs/github-backup.log"
PLIST="$HOME/Library/LaunchAgents/com.openclaw.github-backup.plist"

# 颜色输出
RED='\033[0;31m'

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% 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/manage.sh (reported line 129)May include surrounding context.

sh
CONFIG_FILE="$HOME/.openclaw/workspace/.backup-config.json"
BACKUP_SCRIPT="$HOME/.openclaw/scripts/github-backup.sh"
LOG_FILE="$HOME/.openclaw/logs/github-backup.log"
PLIST="$HOME/Library/LaunchAgents/com.openclaw.github-backup.plist"

# 颜色输出
RED='\033[0;31m'

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% 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/manage.sh (reported line 130)May include surrounding context.

sh
CONFIG_FILE="$HOME/.openclaw/workspace/.backup-config.json"
BACKUP_SCRIPT="$HOME/.openclaw/scripts/github-backup.sh"
LOG_FILE="$HOME/.openclaw/logs/github-backup.log"
PLIST="$HOME/Library/LaunchAgents/com.openclaw.github-backup.plist"

# 颜色输出
RED='\033[0;31m'

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% 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/manage.sh (reported line 131)May include surrounding context.

sh
CONFIG_FILE="$HOME/.openclaw/workspace/.backup-config.json"
BACKUP_SCRIPT="$HOME/.openclaw/scripts/github-backup.sh"
LOG_FILE="$HOME/.openclaw/logs/github-backup.log"
PLIST="$HOME/Library/LaunchAgents/com.openclaw.github-backup.plist"

# 颜色输出
RED='\033[0;31m'

Static analysis

No suspicious patterns detected.