T09 · Insecure Skill Coding Practices
- Location
SKILL.md:31- Finding
Unrestricted URL Fetching Enables SSRF and External Disclosure of Sensitive Content
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 31-46 and 127-218
Vulnerability Type: Server-Side Request Forgery, local file access, and sensitive-data transmission
Risk Level: HighVulnerable Code
The source URL is passed directly to
curlwithout validating its scheme, destination, resolved IP address, port, or redirects:python def fetch_article_content(url): """Fetch article content using curl for reliability.""" # Use curl to get raw HTML - more reliable than web fetch tools result = subprocess.run( ["curl", "-s", url], capture_output=True, text=True ) html = result.stdout # Strip HTML tags (basic approach) import re text = re.sub(r'<script[^>]*>.*?</script>', '', html, flags=re.DOTALL) text = re.sub(r'<style[^>]*>.*?</style>', '', html, flags=re.DOTALL) text = re.sub(r'<[^>]+>', ' ', text) text = re.sub(r'\s+', ' ', text).strip() return textThe resulting content is subsequently transmitted to external TTS providers. For example, the OpenAI implementation sends every text chunk in the request body:
python def create_with_openai(text, output_path): """Generate audiobook using OpenAI TTS API.""" api_key = os.environ.get("OPENAI_API_KEY") chunks = chunk_text(text, max_chars=4000) audio_files = [] for i, chunk in enumerate(chunks): chunk_file = f"/tmp/chunk_{i:03d}.mp3" response = requests.post( "https://api.openai.com/v1/audio/speech", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }, json={ "model": "tts-1", "input": chunk, "voice": "onyx", "response_format": "mp3" } ) if ...[truncated 4236 chars]- Remediation
View remediation
Remediation Suggestions
- Accept only
httpsURLs and reject all other schemes. - Reject URLs containing embedded credentials, unexpected ports, malformed hosts, or ambiguous IP representations.
- Resolve the hostname before connecting and reject loopback, private, link-local, multicast, reserved, and unspecified IPv4 and IPv6 addresses.
- Repeat destination validation after every redirect to prevent redirect-based SSRF and DNS rebinding bypasses.
- Restrict
curlexplicitly, for example with--proto '=https'and--proto-redir '=https', or replace it with an HTTP client implementing equivalent controls. - Apply connection timeouts, total request timeouts, response-size limits, and maximum redirect counts.
- Consider an allowlist of approved content hosts where operationally feasible.
- Keep local-file and internal-network access unavailable to the content-fetching component through sandboxing and outbound network policy.
- Clearly disclose that all cloud TTS options, including gTTS, transmit the complete source text to an external provider.
- Require explicit user confirmation before transmitting local files, private URLs, authenticated content, or potentially confidential text.
- Offer an offline TTS option for sensitive content.
- Accept only
