URL policy: checkUrl
checkUrl is the URL-scheme policy every URL-valued attribute goes through during enforceProfile. It is exported so you can
apply the same judgement to your own values. It uses the platform URL parser, never regex: regex scheme checks are a
recurring bypass vector (control characters, tabs or newlines inside the scheme, mixed-case JaVaScRiPt:, leading whitespace),
and the WHATWG parser normalizes exactly what browsers’ own navigation does. A value it cannot get a scheme out of is blocked,
never treated as relative.
checkUrl(rawValue, allowedSchemes, base?)
Section titled “checkUrl(rawValue, allowedSchemes, base?)”import { checkUrl } from "@johnhenry/safe-fragment";
checkUrl("https://example.com/", ["relative", "https:"]); // { allowed: true, scheme: "https:" }checkUrl("/docs/page", ["relative", "https:"]); // { allowed: true, scheme: "relative" }checkUrl("javascript:alert(1)", ["relative", "https:"]); // { allowed: false, scheme: "javascript:" }| Parameter | Meaning |
|---|---|
rawValue |
An attribute value taken verbatim from markup. |
allowedSchemes |
Allowed schemes: the literal "relative" and/or schemes including the trailing colon ("https:", "mailto:"), matching URL#protocol. |
base |
The URL of the document the markup will be inserted into (document.baseURI). Optional. |
It returns a UrlCheckResult.
How a value is judged
Section titled “How a value is judged”- An empty (after trimming) value is
"relative". - If
new URL(value)succeeds with no base, the value is absolute and its.protocolis authoritative. This coversjavascript:,data:,vbscript:,file:,https:, including whitespace and control-character-obfuscated variants. - Otherwise it is resolved against a fixed probe base. If scheme and host are unchanged, the value carried neither: it is a
same-document path, query or fragment reference, judged against the
"relative"allowance. - A different host means an authority-bearing reference: protocol-relative
//host/xand its backslash variants (\\host,/\host). These inherit their scheme from the document, sobaseis used: on anhttp:page//evil.example/xis judged ashttp:, never assumedhttps:. They are never"relative". - When
baseis omitted a fixed HTTPS probe is used (for pure-function callers and tests). Whenbaseis supplied but is not a usable hierarchical URL (about:blank,data:, unparseable), an authority-bearing reference cannot be resolved and is rejected as"unparseable": fail closed. - Anything that fails to parse is rejected outright.
Defense in depth. A value that only becomes a disallowed scheme once whitespace, control and format characters are removed
(java script:, javascript​:) is also rejected, even though a browser’s parser would treat the original as a harmless
relative reference. That keeps the two engines in agreement.
Constants
Section titled “Constants”SAFE_DEFAULT_URL_SCHEMES: a frozen array,["relative", "https:", "mailto:"]. The conservative default shipped profiles use.RELATIVE_URL_SCHEME: the string"relative".
UrlCheckResult: { allowed: boolean; scheme: string }. scheme is the normalized scheme including its trailing colon,
"relative" for same-document URLs, or "unparseable". It is present even when allowed is false, for reporting.
registerProfile refuses javascript:, data:, vbscript:, file: and blob: as profile schemes, so checkUrl with a
registered profile’s urlSchemes never allows them.