T05 · Unauthorized Access and Privilege Escalation
- Location
scripts/md_to_png.py:143- Finding
Unrestricted Server-Side Request Forgery Through Markdown Image URLs
- Content
View full analysis
tuple[bytes, str]: req = Request( url, headers={ # Some servers require UA. "User-Agent": "md2img/1.0", "Accept": "image/*,*/*;q=0.8", }, ) with urlopen(req, timeout=timeout_s) as resp: data = resp.read() content_type = resp.headers.get("Content-Type") if content_type: # e.g. "image/png; charset=binary" => keep only mime part mime = content_type.split(";", 1)[0].strip() if mime: return data, mime # Fallback by URL extension ext = Path(url.split("?", 1)[0].split("#", 1)[0]).suffix if ext: mime, _ = mimetypes.guess_type(ext) if mime: return data, mime return data, "application/octet-stream" def _inline_src(src: str) -> str | None: if src.startswith("data:"): return src try: if src.startswith("http://") or src.startswith("https://"): data, mime = _fetch_http(src) ``` ### Technical Analysis Image URLs extracted from attacker-controlled Markdown are passed directly to `urlopen`. The implementation does not restrict destination hosts, resolve and validate destination addresses, prohibit redirects, or reject loopback, private, link-local, multicast, and reserved IP ranges. The `Accept` header does not provide a security boundary. A target can return arbitrary content regardless of that header. Moreover, automatic redirects can move a request from an apparently acceptable public URL to a prohibited internal destination unless every redirect is independently validated. ### Attack Path 1. An attacker supplies Markdown containing an image reference ...[truncated 1019 chars]- Remediation
View remediation
