{"record":{"id":"8ca20189ee37862f","repo":"withastro/astro","slug":"remoteimagenotallowed-8ca201","errorCode":"RemoteImageNotAllowed","errorMessage":"Remote image ${url} is not allowed by your image configuration.","messagePattern":"Remote image (.+?) is not allowed by your image configuration\\.","errorType":"exception","errorClass":"AstroError","httpStatus":null,"severity":"error","filePath":"packages/astro/src/assets/utils/remoteProbe.ts","lineNumber":47,"sourceCode":"\tconst allowlistConfig = imageConfig\n\t\t? {\n\t\t\t\tdomains: imageConfig.domains ?? [],\n\t\t\t\tremotePatterns: imageConfig.remotePatterns ?? [],\n\t\t\t}\n\t\t: undefined;\n\n\tif (!allowlistConfig) {\n\t\tconst parsedUrl = new URL(url);\n\t\tif (!['http:', 'https:'].includes(parsedUrl.protocol)) {\n\t\t\tthrow new AstroError({\n\t\t\t\t...AstroErrorData.FailedToFetchRemoteImageDimensions,\n\t\t\t\tmessage: AstroErrorData.FailedToFetchRemoteImageDimensions.message(url),\n\t\t\t});\n\t\t}\n\t}\n\n\tif (allowlistConfig && !isRemoteAllowed(url, allowlistConfig)) {\n\t\tthrow new AstroError({\n\t\t\t...AstroErrorData.RemoteImageNotAllowed,\n\t\t\tmessage: AstroErrorData.RemoteImageNotAllowed.message(url),\n\t\t});\n\t}\n\n\t// Start fetching the image with redirect validation\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetchWithRedirects({\n\t\t\turl,\n\t\t\tonMaxRedirectsExceeded: (u) =>\n\t\t\t\tnew AstroError({\n\t\t\t\t\t...AstroErrorData.FailedToFetchRemoteImageDimensions,\n\t\t\t\t\tmessage: AstroErrorData.FailedToFetchRemoteImageDimensions.message(u),\n\t\t\t\t}),\n\t\t\tonMissingLocationHeader: (_status, u) =>\n\t\t\t\tnew AstroError({\n\t\t\t\t\t...AstroErrorData.FailedToFetchRemoteImageDimensions,","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/withastro/astro/blob/52e6c34790cc8ac4e69e6135ace06049867e5c4a/packages/astro/src/assets/utils/remoteProbe.ts#L29-L65","documentation":"When your Astro config defines `image.domains` or `image.remotePatterns`, every remote image must match one of them before Astro will fetch it. `isRemoteAllowed(url, allowlistConfig)` returning false at remoteProbe.ts:47 throws RemoteImageNotAllowed — this is a deliberate SSRF/asset-hygiene guard, not a bug.","triggerScenarios":"`<Image src=\"https://cdn.partner.com/logo.png\" />` when cdn.partner.com is not listed; adding a new CDN or CMS media host without updating config; remotePatterns regex/protocol/host fields that do not match the actual URL (pattern written for http while image is https, or missing pathname glob).","commonSituations":"Migrating CMS image domains; staging vs production hosts both needing entries; writing a remotePattern that accidentally excludes the exact asset path; forgetting the config only affects remote (http) images.","solutions":["Add the host to `image.domains: ['cdn.partner.com']` in astro.config.mjs for a simple allowlist","Or add a matching `image.remotePatterns` entry with protocol/hostname/pathname fields covering the URL","Double-check pattern details: hostname must match exactly (or wildcard), pathname needs to match the asset path (default '/**' style globs), scheme must match"],"exampleFix":"// before (astro.config.mjs)\nimage: { domains: ['old-cdn.com'] }\n\n// after\nimage: {\n  domains: ['old-cdn.com', 'cdn.partner.com'],\n  remotePatterns: [{ protocol: 'https', hostname: '**.partner.com' }],\n}","handlingStrategy":"validation","validationCode":"// mirror Astro's allowlist check before using a remote image\nfunction isRemoteAllowed(url: string, cfg: { domains?: string[]; remotePatterns?: Array<{ protocol?: string; hostname: string | string[]; pathname?: string }> }): boolean {\n  try {\n    const u = new URL(url);\n    if (cfg.domains?.includes(u.hostname)) return true;\n    return (cfg.remotePatterns ?? []).some((p) => {\n      if (p.protocol && p.protocol !== u.protocol.replace(':', '')) return false;\n      const hostOk = Array.isArray(p.hostname) ? p.hostname.includes(u.hostname) : u.hostname === p.hostname || (p.hostname.startsWith('**.') && u.hostname.endsWith(p.hostname.slice(2)));\n      return hostOk;\n    });\n  } catch {\n    return false;\n  }\n}\nif (!isRemoteAllowed(src, imageConfig)) throw new Error(`Remote image not allowed: ${src}`);","typeGuard":null,"tryCatchPattern":"try {\n  const size = await inferRemoteSize(url, imageConfig);\n} catch (err) {\n  if (err instanceof AstroError && err.code === 'RemoteImageNotAllowed') {\n    // collect violations and report to content owners instead of failing the build cold\n    reportDisallowedImage(url);\n    return null;\n  }\n  throw err;\n}","preventionTips":["Keep image.domains/remotePatterns in sync with every CMS/CDN host you onboard","Add a CI link-checker that also asserts each remote image host is allowlisted"],"tags":["astro","images","remote","allowlist","security","configuration"],"backgroundTag":"image-domain-not-allowlisted","analyzedSha":"52e6c34790cc8ac4e69e6135ace06049867e5c4a","analyzedAt":"2026-08-18T18:48:03.901Z","contentChangedAt":"2026-08-18T18:48:03.901Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}