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:
- Source:
(inner, constant) DANGEROUS_SCHEMES :Set:.<string:>
Schemes that execute rather than locate.
Type:
- 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