T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/config_manager.py:35
- Finding
- Plaintext API Credential Storage and Disclosure<![CDATA[ ## Vulnerability Details **File Location**: `scripts/config_manager.py:35-43, 68-77` **Vulnerability Type**: Plaintext secret storage and sensitive information exposure **Risk Level**: High ### Vulnerable Code ```python def save_config(key: str, secret: str) -> None: """将 key 和 secret 持久化写入 config.json。""" data = load_config() data["key"] = key.strip() data["secret"] = secret.strip() with open(CONFIG_PATH, "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False, indent=2) print(f"[OK] 配置已保存至: {CONFIG_PATH}") ``` ```python if args.command == "load": cfg = load_config() configured = is_configured(cfg) output = { "configured": configured, "key": cfg.get("key", ""), "secret": cfg.get("secret", ""), "config_path": CONFIG_PATH, } print(json.dumps(output, ensure_ascii=False, indent=2)) ``` ### Technical Analysis The credential manager writes the OCR API key and secret directly to `config.json` without encryption or explicit restrictive file permissions. The effective permissions therefore depend on the process umask and may allow other local users or processes to read the file. Credentials are also accepted through command-line arguments, as documented by the Skill, which can expose them through shell history, process inspection, command logging, or orchestration telemetry. The `load` command then prints both credentials verbatim to standard output. This unnecessarily increases the number of disclosure channels and exceeds the minimum access needed to verify whether the Skill is configured. No live credentials were embedded in the reviewed package; the shipped `config.json` contains empty values. ### Attack Path 1. A user runs the documented `save --key ... --secret ...` command. 2. The shell records the credentials in command history, or another local process observes the command-line arguments. 3. The manager writes the credentials to `config.json` using ...[truncated 625 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Do not print secrets from the `load` command. Return only a configuration status and, if necessary, a partially masked key. - Store credentials in an operating-system credential manager or secrets service rather than a project-local JSON file. - If file-based storage must be supported, create the file atomically with owner-only permissions such as `0600`, verify ownership and permissions before reading it, and reject insecure configurations. - Accept secrets through protected standard input or an interactive hidden prompt rather than command-line arguments. - Warn users not to place credential files under version control, shared folders, logs, or backups. - Add a migration routine that detects an existing permissive `config.json`, corrects its permissions, and advises credential rotation if exposure may have occurred. ]]>
