Back to skill

Security audit

Openclaw Switch

Security checks for vulnerabilities and agentic risk

Overview

The skill is purpose-aligned, but its bundled switch script has a real local code-execution risk if a crafted OpenClaw config or config path is used.

Review this skill before installing. It is intended to manage local OpenClaw model routing, but do not run the switch command against an openclaw.json or OPENCLAW_CONFIG path you do not trust. Prefer a patched version that passes values to Python through argv or environment variables, pins installation to a reviewed release or commit, and clearly documents the persistent config and shell-profile changes.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/openclaw-switch.sh:42
Finding

Arbitrary Python Code Execution Through Model Identifier Interpolation

Content
View full analysis
/dev/null; } get_primary() { py " import json, pathlib d = json.loads(pathlib.Path('$CFG').read_text()) print(d.get('agents',{}).get('defaults',{}).get('model',{}).get('primary','(not set)')) " } ``` ```bash list_models() { py " import json, pathlib d = json.loads(pathlib.Path('$CFG').read_text()) providers = d.get('models',{}).get('providers',{}) i = 1 for pname, pcfg in providers.items(): for m in pcfg.get('models',[]): mid = f\"{pname}/{m['id']}\" name = m.get('name', m['id']) print(f\"{i}|{mid}|{name}\") i += 1 " } set_primary() { py " import json, pathlib p = pathlib.Path('$CFG') d = json.loads(p.read_text()) d['agents']['defaults']['model']['primary'] = '$1' p.write_text(json.dumps(d, indent=2, ensure_ascii=False) + '\n') print('OK') " } ``` ```bash cmd_switch() { local target_n="$1" local target_id target_id=$(list_models | awk -F'|' -v n="$target_n" '$1==n {print $2}') [[ -z "$target_id" ]] && { echo "❌ Invalid number. Run: openclaw-switch list"; exit 1; } local cur; cur=$(get_primary) [[ "$target_id" == "$cur" ]] && { echo "⚠️ Already using ${target_id}"; exit 0; } echo -e "${C}🔄 Switching to: ${BD}${target_id}${N}" local res; res=$(set_primary "$target_id") ``` ### Technical Analysis The script builds Python programs as shell strings and executes them with `python3 -c`. The configuration path and selected model identifier are inserted directly into Python single-quoted string literals: ```python d['agents']['defaults']['model']['primary'] = '$1' ``` Shell quoting does not make the resulting Python source safe. If a model identifier contains a single quote followed by Python statements, it can terminate the intended Python literal and introduce ...[truncated 2567 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
README.md:25
Finding

Unpinned Installation From a Mutable Repository With Inconsistent Provenance

Content
View full analysis
Remediation
View remediation
``` 3. Publish SHA-256 checksums for release archives and document mandatory verification before execution. 4. Sign release tags or artifacts using a verifiable maintainer key, Sigstore, or an equivalent signing mechanism. 5. Protect the upstream repository with multi-factor authentication, branch protection, mandatory review, and restricted release workflows. 6. Replace the inconsistent source comment with the exact authoritative project URL. 7. Record the version and commit reviewed by each security audit so users can determine whether their installed copy matches the audited artifact. 8. Advise users not to execute newly cloned or updated shell code until its version, signature, and checksum have been verified. ]]>
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 (4)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

This markdown file instructs users to append to ~/.zshrc and later use the switch command to alter model routing, both of which affect local system or application state. Although the README explains how to perform the actions, it does not include an explicit user warning about persistent configuration changes or the need to review/back up affected files first.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill declares an executable script and describes operations that read and modify local configuration, but it does not declare any tool scope such as permissions or allowed-tools. This creates a capability mismatch: consumers of the skill may not realize it can perform file reads and writes, reducing transparency and weakening policy enforcement around local configuration changes.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
76% confidence
Finding

Natural-language content throughout the file is primarily in Chinese, including core instructions and usage guidance, and there is no indication that users may choose another language. Under the policy, forcing a specific language without opt-in can be a locale-policy issue unless the restriction is clearly documented and justified.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The file header describes the script as 'Pure bash + python3 stdlib. No external deps. No network.', setting an expectation of purely local behavior. However, the script later executes openclaw daemon restart, which is an external program invocation and not part of the stated 'pure' local JSON-only behavior; even if it often stays local, the comment is stronger than what the code guarantees.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.