T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/pokeinfo.py:303
- Finding
- Unrestricted Requests to API-Provided URLs## Vulnerability Details **File Location**: `scripts/pokeinfo.py:303-321`, `scripts/pokeinfo.py:323-330`, `scripts/pokeinfo.py:336-350`, `scripts/pokeinfo.py:404-406`, and `scripts/pokeinfo.py:444-455` **Vulnerability Type**: Server-Side Request Forgery and Unrestricted Resource Retrieval **Risk Level**: Medium ### Vulnerable Code ```python def get_localized_type_name(type_url, lang): """Get type name in specified language.""" try: type_data = fetch_url(type_url) for name_entry in type_data.get("names", []): if name_entry["language"]["name"] == lang: return name_entry["name"] except Exception: pass return None def get_localized_ability_name(ability_url, lang): """Get ability name in specified language.""" try: ability_data = fetch_url(ability_url) for name_entry in ability_data.get("names", []): if name_entry["language"]["name"] == lang: return name_entry["name"] except Exception: pass return None def download_cry(cry_url, output_path): """Download cry audio file.""" req = urllib.request.Request(cry_url, headers={ 'User-Agent': 'Mozilla/5.0 (compatible; Pokeinfo/1.0)' }) with urllib.request.urlopen(req, timeout=15) as response: with open(output_path, 'wb') as f: f.write(response.read()) ``` ```python for t_entry in data['types']: type_name = get_localized_type_name(t_entry['type']['url'], lang) if not type_name: type_name = t_entry['type']['name'].title() types.append(type_name) abilities = [] for a in data['abilities']: ability_name = get_localized_ability_name(a['ability']['url'], lang) if not ability_name: ability_name = a['ability']['name'].replace('-', ' ').title() ``` ```python cry_url = data['cries'].get('latest') if cry_url: lines.ap ...[truncated 3079 chars]
- Remediation
- ## Remediation Suggestions 1. Implement a centralized URL-validation function before every outbound request. 2. Permit only `https` URLs with an explicit allowlist of required PokéAPI-controlled hostnames, such as the API and approved static asset hosts. 3. Reject URLs containing credentials, fragments, unexpected ports, or unsupported schemes. 4. Resolve destination hostnames and reject loopback, private, link-local, multicast, reserved, and unspecified IP address ranges. 5. Validate every redirect destination rather than validating only the initial URL, or disable automatic redirects. 6. Apply separate allowlists for API metadata and cry assets. 7. Stream responses in bounded chunks and enforce strict maximum sizes for JSON and audio. 8. Verify `Content-Type` and reject unexpected content before parsing. 9. Validate downloaded audio structure and duration before passing it to native audio libraries. 10. Return a controlled error when validation fails rather than silently accepting an untrusted destination.
