T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/decode.py:20
- Finding
- Unrestricted URL Fetching Enables SSRF and Resource Exhaustion<![CDATA[ ## Vulnerability Details **File Locations**: - `scripts/decode.py:20-35` - `scripts/batch_decode.py:36-55` - `scripts/decode.js:29-51` - `scripts/batch_decode.js:35-52` **Vulnerability Type**: Server-Side Request Forgery and Unbounded Resource Consumption **Risk Level**: High ### Vulnerable Code Python single-image decoder: ```python def is_url(s: str) -> bool: return s.startswith("http://") or s.startswith("https://") def download_image(url: str) -> str: """Download an image into a temporary file and return its path.""" import urllib.request suffix = Path(url.split("?")[0]).suffix or ".png" tmp = tempfile.NamedTemporaryFile(delete=False, suffix=suffix) try: urllib.request.urlretrieve(url, tmp.name) except Exception as e: tmp.close() os.unlink(tmp.name) raise RuntimeError(f"Image download failed: {e}") tmp.close() return tmp.name ``` Python batch decoder: ```python def _is_url(s: str) -> bool: return s.startswith("http://") or s.startswith("https://") def _try_zxing(source: str) -> str | None: try: import zxingcpp from PIL import Image except ImportError: return None tmp_path = None try: if _is_url(source): import urllib.request suffix = Path(source.split("?")[0]).suffix or ".png" tmp = tempfile.NamedTemporaryFile(delete=False, suffix=suffix) urllib.request.urlretrieve(source, tmp.name) tmp.close() tmp_path = tmp.name img_path = tmp_path ``` Node.js single-image decoder: ```javascript function isUrl(s) { return s.startsWith("http://") || s.startsWith("https://"); } function downloadToTemp(url) { return new Promise((resolve, reject) => { const ext = path.extname(url.split("?")[0]) || ".png"; const tmp = path.join(os.tmpdir(), `qr_${Date.now()}${ext}`); const mod = url.startsWith("https") ? https : http; const file = fs. ...[truncated 3890 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Parse URLs with a standards-compliant URL parser and allow only explicitly supported schemes. 2. Prefer HTTPS and reject URLs containing embedded credentials. 3. Resolve the hostname before connecting and block: - Loopback ranges - RFC 1918 private ranges - IPv6 unique-local ranges - Link-local ranges - Multicast and reserved ranges - Known cloud metadata addresses 4. Repeat hostname and IP validation after every redirect to prevent redirect-based bypasses. 5. Limit the number of redirects, such as to three. 6. Add strict connection, response, and total-operation timeouts. 7. Stream responses while enforcing a conservative maximum byte count. 8. Reject non-2xx HTTP responses. 9. Validate the response content type and inspect file signatures before image decoding. 10. Configure Pillow and Sharp limits for image dimensions, pixel counts, and decompression-bomb detection. 11. Consider requiring explicit user confirmation before fetching URLs from batch files. 12. Where practical, require users to download remote images separately and pass a local file to the decoder. ]]>
