Module: lib/core/security/urlPolicy

Refuses dangerous URL schemes in attributes that navigate or load.

The gap this closes

Interpolation escapes correctly: {{ value }} in a quoted attribute cannot break out of the quotes. What it cannot do is make the value safe, and for a URL-bearing attribute the value is the whole attack:

<a href="{{ link }}">…</a>      <!-- link = "javascript:steal()" -->

Nothing is escaped away, because nothing needs escaping — the string is a perfectly well-formed attribute value that happens to execute when clicked. Any application binding a user-supplied URL had a script-execution sink, and Avenx shipped a full Sanitizer that was never applied on this path.

The policy

Only the scheme is judged, and only for attributes whose value is fetched or navigated to. A relative URL, a fragment, a query, an absolute path and the ordinary schemes all pass untouched; javascript:, vbscript: and data: do not. data: is included because a data:text/html document navigated to from href executes in the page's origin.

The check is deliberately conservative about what it inspects. It is not a URL validator and does not rewrite anything: it either allows the value through unchanged or replaces it with a value that cannot navigate, and says so. Silently mangling a URL would be worse than either.

Source:

Members

(static, constant) REFUSED_URL :string

The value substituted for a refused URL.

about:blank rather than an empty string: an empty href resolves to the current document, so a refused link would silently reload the page instead of doing nothing.

Type:
  • string
Source:

(static, constant) URL_ATTRIBUTES :Set:.<string:>

Attributes whose value is navigated to or loaded.

src and href are the obvious ones. action and formaction submit to a URL; xlink:href is the SVG spelling of href and executes on click in exactly the same way; ping and data are fetched.

Type:
  • Set:.<string:>
Source:

(inner, constant) DANGEROUS_SCHEMES :Set:.<string:>

Schemes that execute rather than locate.

Type:
  • Set:.<string:>
Source:

(inner, constant) INERT_DATA_URL :RegExp

data: URLs that are inert in every context Avenx puts them in.

An image or a font cannot execute. Blocking data:image/png would break inline avatars and icons for no security gain, so the media types that cannot carry script are allowed through.

Type:
  • RegExp
Source:

Methods

(static) isSafeUrl(value) → {boolean}

Whether a URL is safe to place in a navigating attribute.

Parameters:
Name Type Description
value string

The attribute value.

Source:
Returns:

True when the URL may be used.

Type
boolean

(static) isUrlAttribute(name) → {boolean}

Whether an attribute's value is treated as a URL.

Parameters:
Name Type Description
name string

The attribute name.

Source:
Returns:

True when the attribute navigates or loads.

Type
boolean

(static) sanitizeUrlAttribute(name, value, contextopt) → {string}

Returns a URL safe for the given attribute, reporting a refusal.

Parameters:
Name Type Attributes Description
name string

The attribute name.

value string

The attribute value.

context object <optional>

Logging context.

Source:
Returns:

The original value, or REFUSED_URL.

Type
string

(static) schemeOf(value) → {string|null}

Extracts the scheme of a URL, if it has one.

Leading control characters and whitespace are stripped first: browsers ignore them when resolving a URL, so java\tscript:alert(1) navigates exactly as javascript:alert(1) does, and a check that did not strip them would be reading a different string than the browser.

Parameters:
Name Type Description
value string

The attribute value.

Source:
Returns:

The lowercased scheme, or null when the URL is relative.

Type
string | null