Back to skill

Security audit

Delete Agent With Telegram Group

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed cleanup skill, but its deletion script can permanently remove local OpenClaw data with safety checks that are too loose for that level of impact.

Review this before installing if you rely on OpenClaw workspaces or shared Telegram routing. Only run it after inspecting the dry-run output, verifying the exact workspace path, and keeping backups; avoid workspace deletion unless you are sure the OpenClaw config has not been tampered with. Handle actual Telegram group deletion manually or with a clearly separate confirmation step.

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/delete_agent.py:128
Finding
Untrusted workspace configuration can cause recursive deletion of unrelated user data## Vulnerability Details **File Location**: `scripts/delete_agent.py`, lines 70-74 and 128-136 **Vulnerability Type**: Insufficient validation of a destructive filesystem target **Risk Level**: High ### Vulnerable Code ```python if target: removed["agent"] = True cfg["agents"]["list"] = new_agents removed["workspace"] = target.get("workspace") ``` ```python if args.delete_workspace and removed["workspace"]: wp = Path(removed["workspace"]).expanduser() # guardrail: only allow deleting workspaces under user's home and matching claw-* naming validate_within(Path.home(), wp, "workspace") if not wp.name.startswith("claw-"): raise SystemExit(f"Error: refusing unsafe workspace delete (expected claw-*): {wp}") if wp.exists(): shutil.rmtree(wp) ``` ### Technical Analysis The recursive deletion target is taken directly from the mutable `workspace` field in `~/.openclaw/openclaw.json`. The implemented checks only establish that the resolved path is beneath the current user's home directory and that its final component starts with `claw-`. These conditions do not prove that the directory belongs to the selected agent. Consequently, any unrelated directory beneath the user's home whose basename begins with `claw-` can satisfy the guardrails. If configuration integrity has been compromised or the workspace value was incorrectly assigned, `shutil.rmtree` recursively removes that unrelated directory. The path-resolution check does protect against straightforward traversal outside the home directory and against symlink targets resolving outside it. However, it does not provide ownership or agent-to-workspace binding validation. ### Attack Path 1. An attacker or another process with permission to modify `~/.openclaw/openclaw.json` changes the selected agent's `workspace` value to an unrelated directory such as `/home/user/projects/claw-important`. 2. The user follows the ...[truncated 826 chars]
Remediation
## Remediation Suggestions - Do not authorize deletion based only on a name prefix. - Define a dedicated canonical workspace root and require all removable workspaces to be direct children of that root. - Derive the expected workspace path from the validated agent identifier where possible instead of trusting a mutable configuration path. - Store and verify an ownership marker inside the workspace, containing the corresponding agent ID. - Resolve the path before any destructive operation and reject symlinks, the home directory itself, filesystem roots, and paths that do not match the authoritative agent-to-workspace mapping. - Include the canonical target path in dry-run output and require path-specific confirmation for workspace deletion. - Consider moving the workspace into a recoverable quarantine or trash location before permanent removal. Example hardening logic should require all of the following: the canonical path is beneath the dedicated workspace root, its expected name exactly matches the selected agent, its ownership marker matches `agent_id`, and it is not a symbolic link.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/delete_agent.py:119
Finding
Workspace validation occurs after irreversible configuration and directory changes## Vulnerability Details **File Location**: `scripts/delete_agent.py`, lines 119-136 **Vulnerability Type**: Non-transactional destructive operation and late input validation **Risk Level**: Medium ### Vulnerable Code ```python # write files with backups removed["backups"].append(backup(OPENCLAW_JSON)) OPENCLAW_JSON.write_text(json.dumps(cfg, ensure_ascii=False, indent=2), encoding="utf-8") if cron and args.delete_cron_jobs: removed["backups"].append(backup(CRON_JSON)) CRON_JSON.write_text(json.dumps(cron, ensure_ascii=False, indent=2), encoding="utf-8") if agent_dir.exists(): shutil.rmtree(agent_dir) if args.delete_workspace and removed["workspace"]: wp = Path(removed["workspace"]).expanduser() # guardrail: only allow deleting workspaces under user's home and matching claw-* naming validate_within(Path.home(), wp, "workspace") if not wp.name.startswith("claw-"): raise SystemExit(f"Error: refusing unsafe workspace delete (expected claw-*): {wp}") if wp.exists(): shutil.rmtree(wp) ``` ### Technical Analysis The workspace path is canonicalized and validated only after the script has rewritten the main configuration, potentially rewritten the cron configuration, and recursively deleted the agent directory. If the workspace is invalid—for example, it is outside the home directory or does not have a `claw-` basename—the script terminates through `SystemExit` only after those earlier operations have completed. This creates a partially applied deletion and violates the expectation that safety checks prevent the destructive run. Although configuration backups are created, the deleted agent directory is not backed up. There is also no automatic rollback when a later validation or deletion fails. ### Attack Path 1. The selected agent has an invalid or malformed workspace value in configuration. 2. The user invokes the script with `--yes --delete-workspace`. ...[truncated 863 chars]
Remediation
## Remediation Suggestions - Perform a complete preflight phase before making any changes. - During preflight, resolve and validate the agent directory, workspace, configuration structures, cron data, and every other deletion target. - Abort before the first write or deletion if any target is unsafe or malformed. - Write modified JSON to temporary files in the same directory, flush and synchronize them, and atomically replace the originals only after successful validation. - Move removable directories to a quarantine location before committing configuration changes, then permanently delete them only after all operations succeed. - Implement rollback that restores configuration files and quarantined directories if any later operation fails. - Ensure the dry-run executes the same preflight validation logic as the destructive mode rather than merely reporting unvalidated targets.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/delete_agent.py:76
Finding
Telegram group routing configuration can be removed while retained bindings still depend on it## Vulnerability Details **File Location**: `scripts/delete_agent.py`, lines 76-96 **Vulnerability Type**: Unsafe deletion of a potentially shared configuration resource **Risk Level**: Medium ### Vulnerable Code ```python bindings = cfg.get("bindings", []) keep_bindings = [] group_ids = set() for b in bindings: if b.get("agentId") == agent_id: removed["bindings"].append(b) p = b.get("match", {}).get("peer", {}) if p.get("kind") == "group" and p.get("id"): group_ids.add(p.get("id")) else: keep_bindings.append(b) cfg["bindings"] = keep_bindings if args.delete_telegram_group_config: tg_groups = cfg.get("channels", {}).get("telegram", {}).get("groups", {}) for gid in sorted(group_ids): if gid in tg_groups: removed["telegram_groups"].append(gid) tg_groups.pop(gid, None) ``` ### Technical Analysis Every Telegram group ID referenced by a removed binding is collected in `group_ids`. When group-configuration deletion is enabled, the corresponding entry is removed from `channels.telegram.groups` without checking whether any binding in `keep_bindings` still references the same group. A Telegram group configuration is therefore treated as exclusively owned by the deleted agent even though the data model permits multiple bindings to reference one group ID. This is a shared-resource lifecycle error: deleting one consumer can remove configuration required by other consumers. ### Attack Path 1. Agent A and Agent B both have bindings that reference the same Telegram group ID. 2. The user deletes Agent A with `--delete-telegram-group-config`. 3. Agent A's binding causes the shared group ID to be added to `group_ids`. 4. Agent B's binding remains in `keep_bindings`. 5. The script nevertheless removes the shared entry from `channels.telegram.groups`. 6. Agent B retains a binding to a group whose routing configuratio ...[truncated 466 chars]
Remediation
## Remediation Suggestions - Build a set of Telegram group IDs referenced by all retained bindings. - Remove a group configuration entry only if its ID is not referenced by any retained binding. - If the configuration supports explicit ownership metadata, verify that the selected agent exclusively owns the group entry before removing it. - Report shared group entries as retained during dry-run and execution output. - Add tests covering two or more agents bound to the same Telegram group. - Keep the separate confirmation requirement for actual Telegram group deletion and ensure shared bindings also block browser-assisted deletion unless all affected consumers are explicitly addressed. A safe implementation should compute retained group references after `keep_bindings` is constructed and skip `tg_groups.pop(gid, None)` whenever `gid` remains referenced.
Vulnerability Patterns
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (2)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The skill claims strong safety guarantees—mandatory dry-run first and separate explicit confirmation before irreversible Telegram group deletion—but those controls are only described in prose and not technically enforced. This can mislead operators into trusting a safer workflow than actually exists, creating a path to accidental destructive deletion of local artifacts or unintended browser/session-controlled actions without the promised confirmation barriers.

Lp3

Medium
Category
MCP Least Privilege
Confidence
85% confidence
Finding
The skill describes file-reading and file-writing behavior but declares no explicit tool scope or permission boundary. In a destructive deletion workflow, missing tool restrictions increases the chance that an agent can access or modify files beyond the intended cleanup set, especially if the runtime grants broader filesystem capabilities by default.

Static analysis

No suspicious patterns detected.