diff --git a/core/src/utils/sanitization/index.ts b/core/src/utils/sanitization/index.ts index bb851fea7e0..2ee633f4a6f 100644 --- a/core/src/utils/sanitization/index.ts +++ b/core/src/utils/sanitization/index.ts @@ -36,8 +36,12 @@ export const sanitizeDOMString = (untrustedString: IonicSafeString | string | un * fragment in Chrome. If a string * contains onload then we should not * attempt to add this to the fragment. + * + * HTML attribute names are case-insensitive and may have whitespace + * around the `=`, so match those variants too (e.g. `onLoad=`, + * `ONLOAD =`) instead of only the exact lowercase `onload=` substring. */ - if (untrustedString.includes('onload=')) { + if (/onload\s*=/i.test(untrustedString)) { return ''; } diff --git a/core/src/utils/sanitization/test/sanitization.spec.ts b/core/src/utils/sanitization/test/sanitization.spec.ts index 2ca069e387f..03c2abf7c48 100644 --- a/core/src/utils/sanitization/test/sanitization.spec.ts +++ b/core/src/utils/sanitization/test/sanitization.spec.ts @@ -26,6 +26,21 @@ describe('sanitizeDOMString', () => { ).toEqual(''); }); + it('filter onload regardless of case or whitespace around =', () => { + /** + * onload is blocked with an upfront string check (rather than the + * attribute-stripping pass used for onerror/onclick above) because it + * can fire synchronously while the untrusted string is being parsed + * into the working document fragment, before that pass runs. HTML + * attribute names are case-insensitive and may have whitespace around + * `=`, so the check must not be a plain lowercase substring match. + */ + expect(sanitizeDOMString('')).toEqual(''); + expect(sanitizeDOMString('')).toEqual(''); + expect(sanitizeDOMString('')).toEqual(''); + expect(sanitizeDOMString('')).toEqual(''); + }); + it('filter href JS', () => { expect(sanitizeDOMString('harmless link')).toEqual( 'harmless link'