facebook/react · error · Error
React has blocked a javascript: URL as a security…
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.
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
AI-assisted analysis of facebook/react@eafeac097b (2026-08-21).
Data as JSON: /api/errors/a14260f54f4c553f.
Report an issue: GitHub.
Appendix: 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)