Back to skill

Security audit

Agent Deploy

Security checks for vulnerabilities and agentic risk

Overview

This skill manages OpenClaw agents as advertised, but it broadly copies credentials into new agents and performs sensitive config changes with weak scoping and confirmation.

Install only if you are comfortable with this skill modifying OpenClaw agent configuration and copying existing API credentials into newly deployed agents. Prefer reviewing or changing it first so credentials are explicitly allowlisted, tokens are not passed on the command line, removal requires confirmation, and generated auth files are securely permissioned and cleaned up on failure or removal.

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

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/deploy_helper.py:115
Finding
Broad Credential Replication Violates Agent Isolation and Least Privilege<![CDATA[ ## Vulnerability Details **File Location**: `scripts/deploy_helper.py:115-151` **Vulnerability Type**: Credential over-provisioning and privilege boundary violation **Risk Level**: High ### Vulnerable Code ```python elif action == "merge-auth": agent_id = sys.argv[2] agent_auth_path = os.path.expanduser( f"~/.openclaw/agents/{agent_id}/agent/auth-profiles.json" ) main_auth_path = os.path.expanduser( "~/.openclaw/agents/main/agent/auth-profiles.json" ) # Start with empty auth merged = {"version": 1, "profiles": {}, "lastGood": {}, "usageStats": {}} # Source 1: Global auth from openclaw.json global_profiles = config.get("auth", {}).get("profiles", {}) for pid, pdata in global_profiles.items(): merged["profiles"][pid] = pdata provider = pdata.get("provider", pid.split(":")[0]) merged["lastGood"][provider] = pid merged["usageStats"][pid] = {"lastUsed": 0, "errorCount": 0} print(f" [global] {pid}") # Source 2: Main agent per-agent auth if os.path.isfile(main_auth_path): with open(main_auth_path) as f2: main_auth = json.load(f2) for pid, pdata in main_auth.get("profiles", {}).items(): if pid not in merged["profiles"]: merged["profiles"][pid] = pdata provider = pdata.get("provider", pid.split(":")[0]) merged["lastGood"][provider] = pid merged["usageStats"][pid] = {"lastUsed": 0, "errorCount": 0} print(f" [main] {pid}") # Write to agent auth dir os.makedirs(os.path.dirname(agent_auth_path), exist_ok=True) with open(agent_auth_path, "w") as f2: json.dump(merged, f2, indent=2) print(f" Total: {len(merged['profiles'])} profiles -> {agent_auth_path}") ``` The behavior is also explicitly described in `SKILL.md:95-96`: ```markdown - Merges API keys from BOTH global config (`openclaw.json` auth.profiles) AND m ...[truncated 1781 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not copy any authentication profile into a new agent by default. 2. Require the operator to supply an explicit allowlist of profiles required by that agent. 3. Create agent-specific, least-privileged credentials rather than duplicating main-agent credentials. 4. Prefer short-lived or dynamically issued credentials with narrowly scoped provider permissions. 5. Prevent child agents from reading the main agent's authentication directory. 6. Record and audit which profile was granted to which agent. 7. Fail deployment if an requested profile is unavailable instead of silently granting all available profiles. 8. Revoke and rotate credentials that may already have been broadly replicated. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/deploy_helper.py:148
Finding
Plaintext Credential Files Lack Enforced Permissions and Lifecycle Cleanup<![CDATA[ ## Vulnerability Details **File Location**: `scripts/deploy_helper.py:148-149` **Related Locations**: `scripts/deploy.sh:56-63`, `scripts/remove.sh:43-46` **Vulnerability Type**: Insecure plaintext secret storage and residual credential data **Risk Level**: High ### Vulnerable Code Credential file creation does not enforce a restrictive directory or file mode: ```python # Write to agent auth dir os.makedirs(os.path.dirname(agent_auth_path), exist_ok=True) with open(agent_auth_path, "w") as f2: json.dump(merged, f2, indent=2) ``` The credentials are written before the remaining deployment and validation steps: ```bash # [4/8] Merge auth profiles (global + main agent) echo "[4/8] Merge auth profiles..." python3 "$HELPER" merge-auth "$AGENT_ID" if [ $? -ne 0 ]; then echo " WARNING: Auth merge failed. New agent may not have API keys." echo " Run manually: openclaw agents add $AGENT_ID" fi ``` Removal performs configuration changes but does not delete the generated agent authentication file: ```bash echo "" echo "SUCCESS: Agent '$AGENT_ID' removed" echo " Workspace NOT deleted: $HOME/.openclaw/workspace-$AGENT_ID" echo " Channels/bindings hot-reload automatically." ``` ### Technical Analysis `open(..., "w")` creates a plaintext JSON credential file using permissions derived from the process umask. The code does not explicitly require mode `0600`, and the containing directory is created without explicitly requiring mode `0700`. On a system with a permissive umask or pre-existing permissive directories, other local users may be able to read the file. The file is generated before later configuration and doctor-validation operations. The configuration rollback only restores `openclaw.json`; it does not remove the newly generated authentication file. The removal script likewise does not delete or revoke the child agent's authentication material. Consequently, credentials can survive a failed deployment or agent removal and remain ava ...[truncated 1098 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create each agent authentication directory with mode `0700`. 2. Create credential files atomically with mode `0600`, independent of the process umask. 3. Write credentials to a securely created temporary file in the same directory, flush and synchronize it, and atomically rename it into place. 4. Reject pre-existing authentication paths that are symbolic links or not owned by the expected user. 5. Track every filesystem artifact created during deployment and remove it if a later step fails. 6. On agent removal, delete the agent-specific authentication material and revoke associated credentials where supported. 7. If credentials must be retained, require an explicit operator option and clearly report the retained path. 8. Rotate credentials that may have remained in files created by previous deployments. 9. Prefer a protected operating-system key store or dedicated secret manager over plaintext JSON storage. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/deploy.sh:6
Finding
Telegram Bot Token Is Exposed Through Process Arguments and Console Output<![CDATA[ ## Vulnerability Details **File Location**: `scripts/deploy.sh:6-7` **Related Locations**: `SKILL.md:37-43`, `scripts/deploy.sh:17,35`, `scripts/deploy_helper.py:91-92` **Vulnerability Type**: Sensitive information exposure **Risk Level**: Medium ### Vulnerable Code The documentation directs the agent to place the complete token in the command line: ```bash bash {baseDir}/scripts/deploy.sh <agentId> <botToken> ``` The deployment script accepts the secret as a positional argument and prints a token prefix: ```bash AGENT_ID="${1:?Usage: deploy.sh <agentId> <botToken> [workspace_path]}" BOT_TOKEN="${2:?Usage: deploy.sh <agentId> <botToken> [workspace_path]}" ``` ```bash echo " Agent: $AGENT_ID" echo " Token: ${BOT_TOKEN:0:10}..." echo " Workspace: $WORKSPACE" echo " Config: $CONFIG" ``` It then places the complete token in another process's arguments: ```bash PREFLIGHT=$(python3 "$HELPER" preflight "$AGENT_ID" "$BOT_TOKEN" 2>&1) || { echo "$PREFLIGHT" exit 1 } ``` The listing action also prints the beginning of stored tokens: ```python token = accounts.get(tg_acct, {}).get("botToken", "N/A") t_short = token[:10] + "..." if len(token) > 10 else token ``` ### Technical Analysis Command-line arguments are not an appropriate secret transport mechanism. Depending on the operating system and process visibility settings, arguments can be exposed through process-listing tools or process metadata. The invoking command may also be retained in shell history, agent execution logs, orchestration telemetry, or audit records. The deployment creates two observable argument vectors containing the complete token: the Bash invocation and the Python preflight invocation. Printing the first ten characters in deploy and list output also discloses unnecessary credential metadata and can propagate it into conversation logs or monitoring systems. ### Attack Path 1. An operator or AI agent invokes `deploy.sh` with the Telegram token as a pos ...[truncated 975 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not accept bot tokens as command-line arguments. 2. Read the token from protected standard input without echoing it, a dedicated file descriptor, or a secret manager. 3. If a temporary secret file is unavoidable, create it with mode `0600`, validate ownership, reject symbolic links, and delete it immediately after use. 4. Refactor preflight validation so the token is passed in memory or over standard input rather than as a Python argument. 5. Never print the complete token or any token prefix in deployment and listing output. 6. Redact secret values from exception messages, diagnostics, telemetry, and audit logs. 7. Rotate any tokens that may have been exposed through command history or process monitoring. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/deploy.sh:6
Finding
Missing Agent Identifier Validation Enables Unsafe Path and Configuration-Key Handling<![CDATA[ ## Vulnerability Details **File Location**: `scripts/deploy.sh:6-11` **Related Locations**: `scripts/deploy.sh:46-53,99`, `scripts/deploy_helper.py:11-37,115-117`, `scripts/remove.sh:5-8,30-37`, `SKILL.md:67-71` **Vulnerability Type**: Improper input validation **Risk Level**: Medium ### Vulnerable Code The deployment script consumes the identifier without enforcing the documented format: ```bash AGENT_ID="${1:?Usage: deploy.sh <agentId> <botToken> [workspace_path]}" BOT_TOKEN="${2:?Usage: deploy.sh <agentId> <botToken> [workspace_path]}" WORKSPACE="${3:-$HOME/.openclaw/workspace-$AGENT_ID}" CONFIG="${OPENCLAW_CONFIG_PATH:-$HOME/.openclaw/openclaw.json}" BACKUP="$HOME/.openclaw/openclaw.json.pre-$AGENT_ID" OC="${OPENCLAW_BIN:-openclaw}" HELPER="$(dirname "$0")/deploy_helper.py" ``` The script creates directories from the derived or caller-provided workspace path: ```bash echo "[3/8] Create workspace..." mkdir -p "$WORKSPACE/memory" "$WORKSPACE/output" "$WORKSPACE/skills" if [ ! -f "$WORKSPACE/SOUL.md" ]; then printf '# Agent\n\nYou are a helpful AI assistant.\n' > "$WORKSPACE/SOUL.md" echo " Created default SOUL.md" fi ``` The unvalidated identifier is interpolated into a dotted configuration key: ```bash $OC config set "channels.telegram.accounts.$AGENT_ID" "$ACCT_JSON" || { echo "ERROR: Failed to set telegram account. Rolling back..." cp "$BACKUP" "$CONFIG" exit 1 } ``` The helper also uses the identifier in an authentication path: ```python agent_id = sys.argv[2] agent_auth_path = os.path.expanduser( f"~/.openclaw/agents/{agent_id}/agent/auth-profiles.json" ) ``` The documentation claims a validation rule that the implementation does not enforce: ```markdown 3. **NEVER change the agentId format.** It must be lowercase letters, numbers, and hyphens only. No spaces, no uppercase, no special characters. ``` ### Technical Analysis The documented identifier grammar is lowercase letters, numbers, and hyphens, but ne ...[truncated 2104 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Validate the identifier at the beginning of every shell and Python entry point. 2. Enforce a strict expression such as `^[a-z0-9]+(?:-[a-z0-9]+)*$`. 3. Reject dots, slashes, backslashes, whitespace, control characters, empty identifiers, leading hyphens, and traversal sequences. 4. Apply a reasonable maximum identifier length. 5. Remove the undocumented workspace argument unless it is required. 6. If custom workspaces are required, canonicalize the path and verify that it remains beneath an approved workspace root. 7. Reject symbolic-link components and verify ownership before creating files. 8. Avoid interpolating untrusted values into dotted configuration keys. Use a structured API that accepts path components separately, if available. 9. Repeat validation in `deploy_helper.py` so directly invoking the helper cannot bypass shell-level checks. 10. Add tests for malformed identifiers, traversal attempts, dotted identifiers, Unicode edge cases, and arbitrary workspace paths. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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
Findings (15)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The skill is presented as a deployment skill, yet it also includes a destructive removal operation that can delete agent bindings and account configuration. Hiding destructive functionality behind a create/deploy-oriented description makes accidental or unauthorized invocation more likely, especially in agentic systems that rely on manifest descriptions for routing and trust decisions.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill is presented as a deployment skill, yet it also includes a destructive removal operation that can delete agent bindings and account configuration. Hiding destructive functionality behind a create/deploy-oriented description makes accidental or unauthorized invocation more likely, especially in agentic systems that rely on manifest descriptions for routing and trust decisions.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill is presented as a deployment skill, yet it also includes a destructive removal operation that can delete agent bindings and account configuration. Hiding destructive functionality behind a create/deploy-oriented description makes accidental or unauthorized invocation more likely, especially in agentic systems that rely on manifest descriptions for routing and trust decisions.

Missing User Warnings

High
Confidence
98% confidence
Finding
The skill instructs direct execution of an agent removal script without any confirmation, preview, or warning despite the action being destructive. In an agentic environment, this creates a significant risk of accidental deletion from a mistaken request, ambiguous routing, or prompt-manipulated invocation.

Intent-Code Divergence

High
Confidence
98% confidence
Finding
The script prints that the deployed agent has sandbox restrictions such as non-main mode, agent scope, no workspace access, and denied gateway tools, but it never actually configures those controls. This creates a dangerous mismatch between operator expectations and real security posture, so users may deploy agents believing they are constrained when they are not.

Description-Behavior Mismatch

High
Confidence
97% confidence
Finding
The merge-auth action copies authentication profiles from global and main-agent stores into a newly created agent, effectively propagating credentials across trust boundaries. In a multi-agent system, this broadens access for the new agent and undermines isolation, so compromise or misuse of one agent can inherit secrets intended for other contexts.

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill instructs execution of shell scripts and handling of secrets, but the manifest does not declare any tool scope or allowed-tools boundaries. This increases the risk that an agent platform may grant broader-than-necessary file or environment access, enabling unintended writes or exposure of sensitive configuration and bot tokens during deployment operations.

Vague Triggers

Medium
Confidence
94% confidence
Finding
The trigger guidance uses broad language like 'or similar,' making activation boundaries ambiguous for an agent that may auto-select this skill. In a skill capable of modifying configuration, deploying bots, or removing agents, vague routing conditions raise the chance of unintended execution in response to loosely related user requests.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The script logs the first part of the bot token to stdout, which can expose credential material in shell history capture, CI logs, terminal recording, or centralized logging systems. Even partial secret disclosure increases the chance of token identification and mishandling, especially in operational environments where logs are widely accessible.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The script claims to create an isolated agent, yet it explicitly merges authentication profiles from global or main-agent state into the new agent. That breaks isolation boundaries and can grant the new agent access to API keys or credentials it should not inherit, increasing blast radius if the new agent is compromised or misconfigured.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The top-level docstring narrows the helper's purpose to 'pre-flight checks + config generation'. In reality, later branches perform unrelated operational tasks including listing agents, removing config entries, migrating existing bot configuration, and writing merged auth data to disk, which actively contradicts the stated scope of the module.

Missing User Warnings

Medium
Confidence
80% confidence
Finding
The helper loads `openclaw.json`, later compares `botToken` values and merges auth profiles from auth files, which involves access to credential-bearing data. There is no visible warning, comment, or user-facing log explaining that the script accesses sensitive tokens/auth profile information.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The list action enumerates configured Telegram accounts and prints a visible prefix of each bot token. Even though it truncates the value, exposing secret material and account inventory exceeds the helper's deployment role and creates unnecessary credential disclosure risk through logs, terminal history, screenshots, or delegated tool output.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
This code performs a file write to an auth-related path containing merged credential/profile data, but there is no confirmation prompt, warning comment/docstring, or user-facing disclosure immediately describing that sensitive auth data will be written. For a code file, writing authentication material is a safety-relevant operation that should be clearly disclosed.

Description-Behavior Mismatch

Low
Confidence
96% confidence
Finding
The manifest says the skill deploys new agents, but the body also documents listing and removing agents. This scope drift weakens transparency and can cause systems or users to invoke a skill expecting creation-only behavior while unknowingly granting access to reconnaissance and destructive operations.

Static analysis

No suspicious patterns detected.