T09 · Insecure Skill Coding Practices
- Location
fish_tts.py:31- Finding
Broad plaintext API-key discovery from shared Agent configuration
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This FishAudio TTS skill mostly matches its stated purpose, but it needs review because it automatically reads a shared TOOLS.md file for credentials and proxy settings before sending requests to a cloud API.
Review before installing. Prefer setting FISH_AUDIO_API_KEY explicitly and avoid storing secrets in a shared TOOLS.md file. Do not submit confidential, regulated, or internal text unless you are comfortable sending it to FishAudio, and consider pinning dependencies in a virtual environment.
fish_tts.py:31Broad plaintext API-key discovery from shared Agent configuration
SKILL.md:24Unpinned third-party dependency installation
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
if proxies:
print(f"Using proxy: {proxies['https']}")
response = requests.post(url, json=payload, headers=headers, proxies=proxies)
response.raise_for_status()
# Save the audio
The function explicitly accesses credentials from both an environment variable and a local workspace file, giving the skill credential-access capability beyond what is minimally necessary. In this context, environment-variable access alone is normal, but combining it with opportunistic secret discovery from TOOLS.md makes the behavior materially more dangerous because it broadens the set of secrets the skill may consume without clear consent.
}
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
The skill documentation instructs use of an external Python script that requires environment/API-key access, local file output, and network communication, but the skill declares no explicit tool scope or permissions. This creates an authorization and transparency gap: an agent or user may invoke capabilities beyond what is visibly declared, increasing the risk of secret exposure or unintended external communication.
The skill reads ~/.openclaw/workspace/TOOLS.md to discover proxy settings and API credentials, even though a TTS utility does not need to inspect an unrelated workspace notes file to function. This expands the skill's access to local sensitive data and can unintentionally harvest secrets or route traffic through attacker-controlled proxy settings embedded in that file.
The script silently searches TOOLS.md for lines resembling a FishAudio API key and uses any extracted value. Pulling credentials from a general-purpose local document without explicit user awareness creates a secret-discovery behavior that is unnecessary for the stated purpose and may cause accidental use or disclosure of credentials stored for other tools.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
voice_id = get_voice_id(voice_name)
# FishAudio API endpoint
url = "https://api.fish.audio/v1/tts"
headers = {
"Authorization": f"Bearer {api_key}",
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
if proxies:
print(f"Using proxy: {proxies['https']}")
response = requests.post(url, json=payload, headers=headers, proxies=proxies)
response.raise_for_status()
# Save the audio
The skill sends user-supplied text to api.fish.audio, but it does not clearly warn that all provided text leaves the local environment and is processed by an external service. In a skill context, users may pass sensitive prompts or internal content, so the lack of a prominent disclosure increases privacy and data-handling risk.
No suspicious patterns detected.