T09 · Insecure Skill Coding Practices
- Location
references/SETUP_GUIDE.md:175- Finding
Sensitive backup directory is configured with overly permissive access
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill is a coherent OpenClaw backup tool, but it needs review because it handles sensitive backups, schedules recurring automation, and includes weak backup-storage and deletion safeguards.
Review before installing. Use a private backup directory such as mode 700, protect archives as sensitive secrets, avoid shared or synced locations unless encrypted, confirm the cron schedule and timezone, and do not run cleanup with --execute unless the selected archives have been reviewed.
references/SETUP_GUIDE.md:175Sensitive backup directory is configured with overly permissive access
scripts/cleanup_old_backups.py:28Negative retention values can delete all matching backup archives
The primary backup behavior matches part of the description: it uses the built-in openclaw backup create command and supports verification and dry-run. However, the declared description materially overstates the implemented functionality by claiming cleanup of old backups, health verification workflows, and first-run setup with cron prompting, none of which are present in the supplied code. This is a description-to-behavior mismatch due to missing declared capabilities rather than undeclared extra behavior.
The description presents a broader backup-management skill whose core capability is creating OpenClaw backups and also verifying backup health, cleaning old backups, and handling setup/cron guidance. The provided code chunk is narrowly scoped to cleanup of old backup archives in ~/openclaw_backups (or OPENCLAW_BACKUP_DIR), with dry-run behavior by default and optional deletion using --execute. This is not malicious or unrelated, but it materially underimplements the declared primary purpose. Since the code lacks the key declared behaviors—especially backup creation and health verification—the description does not accurately represent what this code chunk actually does.
The declared description centers on running backups via openclaw backup create, plus cleanup and health verification. The provided code does none of those things: it only lists existing cron jobs and adds a scheduled cron entry if one is absent. While cron setup is mentioned in the description as a first-run behavior, here it is the entire implementation, so the actual code chunk's primary behavior is materially narrower and different from the declared backup/verification/cleanup functionality.
The changelog explicitly states that backups include credentials and session history, which are highly sensitive data types, but it provides no warning, opt-in language, encryption note, or handling guidance. In the context of a backup skill, this increases the risk that users will create archives containing secrets and activity history without understanding the exposure if the backup directory is accessed, copied, or retained insecurely.
The skill advertises and invokes shell-based scripts and implies access to files, environment, and backup operations, but it does not declare any explicit tool scope such as permissions or allowed-tools. That creates an authorization ambiguity where an agent may run higher-risk capabilities than users expect, especially for a skill that handles archives containing configuration, session history, and credentials.
Trigger phrases like 'run backup', 'backup now', and especially the cron phrase 'backup openclaw' are broad enough to collide with ordinary user language. That can cause unintended activation of backup, verification, or deletion-related flows, which is risky for a skill that touches sensitive archives and may schedule persistent automation.
The skill is designed to create a cron job, which introduces persistence beyond the current user interaction. Persistence increases risk because a sensitive operation involving backups of credentials, session history, and workspace data may continue automatically and repeatedly, potentially after the user forgets it was enabled or in contexts where broad natural-language triggers could be misinterpreted.
- "backup openclaw", "run backup", "backup now"
- "check backup health", "verify backup"
- "cleanup old backups", "remove old backups"
- First run on new machine → run setup + prompt to create cron job
Uses built-in `openclaw backup create` — no extra tools needed.
Cron message: "backup openclaw" → runs scripts/backup.py
---
Using a broad natural-language cron trigger message means a background scheduled session may activate based on an ambiguous phrase rather than a constrained command. In a persistent automated context, ambiguity is more dangerous because it can repeatedly invoke a high-sensitivity backup skill without fresh user review.
The file specifies a daily 4 AM HKT backup schedule, which forces a locale-specific timezone choice in natural-language instructions. There is no indication that users can select their own timezone or that HKT is required for a region-specific purpose.
The statement that the cron job runs automatically at 04:00 HKT reflects a locale-specific policy choice presented as the default behavior. The documentation does not offer localization options or explain why this timezone is mandatory.
The skill explicitly states that backups include credentials, session history, and workspace files, but it does not present a prominent warning about the sensitivity of the resulting archives or the need to protect storage and transfer. Users may treat the backups like ordinary files and inadvertently expose highly sensitive data.
The setup instructions direct users to configure backups specifically for 4 AM HKT, and later the manual cron example fixes the timezone to Asia/Hong_Kong. This imposes a locale-specific policy in natural language without offering alternatives or explaining that users should choose their own timezone.
This markdown file includes a command that will actually delete backup archives, but the surrounding text does not clearly warn that the operation is irreversible or may remove user data permanently. Under the markdown-specific warning criteria, destructive behavior affecting stored backups should be accompanied by an explicit caution.
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
Create the directory:
mkdir -p ~/openclaw_backups
chmod 755 ~/openclaw_backups
Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.
os.makedirs(get_backup_dir(), exist_ok=True)
def run_backup(verify=False, dry_run=False):
backup_dir = get_backup_dir()
ensure_backup_dir()
cmd = ["openclaw", "backup", "create", "--output", backup_dir]
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
cmd.append("--dry-run")
print(f"Running: {' '.join(cmd)}")
result = subprocess.run(cmd, capture_output=True, text=True)
print(result.stdout)
if result.stderr:
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
cmd.append("--dry-run")
print(f"Running: {' '.join(cmd)}")
result = subprocess.run(cmd, capture_output=True, text=True)
print(result.stdout)
if result.stderr:
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
def verify_archive(archive_path):
print(f"Verifying: {archive_path}")
result = subprocess.run(
["openclaw", "backup", "verify", archive_path],
capture_output=True,
text=True
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
def cron_exists(name):
result = subprocess.run(
["openclaw", "cron", "list", "--json"],
capture_output=True, text=True
)
The text references an optional daily cron at 04:00 HKT, which imposes a specific locale/timezone in natural language without documenting user opt-in to that locale or a reason for the regional constraint. This can be a language/locale policy concern because it assumes a fixed locale context rather than offering a neutral or user-configurable one.