T09 · Insecure Skill Coding Practices
- Location
scripts/add.py:34- Finding
Credential vault stores secrets in plaintext
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill is a credential manager that stores sensitive tokens locally, but its security claims are stronger than what the code actually provides.
Review this skill carefully before installing. It may be acceptable for low-risk local notes or temporary credentials, but do not treat it as a hardened password manager or secure vault. Any secrets saved to it should be considered readable by code running as your user, and deleted credentials should still be rotated at the provider.
scripts/add.py:34Credential vault stores secrets in plaintext
scripts/remove.py:31Secure deletion implementation does not overwrite persisted secret data
scripts/audit.py:15Audit log is writable and does not provide tamper evidence
scripts/get.py:30Credential database updates are non-atomic and lack concurrency control
SKILL.md:48Cryptographic dependency is installed without version or hash pinning
This finding suggests the documented capability set is substantially overstated relative to the implemented behavior, to the point that the skill may only provide limited viewing/statistics rather than secure secret management. Security misrepresentation is itself harmful here because users may entrust valuable credentials to a tool that lacks the controls they rely on.
This finding suggests the documented capability set is substantially overstated relative to the implemented behavior, to the point that the skill may only provide limited viewing/statistics rather than secure secret management. Security misrepresentation is itself harmful here because users may entrust valuable credentials to a tool that lacks the controls they rely on.
This finding suggests the documented capability set is substantially overstated relative to the implemented behavior, to the point that the skill may only provide limited viewing/statistics rather than secure secret management. Security misrepresentation is itself harmful here because users may entrust valuable credentials to a tool that lacks the controls they rely on.
This finding suggests the documented capability set is substantially overstated relative to the implemented behavior, to the point that the skill may only provide limited viewing/statistics rather than secure secret management. Security misrepresentation is itself harmful here because users may entrust valuable credentials to a tool that lacks the controls they rely on.
This finding suggests the documented capability set is substantially overstated relative to the implemented behavior, to the point that the skill may only provide limited viewing/statistics rather than secure secret management. Security misrepresentation is itself harmful here because users may entrust valuable credentials to a tool that lacks the controls they rely on.
This finding suggests the documented capability set is substantially overstated relative to the implemented behavior, to the point that the skill may only provide limited viewing/statistics rather than secure secret management. Security misrepresentation is itself harmful here because users may entrust valuable credentials to a tool that lacks the controls they rely on.
The backup workflow explicitly handles a file containing secrets, which is expected for a token manager, but it still represents credential access functionality with high sensitivity. In this skill's context, such access is inherently dangerous because any weakness in storage, export, import, or logging can expose a concentrated set of credentials.
python backup.py # 加密导出到 secrets.json.enc
python backup.py --import backup.json.enc # 解密导入(需输入密码)
python backup.py --check # 检查备份文件完整性
The autocapture feature detects credential-like content in conversation text and saves it to secrets.json, which is a direct credential-collection mechanism. In an AI/agent setting this is especially dangerous because users may paste secrets incidentally, and the skill could persist them locally without a fully informed expectation of retention.
### autocapture.py — 自动截获(AI 对话中自动调用)
当 AI 在对话中检测到凭证信息时,自动解析并保存到 `secrets.json`。
**自动识别的凭证类型:**
| 类型 | 匹配模式 | 自动分类 |
Even with the privacy note, the skill confirms that detected credentials may be written to secrets.json after user confirmation, meaning it persists highly sensitive material locally. Because the broader document also appears to overstate its security controls, this persistence is more dangerous than in a mature, verifiably secure secret manager.
python autocapture.py --list
> **隐私说明**:自动截获**仅检测不保存**,发现凭证后显示预览并提示「确认」后才写入 `secrets.json`。你随时可以拒绝。
## 安全说明
This section acknowledges local storage of secrets.json and audit logging around secret operations, confirming that the skill maintains a concentrated repository of credentials on disk. A local plaintext secret store is a high-value target, and the claimed surrounding controls are questionable based on the other findings, making compromise more impactful.
- **安全删除**:文件删除前覆写3次随机数据
- **审计日志**:所有操作记录到 `secrets.audit.log`,仅追加不可修改
- **输入消毒**:所有 key 只允许 `[a-zA-Z0-9_\-]`,长度≤64,防止 injection
- 不要将 `secrets.json` 提交到 Git
## 文件结构
The script stores highly sensitive credentials in a local JSON file at ~/.openclaw/workspace/secrets.json, with no encryption at rest and no integrity protection. In the context of a token-manager skill explicitly designed to manage API tokens, passwords, and SSH keys, plaintext local storage materially increases the risk of credential theft from local compromise, backups, sync tools, other processes, or accidental disclosure.
import os, json, stat, re
from datetime import datetime
SECRETS_FILE = os.path.expanduser("~/.openclaw/workspace/secrets.json")
AUDIT_FILE = os.path.expanduser("~/.openclaw/workspace/secrets.audit.log")
LOCK_FILE = os.path.expanduser("~/.openclaw/workspace/secrets.lock")
The module is explicitly designed to detect and persist credentials into a local secrets store under the user's home directory. In a skill whose purpose is token and key management, this is highly sensitive behavior: any misuse, compromise of the workspace, or unintended invocation can lead to centralized collection of API keys, passwords, and tokens, increasing the blast radius of a leak.
import os, json, stat, re
from datetime import datetime
SECRETS_FILE = os.path.expanduser("~/.openclaw/workspace/secrets.json")
AUDIT_FILE = os.path.expanduser("~/.openclaw/workspace/secrets.audit.log")
FIELD_PATTERNS = {
The confirm_and_save workflow persists detected credentials to secrets.json once a boolean flag is set, which creates a direct path from arbitrary conversation text to durable secret storage. In agent environments, confirmation logic can be triggered incorrectly or socially engineered, causing sensitive credentials mentioned in chat to be silently aggregated and retained.
"""
确认并保存检测到的凭证。
若 confirmed=False(默认),仅打印预览,不保存。
若 confirmed=True,才真正写入 secrets.json。
返回已保存的结果列表。
"""
if not results:
This code finalizes writing captured credentials to a plaintext JSON file and reports successful storage, confirming that sensitive material is retained locally. Given the skill's context as a centralized token manager, this is more dangerous because it consolidates many third-party secrets into one file, making theft or accidental exposure significantly more impactful.
_audit("autocapture", key, r["field"], r["value_masked"], True)
save(data)
print(f"\n[OK] 已保存 {len(results)} 个凭证到 secrets.json")
return results
# ───────────────────────────────────────────────────────────────
The script stores generated passwords in a plaintext JSON file under '~/.openclaw/workspace/secrets.json'. Although it applies restrictive chmod after writing, the secret remains unencrypted at rest, and there is a race/creation-window risk if the file or parent directory permissions are weak or if the file already exists with broader access.
if not re.fullmatch(r'[a-zA-Z0-9_\-]{1,64}', save_key):
print(f"[错误] Invalid key format: {save_key!r}"); sys.exit(1)
import os, json, stat
SECRETS_FILE = os.path.expanduser("~/.openclaw/workspace/secrets.json")
AUDIT_FILE = os.path.expanduser("~/.openclaw/workspace/secrets.audit.log")
def _audit(action, key, success=True):
entry = {"ts": datetime.now().isoformat(), "action": action, "key": key, "success": success}
The script confirms that a password was saved to 'secrets.json' under a user-supplied key, which reinforces a workflow of persisting highly sensitive credentials to a local plaintext store. In a token-manager skill, this context increases risk because the application is specifically aggregating many credentials into one target file, making compromise more damaging.
json.dump(data, f, ensure_ascii=False, indent=2)
os.chmod(SECRETS_FILE, stat.S_IRUSR | stat.S_IWUSR)
_audit("genpass_save", save_key, True)
print(f"\n[OK] 已保存到 secrets.json [{save_key}]")
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""迁移旧格式 secrets.json 到 v2 格式"""
import sys; sys.stdout.reconfigure(encoding='utf-8')
import os, json, stat
from datetime import datetime
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""迁移旧格式 secrets.json 到 v2 格式"""
import sys; sys.stdout.reconfigure(encoding='utf-8')
import os, json, stat
from datetime import datetime
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""迁移旧格式 secrets.json 到 v2 格式"""
import sys; sys.stdout.reconfigure(encoding='utf-8')
import os, json, stat
from datetime import datetime
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""迁移旧格式 secrets.json 到 v2 格式"""
import sys; sys.stdout.reconfigure(encoding='utf-8')
import os, json, stat
from datetime import datetime
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""迁移旧格式 secrets.json 到 v2 格式"""
import sys; sys.stdout.reconfigure(encoding='utf-8')
import os, json, stat
from datetime import datetime
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""迁移旧格式 secrets.json 到 v2 格式"""
import sys; sys.stdout.reconfigure(encoding='utf-8')
import os, json, stat
from datetime import datetime
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""迁移旧格式 secrets.json 到 v2 格式"""
import sys; sys.stdout.reconfigure(encoding='utf-8')
import os, json, stat
from datetime import datetime
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""迁移旧格式 secrets.json 到 v2 格式"""
import sys; sys.stdout.reconfigure(encoding='utf-8')
import os, json, stat
from datetime import datetime
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""迁移旧格式 secrets.json 到 v2 格式"""
import sys; sys.stdout.reconfigure(encoding='utf-8')
import os, json, stat
from datetime import datetime
No suspicious patterns detected.