{"id":"6fd45ea25985fa34","repo":"webpack/webpack","slug":"nexturl-href-doesn-t-match-the-alloweduris-poli","errorCode":null,"errorMessage":"${nextUrl.href} doesn't match the allowedUris policy after redirect. These URIs are allowed:\n${allowedUris.map((uri) => ` - ${uri}`).join(\"\\n\")}","messagePattern":"(.+?) doesn't match the allowedUris policy after redirect\\. These URIs are allowed:\n(.+?)`\\)\\.join\\(\"\\\\n\"\\)\\}","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/schemes/HttpUriPlugin.js","lineNumber":767,"sourceCode":"\t\t\t\t\t */\n\t\t\t\t\tconst validateRedirectLocation = (location, base) => {\n\t\t\t\t\t\t/** @type {URL} */\n\t\t\t\t\t\tlet nextUrl;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tnextUrl = new URL(location, base);\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t`Invalid redirect URL: ${sanitizeUrlForError(location)}`,\n\t\t\t\t\t\t\t\t{ cause: err }\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (nextUrl.protocol !== \"http:\" && nextUrl.protocol !== \"https:\") {\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t`Redirected URL uses disallowed protocol: ${sanitizeUrlForError(nextUrl.href)}`\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!isAllowed(nextUrl.href)) {\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t`${nextUrl.href} doesn't match the allowedUris policy after redirect. These URIs are allowed:\\n${allowedUris\n\t\t\t\t\t\t\t\t\t.map((uri) => ` - ${uri}`)\n\t\t\t\t\t\t\t\t\t.join(\"\\n\")}`\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn nextUrl.href;\n\t\t\t\t\t};\n\t\t\t\t\t/**\n\t\t\t\t\t * Processes the provided url.\n\t\t\t\t\t * @param {string} url URL\n\t\t\t\t\t * @param {string | null} integrity integrity\n\t\t\t\t\t * @param {(err: Error | null, resolveContentResult?: ResolveContentResult) => void} callback callback\n\t\t\t\t\t * @param {number=} redirectCount number of followed redirects\n\t\t\t\t\t */\n\t\t\t\t\tconst resolveContent = (\n\t\t\t\t\t\turl,\n\t\t\t\t\t\tintegrity,\n\t\t\t\t\t\tcallback,","sourceCodeStart":749,"sourceCodeEnd":785,"githubUrl":"https://github.com/webpack/webpack/blob/318421ea8ac81371f5171236a6efb63675576528/lib/schemes/HttpUriPlugin.js#L749-L785","documentation":"After a redirect resolves to a valid http/https URL, validateRedirectLocation runs `isAllowed(nextUrl.href)` and rejects if the new URL does not match the configured `allowedUris` policy (lib/schemes/HttpUriPlugin.js:766, isAllowed at :1059). Unlike the initial-request check, this catches hosts reachable only through a redirect chain.","triggerScenarios":"`experiments.buildHttp.allowedUris` lists `https://cdn.a.com/` but the requested module on `cdn.a.com` 302s to `https://cdn.b.com/...`. Each allowed entry can be a string prefix, a RegExp, or a function; none match the redirect target.","commonSituations":"CDN front-door redirects to a different backend domain not in allowedUris; a package host redirects to a signed S3 URL on a different bucket host; default allowedUris too narrow; forgot to register a mirror domain.","solutions":["Add the redirect target host to `experiments.buildHttp.allowedUris` (e.g. the S3 / backend CDN host).","Use a RegExp or function allow-list entry to cover signed-URL hosts whose paths vary.","Pin the final resolved URL in the lockfile so the redirect is not followed on subsequent builds.","Confirm the redirect target is genuinely trusted before widening the policy (it is a security boundary)."],"exampleFix":"// before\nexperiments: { buildHttp: { allowedUris: ['https://registry.example.com/'] } }\n// registry 302s to https://objects.example.com/pkg.tgz -> error\n\n// after\nexperiments: {\n  buildHttp: {\n    allowedUris: [\n      'https://registry.example.com/',\n      'https://objects.example.com/'\n    ]\n  }\n}","handlingStrategy":"validation","validationCode":"// Validate allowedUris covers known redirect targets before building\nfunction assertAllowedCoversRedirect(allowed, fromUrl, toUrl) {\n  const ok = allowed.some((a) => {\n    if (typeof a === 'string') return toUrl.startsWith(new URL(a).href);\n    if (typeof a === 'function') return a(toUrl);\n    return a.test(toUrl);\n  });\n  if (!ok) throw new Error(`allowedUris missing redirect target ${toUrl} (from ${fromUrl})`);\n}","typeGuard":null,"tryCatchPattern":"compiler.hooks.failed.tap('AllowedUrisGuard', (err) => {\n  if (/allowedUris policy after redirect/.test(err.message)) {\n    console.error('Add the redirect target host to experiments.buildHttp.allowedUris');\n  }\n});","preventionTips":["List every host a redirect chain can land on (CDN, S3, mirror) in allowedUris.","Use RegExp/function entries to cover signed-URL hosts with variable paths.","Pin final URLs in the lockfile to avoid repeated redirect policy evaluation."],"tags":["security","network","redirect","config","schemes","build-http","allowlist"],"analyzedSha":"318421ea8ac81371f5171236a6efb63675576528","analyzedAt":"2026-08-03T19:39:56.731Z","schemaVersion":2}