sveltejs/kit · error · Error

Cannot redirect to ${JSON.stringify(location)} with `{ exter

Error message

Cannot redirect to ${JSON.stringify(location)} with `{ external: true }`. The `javascript:` and `data:` protocols must be explicitly listed in the `external` allowlist (prod: 'Cannot redirect to external URL unless explicitly allowed')

What it means

Even with `{ external: true }`, SvelteKit blocks `javascript:` and `data:` URLs because redirecting to them is a code-injection/XSS vector. Such URLs can only be redirected to if they are explicitly listed in an `external` allowlist array, signaling deliberate intent.

Source

Thrown at packages/kit/src/exports/url.js:58

 * @param {{ external?: boolean | string[] }} [options]
 */
export function validate_redirect_location(location, options) {
	if (!is_external_location(location)) return;

	const external = options?.external;

	if (!external) {
		throw new Error(
			DEV
				? `Cannot redirect to external URL ${JSON.stringify(location)}. ` +
						'To redirect to an external URL, pass `{ external: true }` or an allowlist of permitted origins as the third argument to `redirect`'
				: 'Cannot redirect to external URL unless explicitly allowed'
		);
	}

	if (external === true) {
		if (is_javascript_location(location)) {
			throw new Error(
				DEV
					? `Cannot redirect to ${JSON.stringify(location)} with \`{ external: true }\`. ` +
							'The `javascript:` and `data:` protocols must be explicitly listed in the `external` allowlist'
					: 'Cannot redirect to external URL unless explicitly allowed'
			);
		}

		return;
	}

	if (Array.isArray(external)) {
		if (!external.some((allowed) => matches_external_allowlist_entry(location, allowed))) {
			throw new Error(
				DEV
					? `Cannot redirect to ${JSON.stringify(location)}: URL origin is not included in the \`external\` allowlist`
					: 'Cannot redirect to external URL unless explicitly allowed'
			);
		}

View on GitHub (pinned to 03f1687fe6)

Solutions

  1. Remove any `javascript:`/`data:` redirect targets — use regular `https://` or relative URLs.
  2. If genuinely required (rare), enumerate them in an allowlist: `redirect(302, loc, { external: ['javascript:myscheme'] })` (pattern: explicit allowed origins/schemes array).
  3. Sanitize input: reject or strip locations whose scheme is not `http:`/`https:` or a relative path.
  4. Treat any user path that produces these URLs as an attack attempt and fall back to a safe default redirect.

Example fix

// before
redirect(302, target, { external: true }); // target may be 'data:...'
// after
if (/^data:|^javascript:/i.test(target)) redirect(302, '/');
else redirect(302, target, { external: true });
Defensive patterns

Strategy: validation

Validate before calling

function isSafeRedirectTarget(loc) {
  if (/^(javascript|data):/i.test(loc)) return false;
  try { const u = new URL(loc, 'http://internal'); return !/^javascript:|^data:/i.test(u.protocol); }
  catch { return false; }
}
if (!isSafeRedirectTarget(target)) redirect(302, '/');

Type guard

const isWebUrl = (s) => {
  try { const u = new URL(s, 'http://internal'); return ['http:', 'https:'].includes(u.protocol); }
  catch { return false; }
};

Try / catch

try {
  redirect(302, target, { external: true });
} catch (e) {
  if (String(e.message).includes('javascript:') || String(e.message).includes('data:')) {
    redirect(302, '/');
  } else throw e;
}

Prevention

When it happens

Trigger: Calling `redirect(302, 'javascript:alert(1)', { external: true })` or `redirect(302, 'data:text/html,...', { external: true })` — `true` is not enough; only `external: ['javascript:...', 'data:...']` permits these schemes.

Common situations: Passing user-supplied URLs straight through with `external: true` in a test harness or admin tool; accidentally forwarding a `data:` URL captured from a form or query parameter.

Related errors


AI-assisted analysis of sveltejs/kit@03f1687fe6 (2026-09-02). Data as JSON: /api/errors/799bc7dfca56387b. Report an issue: GitHub.