T09 · Insecure Skill Coding Practices
- Location
scripts/build-html-lookbook.py:110- Finding
Arbitrary Remote Resource Fetching Enables Server-Side Request Forgery
- Content
View full analysis
0: return tmp = dst.with_suffix(".tmp") subprocess.run(["curl", "-sSL", "-o", str(tmp), src_url], check=True) img = Image.open(tmp).convert("RGB") h = round(w * 4 / 3) ratio = max(w / img.width, h / img.height) new = img.resize((round(img.width * ratio), round(img.height * ratio)), Image.LANCZOS) left = (new.width - w) // 2 top = (new.height - h) // 2 new.crop((left, top, left + w, top + h)).save(dst, "JPEG", quality=85, optimize=True) tmp.unlink() ``` ```python src_url = ((p0.get("try_on") or {}).get("url") or (p0.get("hero") or {}).get("url") or p0.get("image_url")) if not src_url: print(f"warn: no hero image for {look_id}", file=sys.stderr) continue dst = OUT / f"{look_id}.jpg" if not dst.exists(): tmp = dst.with_suffix(".tmp") subprocess.run(["curl", "-sSL", "-o", str(tmp), src_url], check=True) web_jpeg(tmp, dst, max_w=1200) tmp.unlink() ``` ### Technical Analysis The builder accepts image URLs from the caller-controlled picks JSON and passes them directly to `curl`. It does not validate: - The URL scheme - The destination hostname - The resolved IP address - Redirect destinations - Whether the address is loopback, link-local, private, or otherwise reserved - Response size or content type The use of a subprocess argument array prevents ordinary shell metacharacter injection, but it does not prevent SSRF. The `-L` option also causes redirects to be followed without validating the final destination. Because the downloaded response is subsequently processed by Pillow and may be incorporated into a generated deployment, the behavior creates ...[truncated 1432 chars]- Remediation
View remediation
