T09 · Insecure Skill Coding Practices
- Location
scripts/bwp.py:30- Finding
Sensitive Baidu credentials and OAuth tokens are stored without enforced restrictive permissions
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill matches its Baidu Netdisk file-management purpose, but it needs Review because it handles credentials and destructive cloud-file actions with weak safeguards.
Install only if you are comfortable granting the agent meaningful control over your Baidu Netdisk. Treat the AppKey, SecretKey, authorization code, access token, refresh token, and printed download URLs as sensitive; avoid sharing them in chat or logs, verify any delete or upload path before running it, and revoke or rotate Baidu credentials if token-bearing output is exposed.
scripts/bwp.py:30Sensitive Baidu credentials and OAuth tokens are stored without enforced restrictive permissions
SKILL.md:41Client secrets and authorization codes are accepted through exposed command-line arguments
scripts/bwp.py:205Access tokens are disclosed in printed download URLs and reusable curl commands
The skill exposes destructive file-management commands such as delete, move, rename, and upload via exec with user-controlled path parameters. In this context, parameter abuse could cause unintended deletion, overwriting, or relocation of cloud files if the agent misinterprets instructions or is prompted into operating on attacker-specified paths without confirmation.
python ~/.openclaw/workspace/skills/baidu-wangpan/scripts/bwp.py move "/apps/file.txt" "/apps/my_new_folder"
python ~/.openclaw/workspace/skills/baidu-wangpan/scripts/bwp.py delete "/apps/file_to_delete.txt"
### Upload
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
if r.json().get('errno') == 111:
new_token = refresh_access_token(config)
if new_token:
print("Access token refreshed automatically.")
return new_token
print("Error: Token expired and refresh failed. Please re-authenticate.")
sys.exit(1)
The delete command performs destructive remote actions immediately with no confirmation, dry-run mode, or explicit warning. In an agent or automation context, a mistaken path, prompt injection, or unintended invocation could irreversibly remove user cloud data at scale.
The skill invokes shell commands, accesses local files, writes persistent configuration, and makes network requests, but it declares no explicit tool scope or allowed-tools restrictions. This increases the blast radius because an agent may execute high-risk capabilities without a least-privilege policy or clear consent boundaries.
The skill states that tokens are saved in ~/.openclaw/workspace/bwp_config.json, creating session persistence for credentials on disk. Persistent storage of access tokens is common, but without documented encryption, file-permission hardening, rotation, or lifecycle controls, compromise of the local workspace could expose long-lived access to the user's Baidu Netdisk.
### 1. Register a Baidu Developer App
1. Go to the [Baidu Netdisk Open Platform](https://pan.baidu.com/union).
2. Register as a developer and create a new application (Software App / 软件应用).
3. Obtain your **AppKey** (Client ID) and **SecretKey** (Client Secret).
### 2. Tell the Agent to Authenticate
The skill instructs users to paste AppKey, SecretKey, and authorization codes directly into chat, exposing secrets to the agent conversation layer, logs, transcripts, and potentially other tooling integrations. OAuth client secrets and auth codes are sensitive credentials that should not be collected through free-form chat.
The script stores app secrets, access tokens, and refresh tokens in a plaintext JSON file under the user's home directory without enforcing restrictive file permissions or warning the user. Any local process or user with access to that file can reuse those credentials to access or manipulate the victim's Baidu Netdisk data.
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
'autoinit': 1,
'rtype': 1 # Rename if exists
}
response = requests.post(url, data=data)
res_data = response.json()
if res_data.get('errno') == 0:
print(f"Successfully created directory: {res_data.get('path')}")
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
'autoinit': 1,
'rtype': 1 # Rename if exists
}
response = requests.post(url, data=data)
res_data = response.json()
if res_data.get('errno') == 0:
print(f"Successfully created directory: {res_data.get('path')}")
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
'autoinit': 1,
'rtype': 1 # Rename if exists
}
response = requests.post(url, data=data)
res_data = response.json()
if res_data.get('errno') == 0:
print(f"Successfully created directory: {res_data.get('path')}")
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
'autoinit': 1,
'rtype': 1 # Rename if exists
}
response = requests.post(url, data=data)
res_data = response.json()
if res_data.get('errno') == 0:
print(f"Successfully created directory: {res_data.get('path')}")
The upload feature recursively traverses directories and transmits all discovered files to a remote service, but the user-facing interface does not prominently disclose that a directory argument results in bulk exfiltration of local contents. In agent-driven usage, this increases the risk of accidental disclosure of sensitive local files.
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
f"&type=tmpfile&path={urllib.parse.quote(remote_path)}"
f"&uploadid={upload_id}&partseq={seq}"
)
up_res = requests.post(upload_url, files={'file': (file_name, chunk)}).json()
if 'md5' not in up_res:
print(f" Chunk {seq} upload failed: {up_res}")
return
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
'uploadid': upload_id,
'rtype': 1
}
final_res = requests.post(create_url, data=create_data).json()
if final_res.get('errno') == 0:
print(f" OK: {final_res.get('path')}")
else:
No suspicious patterns detected.