T09 · Insecure Skill Coding Practices
Warning
- Location
- fish_tts.py:31
- Finding
- Broad plaintext API-key discovery from shared Agent configuration<![CDATA[ ## Vulnerability Details **File Location**: `fish_tts.py:31-49` **Related Documentation**: `SKILL.md:22-23` **Vulnerability Type**: Plaintext credential handling and imprecise secret selection **Risk Level**: Medium ### Vulnerable Code ```python def get_api_key(): """Get API key from environment variable or TOOLS.md""" api_key = os.environ.get('FISH_AUDIO_API_KEY') if api_key: return api_key # Try to read from TOOLS.md tools_path = os.path.expanduser('~/.openclaw/workspace/TOOLS.md') if os.path.exists(tools_path): with open(tools_path, 'r', encoding='utf-8') as f: content = f.read() # Look for FishAudio API key for line in content.split('\n'): if 'fish' in line.lower() and 'api' in line.lower() and 'key' in line.lower(): # Extract key after colon if ':' in line: candidate = line.split(':', 1)[1].strip() if candidate: return candidate return None ``` The documentation encourages this storage method: ```markdown 1. Get your API key from https://fish.audio/ 2. Add API key to your `TOOLS.md` or environment variable `FISH_AUDIO_API_KEY` ``` ### Technical Analysis The Skill reads the entire shared `~/.openclaw/workspace/TOOLS.md` file to locate a credential. It identifies the credential through a loose substring test requiring only the words `fish`, `api`, and `key` on the same line, then treats everything after the first colon as a Bearer token. This design has two security weaknesses: 1. It encourages storage of an API credential in a general-purpose plaintext Agent configuration file. 2. It may select an unintended value from a comment, example, malformed configuration entry, or attacker-controlled line. The selected value is subsequently placed in the HTTP `Authorization` header and sent to `https://api.fish.audio/v1/tts`. ...[truncated 1596 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove fallback credential discovery from `TOOLS.md`. 2. Accept credentials only through `FISH_AUDIO_API_KEY` or an operating-system-backed secret manager. 3. If configuration-file compatibility is essential, use a dedicated file with restrictive permissions and parse an exact field such as `FISH_AUDIO_API_KEY`, rather than applying substring matching. 4. Validate the credential format before placing it in an authorization header. 5. Document that input text and the FishAudio API credential are transmitted to the FishAudio cloud service. 6. Update `SKILL.md` so it no longer recommends storing API keys in a shared general-purpose configuration file. 7. Avoid recommending `--api-key` for routine use because command-line arguments may be visible to other local processes or retained in shell history. ]]>
