T09 · Insecure Skill Coding Practices
- Location
- tech-library.md:4
- Finding
- Insecure Storage and Exposure of External AI API Credentials<![CDATA[ ## Vulnerability Details **File Locations**: - `tech-library.md`, lines 4, 10, 38, 56, and 73 - `call-guide.md`, lines 95 and 113 **Vulnerability Type**: Plaintext secret storage and command-line credential exposure **Risk Level**: Medium ### Evidence The configuration documentation states that the repository-local Markdown file contains API keys and is read at runtime: ```text This file contains sensitive information such as API keys. Do not commit it to a public repository. skill-factory reads this file at runtime to obtain AI service API configuration. ``` The same file provides fields intended to contain provider credentials: ```markdown | api_key | <your GPT-series API key> | | api_key | <your Gemini API key> | | api_key | <your Claude API key> | ``` The invocation guide instructs users to insert the credential directly into a command-line argument: ```bash curl -s <your API address>/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer <your API key>" \ -d '{ "model": "<model name>", "messages": [ {"role": "system", "content": "<system prompt>"}, {"role": "user", "content": "<user prompt>"} ], "max_tokens": 4096, "temperature": 0.7 }' ``` The response-processing example repeats the same credential-handling pattern: ```bash RESPONSE=$(curl -s -m 30 <your API address>/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer <your API key>" \ -d "${REQUEST_BODY}") ``` ### Technical Analysis The documented configuration workflow encourages users to place live API credentials in `tech-library.md`, a plaintext file inside the Skill directory. Although the file warns against public commits, the project does not prescribe an environment-variable mechanism, secret manager, ignored configuration file, restrictive permissions, or automated secret detection. A warning alone does not prevent the credential from entering source-control history ...[truncated 2257 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Remove live credentials from Markdown configuration** - Keep only variable names and non-sensitive examples in `tech-library.md`. - Load credentials from environment variables such as `OPENAI_API_KEY`, `GEMINI_API_KEY`, and `ANTHROPIC_API_KEY`. - Do not use real-looking example tokens. 2. **Use a secret manager for deployed environments** - Retrieve credentials from the platform's managed secret facility at runtime. - Limit secret access to the specific process or service identity that requires it. - Apply provider-side scopes, quotas, and endpoint restrictions where supported. 3. **Provide safe configuration templates** - Supply a `.env.example` containing empty variable assignments only. - Add `.env`, local secret files, and generated configuration files to `.gitignore`. - Clearly state that `.env.example` must never contain real values. 4. **Restrict local secret-file permissions** - If a local secret file is unavoidable, store it outside the Skill package. - Restrict it to the owning account, such as mode `0600` on applicable systems. - Avoid copying it into build contexts, archives, or diagnostic bundles. 5. **Reduce command-line exposure** - Read the token from a protected environment variable or secret source at runtime. - Avoid hardcoding substituted bearer tokens in shell scripts and command history. - Disable shell tracing around secret-bearing operations and redact authorization headers from logs. - Prefer an SDK or protected configuration mechanism that does not persist the token in scripts. 6. **Add preventive controls** - Enable secret scanning in pre-commit hooks and CI. - Reject commits containing recognized API-key patterns. - Document immediate revocation and rotation procedures. - Rotate any key that has already been stored in the project or exposed through logs or history. ]]>
