Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,25 @@ export class AttributesTests extends RenderTest {
this.assertStableNodes();
}

@test
'svg a[href] is marked as unsafe (sanitization is not namespace-dependent)'() {
// SVG-namespaced elements preserve their authored (lowercase) tag name, so
// `element.tagName` is `'a'` rather than the `'A'` an HTML anchor reports.
// URL sanitization must still apply, otherwise `<svg><a href>` is an XSS
// bypass for the same `javascript:` URLs that are blocked on `<a href>`.
this.render('<svg><a href="{{this.foo}}"></a></svg>', { foo: 'javascript:foo()' });
this.assertHTML('<svg><a href="unsafe:javascript:foo()"></a></svg>');
this.assertStableRerender();

this.rerender({ foo: 'http://foo.bar' });
this.assertHTML('<svg><a href="http://foo.bar"></a></svg>');
this.assertStableNodes();

this.rerender({ foo: 'javascript:foo()' });
this.assertHTML('<svg><a href="unsafe:javascript:foo()"></a></svg>');
this.assertStableNodes();
}

@test
'triple curlies in attribute position'() {
this.render('<div data-bar="bar" data-foo={{{this.rawString}}}>Hello</div>', {
Expand Down
9 changes: 8 additions & 1 deletion packages/@glimmer/runtime/lib/dom/sanitized-values.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,14 @@ function checkDataURI(tagName: Nullable<string>, attribute: string): boolean {
}

export function requiresSanitization(tagName: string, attribute: string): boolean {
return checkURI(tagName, attribute) || checkDataURI(tagName, attribute);
// `badTags`/`badTagsForDataURI` are listed in the uppercase form that HTML
// elements report from `tagName`. Elements in other namespaces (e.g. an SVG
// `<a href>`) preserve their authored case, so `element.tagName` is `'a'`
// rather than `'A'`. Normalize here so the build-time gate matches what
// `sanitizeAttributeValue` already does, and the URL sanitization control
// can't be bypassed simply by living in the SVG namespace.
const upperTagName = tagName.toUpperCase();
return checkURI(upperTagName, attribute) || checkDataURI(upperTagName, attribute);
}

interface NodeUrlParseResult {
Expand Down
Loading