T09 · Insecure Skill Coding Practices
- Location
scripts/pokeinfo.py:303- Finding
Unrestricted Requests to API-Provided URLs
- Content
View full analysis
Vulnerability Details
File Location:
scripts/pokeinfo.py:303-321,scripts/pokeinfo.py:323-330,scripts/pokeinfo.py:336-350,scripts/pokeinfo.py:404-406, andscripts/pokeinfo.py:444-455
Vulnerability Type: Server-Side Request Forgery and Unrestricted Resource Retrieval
Risk Level: MediumVulnerable 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
View remediation
Remediation Suggestions
- Implement a centralized URL-validation function before every outbound request.
- Permit only
httpsURLs with an explicit allowlist of required PokéAPI-controlled hostnames, such as the API and approved static asset hosts. - Reject URLs containing credentials, fragments, unexpected ports, or unsupported schemes.
- Resolve destination hostnames and reject loopback, private, link-local, multicast, reserved, and unspecified IP address ranges.
- Validate every redirect destination rather than validating only the initial URL, or disable automatic redirects.
- Apply separate allowlists for API metadata and cry assets.
- Stream responses in bounded chunks and enforce strict maximum sizes for JSON and audio.
- Verify
Content-Typeand reject unexpected content before parsing. - Validate downloaded audio structure and duration before passing it to native audio libraries.
- Return a controlled error when validation fails rather than silently accepting an untrusted destination.
