T09 · Insecure Skill Coding Practices
- Location
- scripts/setup.py:136
- Finding
- LLM API key is persisted in plaintext configuration<![CDATA[ ## Vulnerability Details **File Location**: `scripts/setup.py:136-146` and `scripts/setup.py:196-211` **Vulnerability Type**: Plaintext credential storage **Risk Level**: High ### Vulnerable Code ```python api_key = input(" API Key (留空使用环境变量 LLM_API_KEY): ").strip() base_url = input(" API Base URL [https://dashscope.aliyuncs.com/compatible-mode/v1]: ").strip() model = input(" 模型名称 [qwen-plus]: ").strip() llm_config = {} if api_key: llm_config["api_key"] = api_key os.environ["LLM_API_KEY"] = api_key if base_url: llm_config["base_url"] = base_url or "https://dashscope.aliyuncs.com/compatible-mode/v1" os.environ["LLM_API_BASE_URL"] = llm_config["base_url"] if model: llm_config["model"] = model or "qwen-plus" os.environ["LLM_MODEL"] = llm_config["model"] ``` ```python def save_config(sources, keywords, channels, llm_config): """保存所有配置""" CONFIG_DIR.mkdir(parents=True, exist_ok=True) with open(SOURCES_FILE, "w", encoding="utf-8") as f: json.dump(sources, f, ensure_ascii=False, indent=2) settings = { "keywords": keywords, "channels": channels, "llm": llm_config, "configured_at": __import__("datetime").datetime.now().isoformat(), "version": "1.0.0" } with open(SETTINGS_FILE, "w", encoding="utf-8") as f: json.dump(settings, f, ensure_ascii=False, indent=2) ``` ### Technical Analysis When a user enters an LLM API key, the setup routine places it in `llm_config`. The entire object is subsequently serialized into `config/settings.json`, resulting in unencrypted credential persistence inside the project directory. This persistence is unnecessary for the current implementation because `scripts/summarizer.py` reads the API key from `LLM_API_KEY` rather than loading it from `settings.json`. Consequently, the code creates credential exposure without providing functional persistence after the setup process exits. No restrictive file permis ...[truncated 1185 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Do not add `api_key` to `llm_config` or serialize it into `settings.json`. 2. Store only non-sensitive settings such as the model name and API base URL. 3. Continue reading the credential from `LLM_API_KEY`, or integrate an operating-system credential store. 4. If file-based secret storage is unavoidable, place it outside the project, restrict permissions to the owner, and clearly identify it as sensitive. 5. Add generated configuration and secret files to `.gitignore`. 6. On startup, detect legacy plaintext keys, migrate them to an approved secret store, and remove them from the JSON file. 7. Document the credential-handling and rotation requirements. ]]>
