Skip to content

Allow SVG pointer-events and vector-effect presentation attributes - #1567

Open
Jaybhade wants to merge 1 commit into
cure53:mainfrom
Jaybhade:allow-svg-pointer-events-vector-effect
Open

Allow SVG pointer-events and vector-effect presentation attributes#1567
Jaybhade wants to merge 1 commit into
cure53:mainfrom
Jaybhade:allow-svg-pointer-events-vector-effect

Conversation

@Jaybhade

@Jaybhade Jaybhade commented Aug 5, 2026

Copy link
Copy Markdown

Summary

This pull request adds the pointer-events and vector-effect SVG presentation attributes to the SVG attribute allow-list. Both are keyword-only presentation attributes, and both were being stripped from otherwise valid SVG.

DOMPurify.sanitize('<svg><rect pointer-events="none" width="10" height="10"/></svg>');
// before: <svg><rect width="10" height="10"></rect></svg>
// after:  <svg><rect pointer-events="none" width="10" height="10"></rect></svg>

DOMPurify.sanitize('<svg><circle vector-effect="non-scaling-stroke" cx="0" cy="0" r="30"/></svg>');
// before: <svg><circle cx="0" cy="0" r="30"></circle></svg>
// after:  <svg><circle vector-effect="non-scaling-stroke" cx="0" cy="0" r="30"></circle></svg>

Background & Context

The SVG list already allow-lists every other keyword-only rendering/interaction presentation attribute in this family — shape-rendering, image-rendering, text-rendering, color-rendering, paint-order, visibility, display, overflow, mask-type, and (since #1526) dominant-baseline and text-orientation. pointer-events and vector-effect are the two remaining Baseline-widely-available members of that group that were still missing, so this is a consistency gap rather than a new capability.

The practical symptom is silent visual breakage in generated SVG. vector-effect="non-scaling-stroke" is what keeps a stroke width constant under a transform; dropping it makes strokes scale with the shape. This was reported for Fabric.js output in #447 — that issue was closed by its reporter, who moved the property into style as a workaround, so the allow-list itself was never revisited. pointer-events="none" is the standard way to make an overlay non-interactive and is emitted routinely by charting libraries.

On the security side, neither attribute widens the attack surface:

  • Keyword-only, no URL or script surface. pointer-events takes bounding-box | visiblePainted | visibleFill | visibleStroke | visible | painted | fill | stroke | all | none; vector-effect takes none | non-scaling-stroke | non-scaling-size | non-rotation | fixed-position. Neither accepts a FuncIRI, a URL, or script.
  • Already reachable today. Both have CSS property counterparts, and style is allow-listed, so style="pointer-events:none" and style="vector-effect:non-scaling-stroke" already survive sanitization unchanged. This repository's own fixtures rely on that — the #137 SVG image payload in test/fixtures/expect.mjs carries vector-effect: non-scaling-stroke inside style, and the #33 payload carries pointer-events:none. Allowing the presentation-attribute form grants nothing that is not already permitted.
  • No URI-safe shortcut. Neither attribute is added to the URI-safe set, so values still pass through the normal IS_ALLOWED_URI screening rather than bypassing it.
  • Existing controls still apply. FORBID_ATTR: ['pointer-events'] still removes it, USE_PROFILES: { html: true } still drops the SVG element entirely, and event handlers and javascript: URLs on the same element are still stripped.

As with the other entries in ATTRS.svg, these names become allow-listed for HTML elements too under the default configuration — the same as fill, display, and visibility today. They remain inert CSS in that position.

Tasks

  • Add pointer-events and vector-effect to ATTRS.svg in src/attrs.ts, in their alphabetical positions
  • Add two fixtures to test/fixtures/expect.mjs covering both attributes, using the payload shape from Adding vector-effect to svg whitelist #447
  • Rebuild dist/ — the bundle diff is exactly the two added strings, with no other build drift
  • npm run lint (xo) passes clean
  • Full jsdom suite passes: 1208 assertions, 0 failures, including the two new fixtures

Dependencies

  • No dependencies on other PRs or API work

Both are keyword-only SVG presentation attributes but were missing from
the SVG attribute allow-list, so DOMPurify stripped e.g.
<rect pointer-events="none"> and <circle vector-effect="non-scaling-stroke">.

Their siblings in the same family are already allow-listed
(shape-rendering, image-rendering, text-rendering, color-rendering,
paint-order, visibility, display, overflow, mask-type), and both added
attributes are enum-only with no script or URL surface. The identical
styling is already reachable through the allow-listed style attribute,
so neither addition grants a capability DOMPurify does not already
permit.

Neither attribute is added to the URI-safe set, so values still go
through the regular IS_ALLOWED_URI screening.
@Jaybhade
Jaybhade requested a review from x00mario as a code owner August 5, 2026 16:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant