Skip to content

fix(sanitization): match onload case- and space-insensitively - #31417

Merged
ShaneK merged 2 commits into
ionic-team:mainfrom
chuhuangvio-itch:fix/sanitize-dom-string-onload-case-bypass
Sep 2, 2026
Merged

fix(sanitization): match onload case- and space-insensitively#31417
ShaneK merged 2 commits into
ionic-team:mainfrom
chuhuangvio-itch:fix/sanitize-dom-string-onload-case-bypass

Conversation

@chuhuangvio-itch

Copy link
Copy Markdown
Contributor

What is the current behavior?

sanitizeDOMString (core/src/utils/sanitization/index.ts) blocks untrusted HTML containing onload= before it reaches innerHTML, because onload can fire synchronously while the string is being parsed into the working document fragment — before the later attribute-allowlist pass runs. The check is a plain lowercase substring match (untrustedString.includes('onload=')), so it misses onLoad=, ONLOAD=, or onload = (whitespace before =) even though HTML parses all of those as the same event handler.

What is the new behavior?

  • Replaced the substring check with a case-insensitive regex that also tolerates whitespace around = (/onload\s*=/i), matching how HTML actually parses attribute names.
  • Added a test covering the case and whitespace variants.

Does this introduce a breaking change?

  • Yes
  • No

Other information

sanitizeDOMString is used by ion-toast, ion-loading, the ion-alert message, ion-refresher-content, and ion-infinite-scroll-content to sanitize developer-supplied HTML strings that may embed end-user input (e.g. another user's display name rendered in a toast/alert). This closes a gap where a payload like <svg onLoad=...> could bypass the intended guard and reach innerHTML unfiltered.

I didn't find an existing SECURITY.md or private vulnerability reporting channel enabled on this repo, so opening this directly as a PR with the fix rather than filing a separate public issue describing the bypass.

sanitizeDOMString blocked untrusted HTML that contains "onload="
before setting it via innerHTML, because onload can fire
synchronously while parsing into the detached document fragment,
ahead of the later attribute-allowlist pass.

The check used a plain lowercase substring match, so variants like
onLoad=, ONLOAD= or onload = (whitespace before the =) were not
caught, even though HTML parses them as the same event handler.
Use a case-insensitive regex that also tolerates whitespace around
the =.

Adds a test covering the case and whitespace variants.
@chuhuangvio-itch
chuhuangvio-itch requested a review from a team as a code owner September 1, 2026 14:30
@vercel

vercel Bot commented Sep 1, 2026

Copy link
Copy Markdown

@chuhuangvio-itch is attempting to deploy a commit to the Ionic Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions github-actions Bot added the package: core @ionic/core package label Sep 1, 2026
@ShaneK
ShaneK requested review from ShaneK and removed request for OS-jacobbell September 2, 2026 17:48
@ShaneK ShaneK added the type: bug a confirmed bug report label Sep 2, 2026
@vercel

vercel Bot commented Sep 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
ionic-framework Ready Ready Preview Sep 2, 2026 6:54pm UTC

Request Review

@ShaneK

ShaneK commented Sep 2, 2026

Copy link
Copy Markdown
Member

Hey @chuhuangvio-itch! Thanks for catching this, the fix looks right and we're going to merge it.

For next time, we do have a security policy with a private reporting channel, it's just inherited from the org so it shows up on our Security tab rather than as a SECURITY.md in the repo. Reports go to security@ionic.io.

I pushed a commit onto your branch with a few changes. The test payloads are nested now (<svg><svg onLoad=...>) because a top-level <svg onload> never actually fires, in Blink only a non-outermost one dispatches its load event during the innerHTML parse, so the original assertions weren't hitting the real vector. I also added a printIonWarning on the discard path since returning '' silently blanks the whole toast or alert message, and the broad match catches benign content like href="/docs?onload=1" too. The old comment said the event fired when appending to the fragment, which isn't quite the mechanism, so I reworded that as well.

Edit: This fix has been released in v9.0.2!

@ShaneK
ShaneK added this pull request to the merge queue Sep 2, 2026
Merged via the queue into ionic-team:main with commit ae7d44e Sep 2, 2026
55 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

package: core @ionic/core package type: bug a confirmed bug report

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants