Any client-controlled URL (including OpenAI image_url) must be treated as SSRF-/DoS-/parsing-risk input and validated at every transition before connecting.
Apply this standard:
redirect: "manual"; for each hop, resolve + validate again and enforce a small maximum redirect count.content-type (and for data: URLs: enforce image/*, base64-only as required).postMessage, explicitly target the intended loopback origins (no *).Example pattern (server-side fetch):
async function safeFetchImageBytes(inputUrl: string) {
// 1) Parse + enforce strict outbound policy
let current = inputUrl;
for (let hop = 0; hop <= 3; hop++) {
const parsed = parseAndValidatePublicUrl(current); // strict scheme/host policy
// 2) DNS rebinding defense (reject if any IP answer is private)
// validateResolvedIps(parsed.hostname)
// 3) Manual redirect handling
const res = await fetch(parsed.toString(), { method: 'GET', redirect: 'manual' });
if (res.status >= 300 && res.status < 400 && res.headers.get('location')) {
current = new URL(res.headers.get('location')!, parsed).toString();
continue; // re-validate next hop
}
// 4) Verify content-type and read with a size cap
const ct = (res.headers.get('content-type') || '').toLowerCase();
if (!ct.startsWith('image/')) throw new Error('Image content-type required');
const data = await readCapped(res, 1 * 1024 * 1024);
return data;
}
throw new Error('Too many redirects');
}
Enter the URL of a public GitHub repository