T09 · Insecure Skill Coding Practices
- Location
SKILL.md:48- Finding
API Server Binds to All Network Interfaces Without Documented Access Controls
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This TTS skill is mostly coherent documentation, but it asks users to run exposed voice-cloning services and mutable installs without enough scoping or safety guidance.
Review this skill before installing. Prefer loopback-only services, pin package/model/container versions or digests, avoid arbitrary URL and file:// reference audio, and only use voice cloning with explicit permission from the speaker. Treat uploaded voice samples as sensitive biometric data and confirm how they are retained or deleted.
SKILL.md:48API Server Binds to All Network Interfaces Without Documented Access Controls
SKILL.md:19Installation Instructions Retrieve Unpinned Executable Dependencies and Model Artifacts
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# Basic TTS
The skill explicitly documents voice-cloning behavior but provides no warning about consent, impersonation, or privacy risks. In a TTS skill, this materially increases misuse risk because users are guided to submit reference audio and generate cloned speech without any guardrails or policy cues.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
-d '{"input": "Streaming.", "stream": true, "response_format": "pcm"}' --no-buffer | play -t raw -r 44100 -e signed -b 16 -c 1 -
curl -X POST http://localhost:8091/v1/audio/speech/batch
-H "Content-Type: application/json"
-d '{"items": [{"input": "Sentence 1"}, {"input": "Sentence 2"}], "voice": "default"}'
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
import requests
resp = requests.post("http://localhost:8091/v1/audio/speech", json={
"input": "Hello.", "voice": "default",
"ref_audio": "https://...", "ref_text": "Reference text"
})
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
import requests
resp = requests.post("http://localhost:8091/v1/audio/speech", json={
"input": "Hello.", "voice": "default",
"ref_audio": "https://...", "ref_text": "Reference text"
})
Code issues a request to a loopback, link-local, or private-range host. This can reach internal services not meant to be exposed and is a common SSRF pivot.
import requests
resp = requests.post("http://localhost:8091/v1/audio/speech", json={
"input": "Hello.", "voice": "default",
"ref_audio": "https://...", "ref_text": "Reference text"
})
Allowing ref_audio to come from URL, base64, or file:// sources without warning or restriction creates privacy and local file access risk. If an implementation follows this interface naively, it may fetch attacker-controlled URLs or read local files, leading to SSRF, sensitive file exposure, or processing of private data without user awareness.
This markdown file documents uploading a voice sample and deleting a voice, including that uploaded data is persisted under the user's cache directory, but it does not provide any explicit warning about privacy implications, persistence, or the destructive nature of deletion. For markdown files, operations affecting user data or system state should include clear user-facing warnings.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
Upload:
curl -X POST http://localhost:8091/v1/audio/voices \
-F "audio_sample=@voice.wav" -F "consent=user_id" \
-F "name=my_voice" -F "ref_text=Transcript." -F "speaker_description=warm narrator"
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
import requests, json, base64, io, wave
with requests.post(..., json={..., "stream": True}, stream=True) as s:
chunks, fmt = [], None
for line in s.iter_lines(decode_unicode=True):
if not line or not line.startswith("data: ") or "[DONE]" in line: continue
The installation guide instructs users to pull a Docker image without pinning a specific tag or immutable digest, so the content retrieved can change over time. This creates a supply-chain risk: if the publisher account is compromised or the latest image is replaced with a malicious or broken build, users may run unreviewed code.
This docker run example executes the same unpinned image reference, which may resolve to whatever local or remote image currently matches fish-speech:webui. If users build or pull a different image under that tag, the command can run unexpected code with GPU access and mounted host directories, increasing supply-chain and host exposure risks.