T09 · Insecure Skill Coding Practices
- Location
scripts/update-openrouter-key.py:156- Finding
API Key Exposed Through Command-Line Arguments
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill has a legitimate key-rotation purpose, but its instructions and helper script can expose OpenRouter API keys through command lines, output, permissions, and plaintext backups.
Install only if you are comfortable letting an agent read and modify OpenClaw credential files. Use dry-run first, do not paste live keys into command lines or chat logs, redact any reported key values, review and remove old .bak files after confirming rollback is no longer needed, and check that ~/.openclaw config files remain owner-readable only. Treat gateway restart and any SSH-based remote update as separate user-approved maintenance actions.
scripts/update-openrouter-key.py:156API Key Exposed Through Command-Line Arguments
scripts/update-openrouter-key.py:84Plaintext Backups Retain Historical API Keys Indefinitely
scripts/update-openrouter-key.py:106JSON Credential File Replacement Does Not Preserve Restrictive Permissions
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
| Priority | Source | Path |
|----------|--------|------|
| 1 (highest) | Environment / .env | `~/.openclaw/.env` |
| 2 | Agent config | `~/.openclaw/agents/<name>/agent/models.json` |
| 3 (lowest) | Global config | `~/.openclaw/openclaw.json` |
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
| Priority | Source | Path |
|----------|--------|------|
| 1 (highest) | Environment / .env | `~/.openclaw/.env` |
| 2 | Agent config | `~/.openclaw/agents/<name>/agent/models.json` |
| 3 (lowest) | Global config | `~/.openclaw/openclaw.json` |
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
| Priority | Source | Path |
|----------|--------|------|
| 1 (highest) | Environment / .env | `~/.openclaw/.env` |
| 2 | Agent config | `~/.openclaw/agents/<name>/agent/models.json` |
| 3 (lowest) | Global config | `~/.openclaw/openclaw.json` |
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
| Priority | Source | Path |
|----------|--------|------|
| 1 (highest) | Environment / .env | `~/.openclaw/.env` |
| 2 | Agent config | `~/.openclaw/agents/<name>/agent/models.json` |
| 3 (lowest) | Global config | `~/.openclaw/openclaw.json` |
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
| Priority | Source | Path |
|----------|--------|------|
| 1 (highest) | Environment / .env | `~/.openclaw/.env` |
| 2 | Agent config | `~/.openclaw/agents/<name>/agent/models.json` |
| 3 (lowest) | Global config | `~/.openclaw/openclaw.json` |
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
| Priority | Source | Path |
|----------|--------|------|
| 1 (highest) | Environment / .env | `~/.openclaw/.env` |
| 2 | Agent config | `~/.openclaw/agents/<name>/agent/models.json` |
| 3 (lowest) | Global config | `~/.openclaw/openclaw.json` |
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
| Priority | Source | Path |
|----------|--------|------|
| 1 (highest) | Environment / .env | `~/.openclaw/.env` |
| 2 | Agent config | `~/.openclaw/agents/<name>/agent/models.json` |
| 3 (lowest) | Global config | `~/.openclaw/openclaw.json` |
The code substantially matches the declared purpose of locating and updating OpenRouter API keys in an OpenClaw installation, including optional verification and safe update behavior via backups and dry-run support. However, the description says it 'restarts the gateway,' which is a concrete operational capability not implemented here. The script merely outputs 'Run: openclaw gateway restart' to stderr and never executes a restart command. That is a material description-to-behavior mismatch, though the rest of the description is accurate.
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# Find every file containing an OpenRouter key
grep -r "sk-or-v1" ~/.openclaw/ --include="*.json" --include=".env" -l 2>/dev/null
# Also check for uncommented key in .env
grep -v '^#' ~/.openclaw/.env 2>/dev/null | grep OPENROUTER_API_KEY
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
# Find every file containing an OpenRouter key
grep -r "sk-or-v1" ~/.openclaw/ --include="*.json" --include=".env" -l 2>/dev/null
# Also check for uncommented key in .env
grep -v '^#' ~/.openclaw/.env 2>/dev/null | grep OPENROUTER_API_KEY
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
```bash
# Find every file containing an OpenRouter key
grep -r "sk-or-v1" ~/.openclaw/ --include="*.json" --include=".env" -l 2>/dev/null
# Also check for uncommented key in .env
grep -v '^#' ~/.openclaw/.env 2>/dev/null | grep OPENROUTER_API_KEY
The command grep -v '^#' ~/.openclaw/.env | grep OPENROUTER_API_KEY will print the full environment line, likely exposing the active API key in logs or chat output. Because the skill explicitly says to report findings to the user before making changes, it creates a direct secret disclosure path during normal use.
grep -r "sk-or-v1" ~/.openclaw/ --include="*.json" --include=".env" -l 2>/dev/null
grep -v '^#' ~/.openclaw/.env 2>/dev/null | grep OPENROUTER_API_KEY
The instruction to 'Report what you found to the user before making changes' follows discovery steps that can expose raw secret material from .env. In combination, the workflow encourages the agent/operator to disclose credential contents or exact secret-bearing lines, which is dangerous because API keys can be reused immediately if leaked.
grep -r "sk-or-v1" ~/.openclaw/ --include="*.json" --include=".env" -l 2>/dev/null
grep -v '^#' ~/.openclaw/.env 2>/dev/null | grep OPENROUTER_API_KEY
Report what you found to the user before making changes.
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
If the user manages OpenClaw on other machines, repeat Steps 2-5 via SSH:
ssh <host> "grep -r 'sk-or-v1' ~/.openclaw/ --include='*.json' --include='.env' -l"
Then run the update script remotely or copy it over.
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.
# Quick API test
curl -s https://openrouter.ai/api/v1/auth/key \
-H "Authorization: Bearer sk-or-v1-YOUR-NEW-KEY" | python3 -m json.tool
The sed command embeds the full replacement API key directly in the command line while modifying .env, which can leak the secret via shell history, audit logs, and process inspection. In a credential-rotation context this is especially risky because the newly issued key is highly sensitive and often has broad access immediately after creation.
# Check if .env has an active (uncommented) key
grep -v '^#' ~/.openclaw/.env 2>/dev/null | grep OPENROUTER
# If it shows a key, update it
sed -i 's|^OPENROUTER_API_KEY=.*|OPENROUTER_API_KEY=sk-or-v1-YOUR-NEW-KEY|' ~/.openclaw/.env
This markdown file applies to SQP-2, and it describes file updates, service restart, and API verification that can affect user data, availability, and privacy. While the document explains what the skill does, it does not include an explicit warning or caution section alerting users that configs will be changed, backups created, the gateway restarted, and the key sent to OpenRouter for verification.
The skill instructs reading environment files, modifying config files, and verifying a key against an external API, which implies file read/write and network access, yet it declares no explicit tool scope or permissions. Missing scope boundaries increases the chance an agent executes sensitive operations without clear authorization controls or least-privilege limits.
The skill specifies creating timestamped backups before writing secrets, which can leave old and new API keys persisted in additional files for an extended period. Although intended as a safety feature, retaining credential-bearing backups increases the attack surface if backup permissions, cleanup, or storage location are not controlled.
The script:
- Finds all config files (`.env` + JSON) containing an openrouter key
- Creates timestamped backups before each write
- Updates only the key value (minimal change)
- Verifies the new key against the OpenRouter API
- Reports what it changed
The skill directs a gateway restart without requiring an explicit warning about service interruption or obtaining confirmation immediately before the disruptive action. In operational environments, this can cause avoidable downtime or interrupt active workloads, especially if run automatically by an agent.
The guide instructs users to place the new API key directly into shell commands and inline Python snippets, which can expose the credential through shell history, process listings, terminal scrollback, logs, and copied documentation. Although the purpose is administrative key rotation, the handling pattern is unsafe because it increases the chance of accidental credential disclosure during a sensitive operation.
The manifest promises to "verify the new key works," which in context suggests end-to-end confirmation after rotation. The verify_key function only calls OpenRouter's auth endpoint to check that the credential is valid; it does not confirm OpenClaw is using the new key successfully after configuration changes.
The manifest description says the skill "restarts the gateway," implying the rotation workflow includes actually performing that action. In the implementation, after updating files it only prints "Run: openclaw gateway restart" to stderr, so the advertised behavior is not carried out by code.
No suspicious patterns detected.