T09 · Insecure Skill Coding Practices
- Location
doubao_vision_recognize.py:72- Finding
Plaintext Credential Storage Without Restrictive File Permissions
- Content
View full analysis
Vulnerability Details
File Location:
doubao_vision_recognize.py, lines 72–96 and 118–126
Vulnerability Type: Plaintext sensitive credential storage
Risk Level: MediumVulnerable Code
python # First run: auto-generate config.json with plaintext storage warning if not _CONFIG_PATH.exists(): meta = {"_comment": "⚠️ API keys stored in plaintext! Do not use on shared/backed-up/synced machines. Fill in values below, leave blank to disable."} config = dict(meta, **_CONFIG_DEFAULTS) with open(_CONFIG_PATH, "w", encoding="utf-8", newline="\n") as _f: json.dump(config, _f, ensure_ascii=False, indent=2) _f.write("\n") # Load config _cfg = {} if _CONFIG_PATH.exists(): try: with open(_CONFIG_PATH, "r", encoding="utf-8") as _f: _cfg = json.load(_f) except Exception: pass API_URL = "https://ark.cn-beijing.volces.com/api/v3/responses" ARK_API_KEY = _cfg.get("ark_api_key", "") IAM_AK = _cfg.get("volcengine_access_key", "") IAM_SK = _cfg.get("volcengine_secret_key", "") ZHIPU_API_URL = "https://open.bigmodel.cn/api/paas/v4/chat/completions" ZHIPU_API_KEY = _cfg.get("zhipu_api_key", "")The same file is subsequently rewritten without enforcing restrictive permissions:
python try: with open(_CONFIG_PATH, "r", encoding="utf-8") as _f: data = json.load(_f) data["privacy_notice_shown"] = True with open(_CONFIG_PATH, "w", encoding="utf-8", newline="\n") as _f: json.dump(data, _f, ensure_ascii=False, indent=2) _f.write("\n") except Exception: passTechnical Analysis
The Skill stores the Volcengine Ark API key, Volcengine IAM access key and secret key, and Zhipu API key as plaintext values in
config.json. Although the user-facing documentation warns about plaintext storage, the implementation does not enforce owner-only permissions when creating or rewriti ...[truncated 2005 chars]- Remediation
View remediation
Remediation Suggestions
- Prefer an operating-system credential manager, secret manager, or runtime environment variables instead of persistent plaintext JSON values.
- If file-based storage must remain supported:
- Create the credential file atomically with owner-only mode
0600on POSIX systems. - Verify and reject or warn about group/world-readable permissions before loading credentials.
- Preserve restrictive permissions whenever the file is rewritten.
- Apply equivalent access-control protections on Windows.
- Create the credential file atomically with owner-only mode
- Separate non-sensitive preferences from credentials so updating
privacy_notice_showndoes not rewrite a secret-bearing file. - Avoid storing IAM access and secret keys unless console synchronization is explicitly enabled by the user.
- Require a least-privileged IAM principal restricted to the usage-query action needed by the Skill.
- Ensure
config.jsonis excluded from source control, package publication, logs, support bundles, backups, and synchronization by default. - Add credential rotation guidance for users who suspect that the file has been exposed.
