facebook/react · error · Error
React has blocked a javascript: URL as a security precaution
Error message
React has blocked a javascript: URL as a security precaution.
What it means
sanitizeURL does not throw during rendering; when a URL attribute (href, src, action, formAction, ...) coerces to a string matching the javascript: protocol — including obfuscated forms with control characters, spaces, and whitespace embedded between the letters — React replaces the URL with javascript:throw new Error('React has blocked a javascript: URL as a security precaution.'). The actual Error is thrown in the browser only if that sanitized URL is ever activated (link clicked, form submitted, window opened), neutralizing XSS via URL attributes.
Source
Thrown at packages/react-dom-bindings/src/shared/sanitizeURL.js:29
// and any newline or tab are filtered out as if they're not part of the URL.
// https://url.spec.whatwg.org/#url-parsing
// Tab or newline are defined as \r\n\t:
// https://infra.spec.whatwg.org/#ascii-tab-or-newline
// A C0 control is a code point in the range \u0000 NULL to \u001F
// INFORMATION SEPARATOR ONE, inclusive:
// https://infra.spec.whatwg.org/#c0-control-or-space
const isJavaScriptProtocol =
/^[\u0000-\u001F ]*j[\r\n\t]*a[\r\n\t]*v[\r\n\t]*a[\r\n\t]*s[\r\n\t]*c[\r\n\t]*r[\r\n\t]*i[\r\n\t]*p[\r\n\t]*t[\r\n\t]*\:/i;
function sanitizeURL<T>(url: T): T | string {
// We should never have symbols here because they get filtered out elsewhere.
// eslint-disable-next-line react-internal/safe-string-coercion
if (isJavaScriptProtocol.test('' + (url as any))) {
// Return a different javascript: url that doesn't cause any side-effects and just
// throws if ever visited.
// eslint-disable-next-line no-script-url
return "javascript:throw new Error('React has blocked a javascript: URL as a security precaution.')";
}
return url;
}
export default sanitizeURL;
View on GitHub (pinned to eafeac097b)
Solutions
- Filter URLs at the source: allowlist schemes (http, https, mailto, tel, relative) before rendering user-supplied hrefs
- Use a sanitizer such as DOMPurify or isomorphic-url parsing to validate the protocol and reject non-http(s) links
- Replace javascript:void(0) placeholder hrefs with href="#" role/button semantics or a <button>
Example fix
// before
<a href={user.website}>Profile</a> // user.website = "javascript:alert(1)"
// after
const SAFE_URL = /^(https?:|mailto:|tel:|#|\/|\.\/)/i;
const href = SAFE_URL.test(user.website) ? user.website : '#';
<a href={href}>Profile</a> Defensive patterns
Strategy: validation
Validate before calling
const SAFE_HREF = /^(?:(?:https?|mailto|tel):|#|\/|\.\.?\/)/i;
function safeHref(url: string | null | undefined): string {
if (url == null) return '#';
const trimmed = url.trim();
return SAFE_HREF.test(trimmed) ? trimmed : '#';
}
// <a href={safeHref(user.website)}> Type guard
function isSafeUrl(url: string): boolean {
try {
const u = new URL(url, 'https://example.invalid');
return ['http:', 'https:', 'mailto:', 'tel:'].includes(u.protocol);
} catch {
return false;
}
} Try / catch
// The throw fires only in the browser if a sanitized URL is activated; catch it there for telemetry:
window.addEventListener('error', (e) => {
if (/React has blocked a javascript: URL/.test(String(e.message))) {
reportSecurityEvent('blocked-javascript-url', e.message);
}
}); Prevention
- Allowlist URL schemes at the data boundary for any user-supplied href/src/action
- Run SSR output through a security scan/CI check that greps for 'javascript:' in emitted HTML
- Prefer real buttons over javascript:void(0) link placeholders
When it happens
Trigger: Server-rendering href={`javascript:${code}`}, a link whose href comes from user/CMS content like <a href={user.website}> where user.website is 'javascript:alert(1)', or formAction/action/img src values that begin with javascript: after the leading-control/space prefix the regex allows for.
Common situations: Markdown or rich-text renderers emitting unfiltered URLs; user profile fields rendered as links; test/security scanners probing the sanitizer; accidentally shipping javascript:void(0) hrefs that get blocked in SSR output.
Related errors
- Invalid tag: ${tag}
- 61
- File/Blob fields are not yet supported in progressive forms.
- Can only set one of `children` or `props.dangerouslySetInner
- `props.dangerouslySetInnerHTML` must be in the form `{__html
AI-assisted analysis of facebook/react@eafeac097b (2026-08-21).
Data as JSON: /api/errors/a14260f54f4c553f.
Report an issue: GitHub.