Bug 1850713: remove duplicated setting of early hint preloader id in `ScriptLoader...
[gecko.git] / dom / base / nsTreeSanitizer.cpp
blob602f6a22d9e3b924c64cfc600377bf6ca81c0d71
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsTreeSanitizer.h"
9 #include "mozilla/Algorithm.h"
10 #include "mozilla/ArrayUtils.h"
11 #include "mozilla/DeclarationBlock.h"
12 #include "mozilla/StaticPrefs_dom.h"
13 #include "mozilla/StyleSheetInlines.h"
14 #include "mozilla/UniquePtr.h"
15 #include "mozilla/dom/DocumentFragment.h"
16 #include "mozilla/dom/HTMLFormElement.h"
17 #include "mozilla/dom/HTMLTemplateElement.h"
18 #include "mozilla/dom/HTMLUnknownElement.h"
19 #include "mozilla/dom/Link.h"
20 #include "mozilla/dom/SanitizerBinding.h"
21 #include "mozilla/dom/ShadowIncludingTreeIterator.h"
22 #include "mozilla/dom/SRIMetadata.h"
23 #include "mozilla/NullPrincipal.h"
24 #include "nsAtom.h"
25 #include "nsCSSPropertyID.h"
26 #include "nsHashtablesFwd.h"
27 #include "nsString.h"
28 #include "nsTHashtable.h"
29 #include "nsUnicharInputStream.h"
30 #include "nsAttrName.h"
31 #include "nsIScriptError.h"
32 #include "nsIScriptSecurityManager.h"
33 #include "nsNameSpaceManager.h"
34 #include "nsNetUtil.h"
35 #include "nsComponentManagerUtils.h"
36 #include "nsContentUtils.h"
37 #include "nsIParserUtils.h"
38 #include "mozilla/dom/Document.h"
39 #include "nsQueryObject.h"
41 #include <iterator>
43 using namespace mozilla;
44 using namespace mozilla::dom;
47 // Thanks to Mark Pilgrim and Sam Ruby for the initial whitelist
49 const nsStaticAtom* const kElementsHTML[] = {
50 // clang-format off
51 nsGkAtoms::a,
52 nsGkAtoms::abbr,
53 nsGkAtoms::acronym,
54 nsGkAtoms::address,
55 nsGkAtoms::area,
56 nsGkAtoms::article,
57 nsGkAtoms::aside,
58 nsGkAtoms::audio,
59 nsGkAtoms::b,
60 nsGkAtoms::bdi,
61 nsGkAtoms::bdo,
62 nsGkAtoms::big,
63 nsGkAtoms::blockquote,
64 // body checked specially
65 nsGkAtoms::br,
66 nsGkAtoms::button,
67 nsGkAtoms::canvas,
68 nsGkAtoms::caption,
69 nsGkAtoms::center,
70 nsGkAtoms::cite,
71 nsGkAtoms::code,
72 nsGkAtoms::col,
73 nsGkAtoms::colgroup,
74 nsGkAtoms::data,
75 nsGkAtoms::datalist,
76 nsGkAtoms::dd,
77 nsGkAtoms::del,
78 nsGkAtoms::details,
79 nsGkAtoms::dfn,
80 nsGkAtoms::dialog,
81 nsGkAtoms::dir,
82 nsGkAtoms::div,
83 nsGkAtoms::dl,
84 nsGkAtoms::dt,
85 nsGkAtoms::em,
86 nsGkAtoms::fieldset,
87 nsGkAtoms::figcaption,
88 nsGkAtoms::figure,
89 nsGkAtoms::font,
90 nsGkAtoms::footer,
91 nsGkAtoms::form,
92 nsGkAtoms::h1,
93 nsGkAtoms::h2,
94 nsGkAtoms::h3,
95 nsGkAtoms::h4,
96 nsGkAtoms::h5,
97 nsGkAtoms::h6,
98 // head checked specially
99 nsGkAtoms::header,
100 nsGkAtoms::hgroup,
101 nsGkAtoms::hr,
102 // html checked specially
103 nsGkAtoms::i,
104 nsGkAtoms::img,
105 nsGkAtoms::input,
106 nsGkAtoms::ins,
107 nsGkAtoms::kbd,
108 nsGkAtoms::keygen,
109 nsGkAtoms::label,
110 nsGkAtoms::legend,
111 nsGkAtoms::li,
112 nsGkAtoms::link,
113 nsGkAtoms::listing,
114 nsGkAtoms::main,
115 nsGkAtoms::map,
116 nsGkAtoms::mark,
117 nsGkAtoms::menu,
118 nsGkAtoms::meta,
119 nsGkAtoms::meter,
120 nsGkAtoms::nav,
121 nsGkAtoms::nobr,
122 nsGkAtoms::noscript,
123 nsGkAtoms::ol,
124 nsGkAtoms::optgroup,
125 nsGkAtoms::option,
126 nsGkAtoms::output,
127 nsGkAtoms::p,
128 nsGkAtoms::picture,
129 nsGkAtoms::pre,
130 nsGkAtoms::progress,
131 nsGkAtoms::q,
132 nsGkAtoms::rb,
133 nsGkAtoms::rp,
134 nsGkAtoms::rt,
135 nsGkAtoms::rtc,
136 nsGkAtoms::ruby,
137 nsGkAtoms::s,
138 nsGkAtoms::samp,
139 nsGkAtoms::section,
140 nsGkAtoms::select,
141 nsGkAtoms::small,
142 nsGkAtoms::source,
143 nsGkAtoms::span,
144 nsGkAtoms::strike,
145 nsGkAtoms::strong,
146 nsGkAtoms::sub,
147 nsGkAtoms::summary,
148 nsGkAtoms::sup,
149 // style checked specially
150 nsGkAtoms::table,
151 nsGkAtoms::tbody,
152 nsGkAtoms::td,
153 // template checked and traversed specially
154 nsGkAtoms::textarea,
155 nsGkAtoms::tfoot,
156 nsGkAtoms::th,
157 nsGkAtoms::thead,
158 nsGkAtoms::time,
159 // title checked specially
160 nsGkAtoms::tr,
161 nsGkAtoms::track,
162 nsGkAtoms::tt,
163 nsGkAtoms::u,
164 nsGkAtoms::ul,
165 nsGkAtoms::var,
166 nsGkAtoms::video,
167 nsGkAtoms::wbr,
168 nullptr
169 // clang-format on
172 const nsStaticAtom* const kAttributesHTML[] = {
173 // clang-format off
174 nsGkAtoms::abbr,
175 nsGkAtoms::accept,
176 nsGkAtoms::acceptcharset,
177 nsGkAtoms::accesskey,
178 nsGkAtoms::action,
179 nsGkAtoms::alt,
180 nsGkAtoms::as,
181 nsGkAtoms::autocomplete,
182 nsGkAtoms::autofocus,
183 nsGkAtoms::autoplay,
184 nsGkAtoms::axis,
185 nsGkAtoms::_char,
186 nsGkAtoms::charoff,
187 nsGkAtoms::charset,
188 nsGkAtoms::checked,
189 nsGkAtoms::cite,
190 nsGkAtoms::_class,
191 nsGkAtoms::cols,
192 nsGkAtoms::colspan,
193 nsGkAtoms::content,
194 nsGkAtoms::contenteditable,
195 nsGkAtoms::contextmenu,
196 nsGkAtoms::controls,
197 nsGkAtoms::coords,
198 nsGkAtoms::crossorigin,
199 nsGkAtoms::datetime,
200 nsGkAtoms::dir,
201 nsGkAtoms::disabled,
202 nsGkAtoms::draggable,
203 nsGkAtoms::enctype,
204 nsGkAtoms::face,
205 nsGkAtoms::_for,
206 nsGkAtoms::frame,
207 nsGkAtoms::headers,
208 nsGkAtoms::height,
209 nsGkAtoms::hidden,
210 nsGkAtoms::high,
211 nsGkAtoms::href,
212 nsGkAtoms::hreflang,
213 nsGkAtoms::icon,
214 nsGkAtoms::id,
215 nsGkAtoms::integrity,
216 nsGkAtoms::ismap,
217 nsGkAtoms::itemid,
218 nsGkAtoms::itemprop,
219 nsGkAtoms::itemref,
220 nsGkAtoms::itemscope,
221 nsGkAtoms::itemtype,
222 nsGkAtoms::kind,
223 nsGkAtoms::label,
224 nsGkAtoms::lang,
225 nsGkAtoms::list_,
226 nsGkAtoms::longdesc,
227 nsGkAtoms::loop,
228 nsGkAtoms::low,
229 nsGkAtoms::max,
230 nsGkAtoms::maxlength,
231 nsGkAtoms::media,
232 nsGkAtoms::method,
233 nsGkAtoms::min,
234 nsGkAtoms::minlength,
235 nsGkAtoms::multiple,
236 nsGkAtoms::muted,
237 nsGkAtoms::name,
238 nsGkAtoms::nohref,
239 nsGkAtoms::novalidate,
240 nsGkAtoms::nowrap,
241 nsGkAtoms::open,
242 nsGkAtoms::optimum,
243 nsGkAtoms::pattern,
244 nsGkAtoms::placeholder,
245 nsGkAtoms::playbackrate,
246 nsGkAtoms::poster,
247 nsGkAtoms::preload,
248 nsGkAtoms::prompt,
249 nsGkAtoms::pubdate,
250 nsGkAtoms::radiogroup,
251 nsGkAtoms::readonly,
252 nsGkAtoms::rel,
253 nsGkAtoms::required,
254 nsGkAtoms::rev,
255 nsGkAtoms::reversed,
256 nsGkAtoms::role,
257 nsGkAtoms::rows,
258 nsGkAtoms::rowspan,
259 nsGkAtoms::rules,
260 nsGkAtoms::scoped,
261 nsGkAtoms::scope,
262 nsGkAtoms::selected,
263 nsGkAtoms::shape,
264 nsGkAtoms::span,
265 nsGkAtoms::spellcheck,
266 nsGkAtoms::src,
267 nsGkAtoms::srclang,
268 nsGkAtoms::start,
269 nsGkAtoms::summary,
270 nsGkAtoms::tabindex,
271 nsGkAtoms::target,
272 nsGkAtoms::title,
273 nsGkAtoms::type,
274 nsGkAtoms::usemap,
275 nsGkAtoms::value,
276 nsGkAtoms::width,
277 nsGkAtoms::wrap,
278 nullptr
279 // clang-format on
282 const nsStaticAtom* const kPresAttributesHTML[] = {
283 // clang-format off
284 nsGkAtoms::align,
285 nsGkAtoms::background,
286 nsGkAtoms::bgcolor,
287 nsGkAtoms::border,
288 nsGkAtoms::cellpadding,
289 nsGkAtoms::cellspacing,
290 nsGkAtoms::color,
291 nsGkAtoms::compact,
292 nsGkAtoms::clear,
293 nsGkAtoms::hspace,
294 nsGkAtoms::noshade,
295 nsGkAtoms::pointSize,
296 nsGkAtoms::size,
297 nsGkAtoms::valign,
298 nsGkAtoms::vspace,
299 nullptr
300 // clang-format on
303 // List of HTML attributes with URLs that the
304 // browser will fetch. Should be kept in sync with
305 // https://html.spec.whatwg.org/multipage/indices.html#attributes-3
306 const nsStaticAtom* const kURLAttributesHTML[] = {
307 // clang-format off
308 nsGkAtoms::action,
309 nsGkAtoms::href,
310 nsGkAtoms::src,
311 nsGkAtoms::longdesc,
312 nsGkAtoms::cite,
313 nsGkAtoms::background,
314 nsGkAtoms::formaction,
315 nsGkAtoms::data,
316 nsGkAtoms::ping,
317 nsGkAtoms::poster,
318 nullptr
319 // clang-format on
322 const nsStaticAtom* const kElementsSVG[] = {
323 nsGkAtoms::a, // a
324 nsGkAtoms::circle, // circle
325 nsGkAtoms::clipPath, // clipPath
326 nsGkAtoms::colorProfile, // color-profile
327 nsGkAtoms::cursor, // cursor
328 nsGkAtoms::defs, // defs
329 nsGkAtoms::desc, // desc
330 nsGkAtoms::ellipse, // ellipse
331 nsGkAtoms::elevation, // elevation
332 nsGkAtoms::erode, // erode
333 nsGkAtoms::ex, // ex
334 nsGkAtoms::exact, // exact
335 nsGkAtoms::exponent, // exponent
336 nsGkAtoms::feBlend, // feBlend
337 nsGkAtoms::feColorMatrix, // feColorMatrix
338 nsGkAtoms::feComponentTransfer, // feComponentTransfer
339 nsGkAtoms::feComposite, // feComposite
340 nsGkAtoms::feConvolveMatrix, // feConvolveMatrix
341 nsGkAtoms::feDiffuseLighting, // feDiffuseLighting
342 nsGkAtoms::feDisplacementMap, // feDisplacementMap
343 nsGkAtoms::feDistantLight, // feDistantLight
344 nsGkAtoms::feDropShadow, // feDropShadow
345 nsGkAtoms::feFlood, // feFlood
346 nsGkAtoms::feFuncA, // feFuncA
347 nsGkAtoms::feFuncB, // feFuncB
348 nsGkAtoms::feFuncG, // feFuncG
349 nsGkAtoms::feFuncR, // feFuncR
350 nsGkAtoms::feGaussianBlur, // feGaussianBlur
351 nsGkAtoms::feImage, // feImage
352 nsGkAtoms::feMerge, // feMerge
353 nsGkAtoms::feMergeNode, // feMergeNode
354 nsGkAtoms::feMorphology, // feMorphology
355 nsGkAtoms::feOffset, // feOffset
356 nsGkAtoms::fePointLight, // fePointLight
357 nsGkAtoms::feSpecularLighting, // feSpecularLighting
358 nsGkAtoms::feSpotLight, // feSpotLight
359 nsGkAtoms::feTile, // feTile
360 nsGkAtoms::feTurbulence, // feTurbulence
361 nsGkAtoms::filter, // filter
362 nsGkAtoms::font, // font
363 nsGkAtoms::font_face, // font-face
364 nsGkAtoms::font_face_format, // font-face-format
365 nsGkAtoms::font_face_name, // font-face-name
366 nsGkAtoms::font_face_src, // font-face-src
367 nsGkAtoms::font_face_uri, // font-face-uri
368 nsGkAtoms::foreignObject, // foreignObject
369 nsGkAtoms::g, // g
370 // glyph
371 nsGkAtoms::glyphRef, // glyphRef
372 // hkern
373 nsGkAtoms::image, // image
374 nsGkAtoms::line, // line
375 nsGkAtoms::linearGradient, // linearGradient
376 nsGkAtoms::marker, // marker
377 nsGkAtoms::mask, // mask
378 nsGkAtoms::metadata, // metadata
379 nsGkAtoms::missingGlyph, // missingGlyph
380 nsGkAtoms::mpath, // mpath
381 nsGkAtoms::path, // path
382 nsGkAtoms::pattern, // pattern
383 nsGkAtoms::polygon, // polygon
384 nsGkAtoms::polyline, // polyline
385 nsGkAtoms::radialGradient, // radialGradient
386 nsGkAtoms::rect, // rect
387 nsGkAtoms::stop, // stop
388 nsGkAtoms::svg, // svg
389 nsGkAtoms::svgSwitch, // switch
390 nsGkAtoms::symbol, // symbol
391 nsGkAtoms::text, // text
392 nsGkAtoms::textPath, // textPath
393 nsGkAtoms::title, // title
394 nsGkAtoms::tref, // tref
395 nsGkAtoms::tspan, // tspan
396 nsGkAtoms::use, // use
397 nsGkAtoms::view, // view
398 // vkern
399 nullptr};
401 constexpr const nsStaticAtom* const kAttributesSVG[] = {
402 // accent-height
403 nsGkAtoms::accumulate, // accumulate
404 nsGkAtoms::additive, // additive
405 nsGkAtoms::alignment_baseline, // alignment-baseline
406 // alphabetic
407 nsGkAtoms::amplitude, // amplitude
408 // arabic-form
409 // ascent
410 nsGkAtoms::attributeName, // attributeName
411 nsGkAtoms::attributeType, // attributeType
412 nsGkAtoms::azimuth, // azimuth
413 nsGkAtoms::baseFrequency, // baseFrequency
414 nsGkAtoms::baseline_shift, // baseline-shift
415 // baseProfile
416 // bbox
417 nsGkAtoms::begin, // begin
418 nsGkAtoms::bias, // bias
419 nsGkAtoms::by, // by
420 nsGkAtoms::calcMode, // calcMode
421 // cap-height
422 nsGkAtoms::_class, // class
423 nsGkAtoms::clip_path, // clip-path
424 nsGkAtoms::clip_rule, // clip-rule
425 nsGkAtoms::clipPathUnits, // clipPathUnits
426 nsGkAtoms::color, // color
427 nsGkAtoms::colorInterpolation, // color-interpolation
428 nsGkAtoms::colorInterpolationFilters, // color-interpolation-filters
429 nsGkAtoms::cursor, // cursor
430 nsGkAtoms::cx, // cx
431 nsGkAtoms::cy, // cy
432 nsGkAtoms::d, // d
433 // descent
434 nsGkAtoms::diffuseConstant, // diffuseConstant
435 nsGkAtoms::direction, // direction
436 nsGkAtoms::display, // display
437 nsGkAtoms::divisor, // divisor
438 nsGkAtoms::dominant_baseline, // dominant-baseline
439 nsGkAtoms::dur, // dur
440 nsGkAtoms::dx, // dx
441 nsGkAtoms::dy, // dy
442 nsGkAtoms::edgeMode, // edgeMode
443 nsGkAtoms::elevation, // elevation
444 // enable-background
445 nsGkAtoms::end, // end
446 nsGkAtoms::fill, // fill
447 nsGkAtoms::fill_opacity, // fill-opacity
448 nsGkAtoms::fill_rule, // fill-rule
449 nsGkAtoms::filter, // filter
450 nsGkAtoms::filterUnits, // filterUnits
451 nsGkAtoms::flood_color, // flood-color
452 nsGkAtoms::flood_opacity, // flood-opacity
453 // XXX focusable
454 nsGkAtoms::font, // font
455 nsGkAtoms::font_family, // font-family
456 nsGkAtoms::font_size, // font-size
457 nsGkAtoms::font_size_adjust, // font-size-adjust
458 nsGkAtoms::font_stretch, // font-stretch
459 nsGkAtoms::font_style, // font-style
460 nsGkAtoms::font_variant, // font-variant
461 nsGkAtoms::fontWeight, // font-weight
462 nsGkAtoms::format, // format
463 nsGkAtoms::from, // from
464 nsGkAtoms::fx, // fx
465 nsGkAtoms::fy, // fy
466 // g1
467 // g2
468 // glyph-name
469 // glyphRef
470 // glyph-orientation-horizontal
471 // glyph-orientation-vertical
472 nsGkAtoms::gradientTransform, // gradientTransform
473 nsGkAtoms::gradientUnits, // gradientUnits
474 nsGkAtoms::height, // height
475 nsGkAtoms::href,
476 // horiz-adv-x
477 // horiz-origin-x
478 // horiz-origin-y
479 nsGkAtoms::id, // id
480 // ideographic
481 nsGkAtoms::image_rendering, // image-rendering
482 nsGkAtoms::in, // in
483 nsGkAtoms::in2, // in2
484 nsGkAtoms::intercept, // intercept
485 // k
486 nsGkAtoms::k1, // k1
487 nsGkAtoms::k2, // k2
488 nsGkAtoms::k3, // k3
489 nsGkAtoms::k4, // k4
490 // kerning
491 nsGkAtoms::kernelMatrix, // kernelMatrix
492 nsGkAtoms::kernelUnitLength, // kernelUnitLength
493 nsGkAtoms::keyPoints, // keyPoints
494 nsGkAtoms::keySplines, // keySplines
495 nsGkAtoms::keyTimes, // keyTimes
496 nsGkAtoms::lang, // lang
497 // lengthAdjust
498 nsGkAtoms::letter_spacing, // letter-spacing
499 nsGkAtoms::lighting_color, // lighting-color
500 nsGkAtoms::limitingConeAngle, // limitingConeAngle
501 // local
502 nsGkAtoms::marker, // marker
503 nsGkAtoms::marker_end, // marker-end
504 nsGkAtoms::marker_mid, // marker-mid
505 nsGkAtoms::marker_start, // marker-start
506 nsGkAtoms::markerHeight, // markerHeight
507 nsGkAtoms::markerUnits, // markerUnits
508 nsGkAtoms::markerWidth, // markerWidth
509 nsGkAtoms::mask, // mask
510 nsGkAtoms::maskContentUnits, // maskContentUnits
511 nsGkAtoms::maskUnits, // maskUnits
512 // mathematical
513 nsGkAtoms::max, // max
514 nsGkAtoms::media, // media
515 nsGkAtoms::method, // method
516 nsGkAtoms::min, // min
517 nsGkAtoms::mode, // mode
518 nsGkAtoms::name, // name
519 nsGkAtoms::numOctaves, // numOctaves
520 nsGkAtoms::offset, // offset
521 nsGkAtoms::opacity, // opacity
522 nsGkAtoms::_operator, // operator
523 nsGkAtoms::order, // order
524 nsGkAtoms::orient, // orient
525 nsGkAtoms::orientation, // orientation
526 // origin
527 // overline-position
528 // overline-thickness
529 nsGkAtoms::overflow, // overflow
530 // panose-1
531 nsGkAtoms::path, // path
532 nsGkAtoms::pathLength, // pathLength
533 nsGkAtoms::patternContentUnits, // patternContentUnits
534 nsGkAtoms::patternTransform, // patternTransform
535 nsGkAtoms::patternUnits, // patternUnits
536 nsGkAtoms::pointer_events, // pointer-events XXX is this safe?
537 nsGkAtoms::points, // points
538 nsGkAtoms::pointsAtX, // pointsAtX
539 nsGkAtoms::pointsAtY, // pointsAtY
540 nsGkAtoms::pointsAtZ, // pointsAtZ
541 nsGkAtoms::preserveAlpha, // preserveAlpha
542 nsGkAtoms::preserveAspectRatio, // preserveAspectRatio
543 nsGkAtoms::primitiveUnits, // primitiveUnits
544 nsGkAtoms::r, // r
545 nsGkAtoms::radius, // radius
546 nsGkAtoms::refX, // refX
547 nsGkAtoms::refY, // refY
548 nsGkAtoms::repeatCount, // repeatCount
549 nsGkAtoms::repeatDur, // repeatDur
550 nsGkAtoms::requiredExtensions, // requiredExtensions
551 nsGkAtoms::requiredFeatures, // requiredFeatures
552 nsGkAtoms::restart, // restart
553 nsGkAtoms::result, // result
554 nsGkAtoms::rotate, // rotate
555 nsGkAtoms::rx, // rx
556 nsGkAtoms::ry, // ry
557 nsGkAtoms::scale, // scale
558 nsGkAtoms::seed, // seed
559 nsGkAtoms::shape_rendering, // shape-rendering
560 nsGkAtoms::slope, // slope
561 nsGkAtoms::spacing, // spacing
562 nsGkAtoms::specularConstant, // specularConstant
563 nsGkAtoms::specularExponent, // specularExponent
564 nsGkAtoms::spreadMethod, // spreadMethod
565 nsGkAtoms::startOffset, // startOffset
566 nsGkAtoms::stdDeviation, // stdDeviation
567 // stemh
568 // stemv
569 nsGkAtoms::stitchTiles, // stitchTiles
570 nsGkAtoms::stop_color, // stop-color
571 nsGkAtoms::stop_opacity, // stop-opacity
572 // strikethrough-position
573 // strikethrough-thickness
574 nsGkAtoms::string, // string
575 nsGkAtoms::stroke, // stroke
576 nsGkAtoms::stroke_dasharray, // stroke-dasharray
577 nsGkAtoms::stroke_dashoffset, // stroke-dashoffset
578 nsGkAtoms::stroke_linecap, // stroke-linecap
579 nsGkAtoms::stroke_linejoin, // stroke-linejoin
580 nsGkAtoms::stroke_miterlimit, // stroke-miterlimit
581 nsGkAtoms::stroke_opacity, // stroke-opacity
582 nsGkAtoms::stroke_width, // stroke-width
583 nsGkAtoms::surfaceScale, // surfaceScale
584 nsGkAtoms::systemLanguage, // systemLanguage
585 nsGkAtoms::tableValues, // tableValues
586 nsGkAtoms::target, // target
587 nsGkAtoms::targetX, // targetX
588 nsGkAtoms::targetY, // targetY
589 nsGkAtoms::text_anchor, // text-anchor
590 nsGkAtoms::text_decoration, // text-decoration
591 // textLength
592 nsGkAtoms::text_rendering, // text-rendering
593 nsGkAtoms::title, // title
594 nsGkAtoms::to, // to
595 nsGkAtoms::transform, // transform
596 nsGkAtoms::transform_origin, // transform-origin
597 nsGkAtoms::type, // type
598 // u1
599 // u2
600 // underline-position
601 // underline-thickness
602 // unicode
603 nsGkAtoms::unicode_bidi, // unicode-bidi
604 // unicode-range
605 // units-per-em
606 // v-alphabetic
607 // v-hanging
608 // v-ideographic
609 // v-mathematical
610 nsGkAtoms::values, // values
611 nsGkAtoms::vector_effect, // vector-effect
612 // vert-adv-y
613 // vert-origin-x
614 // vert-origin-y
615 nsGkAtoms::viewBox, // viewBox
616 nsGkAtoms::viewTarget, // viewTarget
617 nsGkAtoms::visibility, // visibility
618 nsGkAtoms::width, // width
619 // widths
620 nsGkAtoms::word_spacing, // word-spacing
621 nsGkAtoms::writing_mode, // writing-mode
622 nsGkAtoms::x, // x
623 // x-height
624 nsGkAtoms::x1, // x1
625 nsGkAtoms::x2, // x2
626 nsGkAtoms::xChannelSelector, // xChannelSelector
627 nsGkAtoms::y, // y
628 nsGkAtoms::y1, // y1
629 nsGkAtoms::y2, // y2
630 nsGkAtoms::yChannelSelector, // yChannelSelector
631 nsGkAtoms::z, // z
632 nsGkAtoms::zoomAndPan, // zoomAndPan
633 nullptr};
635 constexpr const nsStaticAtom* const kURLAttributesSVG[] = {nsGkAtoms::href,
636 nullptr};
638 static_assert(AllOf(std::begin(kURLAttributesSVG), std::end(kURLAttributesSVG),
639 [](auto aURLAttributeSVG) {
640 return AnyOf(std::begin(kAttributesSVG),
641 std::end(kAttributesSVG),
642 [&](auto aAttributeSVG) {
643 return aAttributeSVG == aURLAttributeSVG;
645 }));
647 const nsStaticAtom* const kElementsMathML[] = {
648 nsGkAtoms::abs_, // abs
649 nsGkAtoms::_and, // and
650 nsGkAtoms::annotation_, // annotation
651 nsGkAtoms::annotation_xml_, // annotation-xml
652 nsGkAtoms::apply_, // apply
653 nsGkAtoms::approx_, // approx
654 nsGkAtoms::arccos_, // arccos
655 nsGkAtoms::arccosh_, // arccosh
656 nsGkAtoms::arccot_, // arccot
657 nsGkAtoms::arccoth_, // arccoth
658 nsGkAtoms::arccsc_, // arccsc
659 nsGkAtoms::arccsch_, // arccsch
660 nsGkAtoms::arcsec_, // arcsec
661 nsGkAtoms::arcsech_, // arcsech
662 nsGkAtoms::arcsin_, // arcsin
663 nsGkAtoms::arcsinh_, // arcsinh
664 nsGkAtoms::arctan_, // arctan
665 nsGkAtoms::arctanh_, // arctanh
666 nsGkAtoms::arg_, // arg
667 nsGkAtoms::bind_, // bind
668 nsGkAtoms::bvar_, // bvar
669 nsGkAtoms::card_, // card
670 nsGkAtoms::cartesianproduct_, // cartesianproduct
671 nsGkAtoms::cbytes_, // cbytes
672 nsGkAtoms::ceiling, // ceiling
673 nsGkAtoms::cerror_, // cerror
674 nsGkAtoms::ci_, // ci
675 nsGkAtoms::cn_, // cn
676 nsGkAtoms::codomain_, // codomain
677 nsGkAtoms::complexes_, // complexes
678 nsGkAtoms::compose_, // compose
679 nsGkAtoms::condition_, // condition
680 nsGkAtoms::conjugate_, // conjugate
681 nsGkAtoms::cos_, // cos
682 nsGkAtoms::cosh_, // cosh
683 nsGkAtoms::cot_, // cot
684 nsGkAtoms::coth_, // coth
685 nsGkAtoms::cs_, // cs
686 nsGkAtoms::csc_, // csc
687 nsGkAtoms::csch_, // csch
688 nsGkAtoms::csymbol_, // csymbol
689 nsGkAtoms::curl_, // curl
690 nsGkAtoms::declare, // declare
691 nsGkAtoms::degree_, // degree
692 nsGkAtoms::determinant_, // determinant
693 nsGkAtoms::diff_, // diff
694 nsGkAtoms::divergence_, // divergence
695 nsGkAtoms::divide_, // divide
696 nsGkAtoms::domain_, // domain
697 nsGkAtoms::domainofapplication_, // domainofapplication
698 nsGkAtoms::el, // el
699 nsGkAtoms::emptyset_, // emptyset
700 nsGkAtoms::eq_, // eq
701 nsGkAtoms::equivalent_, // equivalent
702 nsGkAtoms::eulergamma_, // eulergamma
703 nsGkAtoms::exists_, // exists
704 nsGkAtoms::exp_, // exp
705 nsGkAtoms::exponentiale_, // exponentiale
706 nsGkAtoms::factorial_, // factorial
707 nsGkAtoms::factorof_, // factorof
708 nsGkAtoms::_false, // false
709 nsGkAtoms::floor, // floor
710 nsGkAtoms::fn_, // fn
711 nsGkAtoms::forall_, // forall
712 nsGkAtoms::gcd_, // gcd
713 nsGkAtoms::geq_, // geq
714 nsGkAtoms::grad, // grad
715 nsGkAtoms::gt_, // gt
716 nsGkAtoms::ident_, // ident
717 nsGkAtoms::image, // image
718 nsGkAtoms::imaginary_, // imaginary
719 nsGkAtoms::imaginaryi_, // imaginaryi
720 nsGkAtoms::implies_, // implies
721 nsGkAtoms::in, // in
722 nsGkAtoms::infinity, // infinity
723 nsGkAtoms::int_, // int
724 nsGkAtoms::integers_, // integers
725 nsGkAtoms::intersect_, // intersect
726 nsGkAtoms::interval_, // interval
727 nsGkAtoms::inverse_, // inverse
728 nsGkAtoms::lambda_, // lambda
729 nsGkAtoms::laplacian_, // laplacian
730 nsGkAtoms::lcm_, // lcm
731 nsGkAtoms::leq_, // leq
732 nsGkAtoms::limit_, // limit
733 nsGkAtoms::list_, // list
734 nsGkAtoms::ln_, // ln
735 nsGkAtoms::log_, // log
736 nsGkAtoms::logbase_, // logbase
737 nsGkAtoms::lowlimit_, // lowlimit
738 nsGkAtoms::lt_, // lt
739 nsGkAtoms::maction_, // maction
740 nsGkAtoms::maligngroup_, // maligngroup
741 nsGkAtoms::malignmark_, // malignmark
742 nsGkAtoms::math, // math
743 nsGkAtoms::matrix, // matrix
744 nsGkAtoms::matrixrow_, // matrixrow
745 nsGkAtoms::max, // max
746 nsGkAtoms::mean_, // mean
747 nsGkAtoms::median_, // median
748 nsGkAtoms::menclose_, // menclose
749 nsGkAtoms::merror_, // merror
750 nsGkAtoms::mfrac_, // mfrac
751 nsGkAtoms::mglyph_, // mglyph
752 nsGkAtoms::mi_, // mi
753 nsGkAtoms::min, // min
754 nsGkAtoms::minus_, // minus
755 nsGkAtoms::mlabeledtr_, // mlabeledtr
756 nsGkAtoms::mlongdiv_, // mlongdiv
757 nsGkAtoms::mmultiscripts_, // mmultiscripts
758 nsGkAtoms::mn_, // mn
759 nsGkAtoms::mo_, // mo
760 nsGkAtoms::mode, // mode
761 nsGkAtoms::moment_, // moment
762 nsGkAtoms::momentabout_, // momentabout
763 nsGkAtoms::mover_, // mover
764 nsGkAtoms::mpadded_, // mpadded
765 nsGkAtoms::mphantom_, // mphantom
766 nsGkAtoms::mprescripts_, // mprescripts
767 nsGkAtoms::mroot_, // mroot
768 nsGkAtoms::mrow_, // mrow
769 nsGkAtoms::ms_, // ms
770 nsGkAtoms::mscarries_, // mscarries
771 nsGkAtoms::mscarry_, // mscarry
772 nsGkAtoms::msgroup_, // msgroup
773 nsGkAtoms::msline_, // msline
774 nsGkAtoms::mspace_, // mspace
775 nsGkAtoms::msqrt_, // msqrt
776 nsGkAtoms::msrow_, // msrow
777 nsGkAtoms::mstack_, // mstack
778 nsGkAtoms::mstyle_, // mstyle
779 nsGkAtoms::msub_, // msub
780 nsGkAtoms::msubsup_, // msubsup
781 nsGkAtoms::msup_, // msup
782 nsGkAtoms::mtable_, // mtable
783 nsGkAtoms::mtd_, // mtd
784 nsGkAtoms::mtext_, // mtext
785 nsGkAtoms::mtr_, // mtr
786 nsGkAtoms::munder_, // munder
787 nsGkAtoms::munderover_, // munderover
788 nsGkAtoms::naturalnumbers_, // naturalnumbers
789 nsGkAtoms::neq_, // neq
790 nsGkAtoms::none, // none
791 nsGkAtoms::_not, // not
792 nsGkAtoms::notanumber_, // notanumber
793 nsGkAtoms::note_, // note
794 nsGkAtoms::notin_, // notin
795 nsGkAtoms::notprsubset_, // notprsubset
796 nsGkAtoms::notsubset_, // notsubset
797 nsGkAtoms::_or, // or
798 nsGkAtoms::otherwise, // otherwise
799 nsGkAtoms::outerproduct_, // outerproduct
800 nsGkAtoms::partialdiff_, // partialdiff
801 nsGkAtoms::pi_, // pi
802 nsGkAtoms::piece_, // piece
803 nsGkAtoms::piecewise_, // piecewise
804 nsGkAtoms::plus_, // plus
805 nsGkAtoms::power_, // power
806 nsGkAtoms::primes_, // primes
807 nsGkAtoms::product_, // product
808 nsGkAtoms::prsubset_, // prsubset
809 nsGkAtoms::quotient_, // quotient
810 nsGkAtoms::rationals_, // rationals
811 nsGkAtoms::real_, // real
812 nsGkAtoms::reals_, // reals
813 nsGkAtoms::reln_, // reln
814 nsGkAtoms::rem, // rem
815 nsGkAtoms::root_, // root
816 nsGkAtoms::scalarproduct_, // scalarproduct
817 nsGkAtoms::sdev_, // sdev
818 nsGkAtoms::sec_, // sec
819 nsGkAtoms::sech_, // sech
820 nsGkAtoms::selector_, // selector
821 nsGkAtoms::semantics_, // semantics
822 nsGkAtoms::sep_, // sep
823 nsGkAtoms::set, // set
824 nsGkAtoms::setdiff_, // setdiff
825 nsGkAtoms::share_, // share
826 nsGkAtoms::sin_, // sin
827 nsGkAtoms::sinh_, // sinh
828 nsGkAtoms::subset_, // subset
829 nsGkAtoms::sum, // sum
830 nsGkAtoms::tan_, // tan
831 nsGkAtoms::tanh_, // tanh
832 nsGkAtoms::tendsto_, // tendsto
833 nsGkAtoms::times_, // times
834 nsGkAtoms::transpose_, // transpose
835 nsGkAtoms::_true, // true
836 nsGkAtoms::union_, // union
837 nsGkAtoms::uplimit_, // uplimit
838 nsGkAtoms::variance_, // variance
839 nsGkAtoms::vector_, // vector
840 nsGkAtoms::vectorproduct_, // vectorproduct
841 nsGkAtoms::xor_, // xor
842 nullptr};
844 const nsStaticAtom* const kAttributesMathML[] = {
845 nsGkAtoms::accent_, // accent
846 nsGkAtoms::accentunder_, // accentunder
847 nsGkAtoms::actiontype_, // actiontype
848 nsGkAtoms::align, // align
849 nsGkAtoms::alignmentscope_, // alignmentscope
850 nsGkAtoms::alt, // alt
851 nsGkAtoms::altimg_, // altimg
852 nsGkAtoms::altimg_height_, // altimg-height
853 nsGkAtoms::altimg_valign_, // altimg-valign
854 nsGkAtoms::altimg_width_, // altimg-width
855 nsGkAtoms::background, // background
856 nsGkAtoms::base, // base
857 nsGkAtoms::bevelled_, // bevelled
858 nsGkAtoms::cd_, // cd
859 nsGkAtoms::cdgroup_, // cdgroup
860 nsGkAtoms::charalign_, // charalign
861 nsGkAtoms::close, // close
862 nsGkAtoms::closure_, // closure
863 nsGkAtoms::color, // color
864 nsGkAtoms::columnalign_, // columnalign
865 nsGkAtoms::columnalignment_, // columnalignment
866 nsGkAtoms::columnlines_, // columnlines
867 nsGkAtoms::columnspacing_, // columnspacing
868 nsGkAtoms::columnspan_, // columnspan
869 nsGkAtoms::columnwidth_, // columnwidth
870 nsGkAtoms::crossout_, // crossout
871 nsGkAtoms::decimalpoint_, // decimalpoint
872 nsGkAtoms::definitionURL_, // definitionURL
873 nsGkAtoms::denomalign_, // denomalign
874 nsGkAtoms::depth_, // depth
875 nsGkAtoms::dir, // dir
876 nsGkAtoms::display, // display
877 nsGkAtoms::displaystyle_, // displaystyle
878 nsGkAtoms::edge_, // edge
879 nsGkAtoms::encoding, // encoding
880 nsGkAtoms::equalcolumns_, // equalcolumns
881 nsGkAtoms::equalrows_, // equalrows
882 nsGkAtoms::fence_, // fence
883 nsGkAtoms::fontfamily_, // fontfamily
884 nsGkAtoms::fontsize_, // fontsize
885 nsGkAtoms::fontstyle_, // fontstyle
886 nsGkAtoms::fontweight_, // fontweight
887 nsGkAtoms::form, // form
888 nsGkAtoms::frame, // frame
889 nsGkAtoms::framespacing_, // framespacing
890 nsGkAtoms::groupalign_, // groupalign
891 nsGkAtoms::height, // height
892 nsGkAtoms::href, // href
893 nsGkAtoms::id, // id
894 nsGkAtoms::indentalign_, // indentalign
895 nsGkAtoms::indentalignfirst_, // indentalignfirst
896 nsGkAtoms::indentalignlast_, // indentalignlast
897 nsGkAtoms::indentshift_, // indentshift
898 nsGkAtoms::indentshiftfirst_, // indentshiftfirst
899 nsGkAtoms::indenttarget_, // indenttarget
900 nsGkAtoms::index, // index
901 nsGkAtoms::integer, // integer
902 nsGkAtoms::largeop_, // largeop
903 nsGkAtoms::length, // length
904 nsGkAtoms::linebreak_, // linebreak
905 nsGkAtoms::linebreakmultchar_, // linebreakmultchar
906 nsGkAtoms::linebreakstyle_, // linebreakstyle
907 nsGkAtoms::linethickness_, // linethickness
908 nsGkAtoms::location_, // location
909 nsGkAtoms::longdivstyle_, // longdivstyle
910 nsGkAtoms::lquote_, // lquote
911 nsGkAtoms::lspace_, // lspace
912 nsGkAtoms::ltr, // ltr
913 nsGkAtoms::mathbackground_, // mathbackground
914 nsGkAtoms::mathcolor_, // mathcolor
915 nsGkAtoms::mathsize_, // mathsize
916 nsGkAtoms::mathvariant_, // mathvariant
917 nsGkAtoms::maxsize_, // maxsize
918 nsGkAtoms::minlabelspacing_, // minlabelspacing
919 nsGkAtoms::minsize_, // minsize
920 nsGkAtoms::movablelimits_, // movablelimits
921 nsGkAtoms::msgroup_, // msgroup
922 nsGkAtoms::name, // name
923 nsGkAtoms::newline, // newline
924 nsGkAtoms::notation_, // notation
925 nsGkAtoms::numalign_, // numalign
926 nsGkAtoms::number, // number
927 nsGkAtoms::open, // open
928 nsGkAtoms::order, // order
929 nsGkAtoms::other, // other
930 nsGkAtoms::overflow, // overflow
931 nsGkAtoms::position, // position
932 nsGkAtoms::role, // role
933 nsGkAtoms::rowalign_, // rowalign
934 nsGkAtoms::rowlines_, // rowlines
935 nsGkAtoms::rowspacing_, // rowspacing
936 nsGkAtoms::rowspan, // rowspan
937 nsGkAtoms::rquote_, // rquote
938 nsGkAtoms::rspace_, // rspace
939 nsGkAtoms::schemaLocation_, // schemaLocation
940 nsGkAtoms::scriptlevel_, // scriptlevel
941 nsGkAtoms::scriptminsize_, // scriptminsize
942 nsGkAtoms::scriptsize_, // scriptsize
943 nsGkAtoms::scriptsizemultiplier_, // scriptsizemultiplier
944 nsGkAtoms::selection_, // selection
945 nsGkAtoms::separator_, // separator
946 nsGkAtoms::separators_, // separators
947 nsGkAtoms::shift_, // shift
948 nsGkAtoms::side_, // side
949 nsGkAtoms::src, // src
950 nsGkAtoms::stackalign_, // stackalign
951 nsGkAtoms::stretchy_, // stretchy
952 nsGkAtoms::subscriptshift_, // subscriptshift
953 nsGkAtoms::superscriptshift_, // superscriptshift
954 nsGkAtoms::symmetric_, // symmetric
955 nsGkAtoms::type, // type
956 nsGkAtoms::voffset_, // voffset
957 nsGkAtoms::width, // width
958 nsGkAtoms::xref_, // xref
959 nullptr};
961 const nsStaticAtom* const kURLAttributesMathML[] = {
962 // clang-format off
963 nsGkAtoms::href,
964 nsGkAtoms::src,
965 nsGkAtoms::cdgroup_,
966 nsGkAtoms::altimg_,
967 nsGkAtoms::definitionURL_,
968 nullptr
969 // clang-format on
972 // https://wicg.github.io/sanitizer-api/#baseline-attribute-allow-list
973 constexpr const nsStaticAtom* const kBaselineAttributeAllowlist[] = {
974 // clang-format off
975 nsGkAtoms::abbr,
976 nsGkAtoms::accept,
977 nsGkAtoms::acceptcharset,
978 nsGkAtoms::charset,
979 nsGkAtoms::accesskey,
980 nsGkAtoms::action,
981 nsGkAtoms::align,
982 nsGkAtoms::alink,
983 nsGkAtoms::allow,
984 nsGkAtoms::allowfullscreen,
985 // nsGkAtoms::allowpaymentrequest,
986 nsGkAtoms::alt,
987 nsGkAtoms::anchor,
988 nsGkAtoms::archive,
989 nsGkAtoms::as,
990 nsGkAtoms::async,
991 nsGkAtoms::autocapitalize,
992 nsGkAtoms::autocomplete,
993 // nsGkAtoms::autocorrect,
994 nsGkAtoms::autofocus,
995 // nsGkAtoms::autopictureinpicture,
996 nsGkAtoms::autoplay,
997 nsGkAtoms::axis,
998 nsGkAtoms::background,
999 nsGkAtoms::behavior,
1000 nsGkAtoms::bgcolor,
1001 nsGkAtoms::border,
1002 nsGkAtoms::bordercolor,
1003 nsGkAtoms::capture,
1004 nsGkAtoms::cellpadding,
1005 nsGkAtoms::cellspacing,
1006 // nsGkAtoms::challenge,
1007 nsGkAtoms::_char,
1008 nsGkAtoms::charoff,
1009 nsGkAtoms::charset,
1010 nsGkAtoms::checked,
1011 nsGkAtoms::cite,
1012 nsGkAtoms::_class,
1013 nsGkAtoms::classid,
1014 nsGkAtoms::clear,
1015 nsGkAtoms::code,
1016 nsGkAtoms::codebase,
1017 nsGkAtoms::codetype,
1018 nsGkAtoms::color,
1019 nsGkAtoms::cols,
1020 nsGkAtoms::colspan,
1021 nsGkAtoms::compact,
1022 nsGkAtoms::content,
1023 nsGkAtoms::contenteditable,
1024 nsGkAtoms::controls,
1025 // nsGkAtoms::controlslist,
1026 // nsGkAtoms::conversiondestination,
1027 nsGkAtoms::coords,
1028 nsGkAtoms::crossorigin,
1029 nsGkAtoms::csp,
1030 nsGkAtoms::data,
1031 nsGkAtoms::datetime,
1032 nsGkAtoms::declare,
1033 nsGkAtoms::decoding,
1034 nsGkAtoms::_default,
1035 nsGkAtoms::defer,
1036 nsGkAtoms::dir,
1037 nsGkAtoms::direction,
1038 // nsGkAtoms::dirname,
1039 nsGkAtoms::disabled,
1040 // nsGkAtoms::disablepictureinpicture,
1041 // nsGkAtoms::disableremoteplayback,
1042 // nsGkAtoms::disallowdocumentaccess,
1043 nsGkAtoms::download,
1044 nsGkAtoms::draggable,
1045 // nsGkAtoms::elementtiming,
1046 nsGkAtoms::enctype,
1047 nsGkAtoms::end,
1048 nsGkAtoms::enterkeyhint,
1049 nsGkAtoms::event,
1050 nsGkAtoms::exportparts,
1051 nsGkAtoms::face,
1052 nsGkAtoms::_for,
1053 nsGkAtoms::form,
1054 nsGkAtoms::formaction,
1055 nsGkAtoms::formenctype,
1056 nsGkAtoms::formmethod,
1057 nsGkAtoms::formnovalidate,
1058 nsGkAtoms::formtarget,
1059 nsGkAtoms::frame,
1060 nsGkAtoms::frameborder,
1061 nsGkAtoms::headers,
1062 nsGkAtoms::height,
1063 nsGkAtoms::hidden,
1064 nsGkAtoms::high,
1065 nsGkAtoms::href,
1066 nsGkAtoms::hreflang,
1067 // nsGkAtoms::hreftranslate,
1068 nsGkAtoms::hspace,
1069 nsGkAtoms::http,
1070 // nsGkAtoms::equiv,
1071 nsGkAtoms::id,
1072 nsGkAtoms::imagesizes,
1073 nsGkAtoms::imagesrcset,
1074 // nsGkAtoms::importance,
1075 // nsGkAtoms::impressiondata,
1076 // nsGkAtoms::impressionexpiry,
1077 // nsGkAtoms::incremental,
1078 nsGkAtoms::inert,
1079 nsGkAtoms::inputmode,
1080 nsGkAtoms::integrity,
1081 // nsGkAtoms::invisible,
1082 nsGkAtoms::is,
1083 nsGkAtoms::ismap,
1084 // nsGkAtoms::keytype,
1085 nsGkAtoms::kind,
1086 nsGkAtoms::label,
1087 nsGkAtoms::lang,
1088 nsGkAtoms::language,
1089 // nsGkAtoms::latencyhint,
1090 nsGkAtoms::leftmargin,
1091 nsGkAtoms::link,
1092 // nsGkAtoms::list,
1093 nsGkAtoms::loading,
1094 nsGkAtoms::longdesc,
1095 nsGkAtoms::loop,
1096 nsGkAtoms::low,
1097 nsGkAtoms::lowsrc,
1098 nsGkAtoms::manifest,
1099 nsGkAtoms::marginheight,
1100 nsGkAtoms::marginwidth,
1101 nsGkAtoms::max,
1102 nsGkAtoms::maxlength,
1103 // nsGkAtoms::mayscript,
1104 nsGkAtoms::media,
1105 nsGkAtoms::method,
1106 nsGkAtoms::min,
1107 nsGkAtoms::minlength,
1108 nsGkAtoms::multiple,
1109 nsGkAtoms::muted,
1110 nsGkAtoms::name,
1111 nsGkAtoms::nohref,
1112 nsGkAtoms::nomodule,
1113 nsGkAtoms::nonce,
1114 nsGkAtoms::noresize,
1115 nsGkAtoms::noshade,
1116 nsGkAtoms::novalidate,
1117 nsGkAtoms::nowrap,
1118 nsGkAtoms::object,
1119 nsGkAtoms::open,
1120 nsGkAtoms::optimum,
1121 nsGkAtoms::part,
1122 nsGkAtoms::pattern,
1123 nsGkAtoms::ping,
1124 nsGkAtoms::placeholder,
1125 // nsGkAtoms::playsinline,
1126 // nsGkAtoms::policy,
1127 nsGkAtoms::poster,
1128 nsGkAtoms::preload,
1129 // nsGkAtoms::pseudo,
1130 nsGkAtoms::readonly,
1131 nsGkAtoms::referrerpolicy,
1132 nsGkAtoms::rel,
1133 // nsGkAtoms::reportingorigin,
1134 nsGkAtoms::required,
1135 nsGkAtoms::resources,
1136 nsGkAtoms::rev,
1137 nsGkAtoms::reversed,
1138 nsGkAtoms::role,
1139 nsGkAtoms::rows,
1140 nsGkAtoms::rowspan,
1141 nsGkAtoms::rules,
1142 nsGkAtoms::sandbox,
1143 nsGkAtoms::scheme,
1144 nsGkAtoms::scope,
1145 // nsGkAtoms::scopes,
1146 nsGkAtoms::scrollamount,
1147 nsGkAtoms::scrolldelay,
1148 nsGkAtoms::scrolling,
1149 nsGkAtoms::select,
1150 nsGkAtoms::selected,
1151 // nsGkAtoms::shadowroot,
1152 // nsGkAtoms::shadowrootdelegatesfocus,
1153 nsGkAtoms::shape,
1154 nsGkAtoms::size,
1155 nsGkAtoms::sizes,
1156 nsGkAtoms::slot,
1157 nsGkAtoms::span,
1158 nsGkAtoms::spellcheck,
1159 nsGkAtoms::src,
1160 nsGkAtoms::srcdoc,
1161 nsGkAtoms::srclang,
1162 nsGkAtoms::srcset,
1163 nsGkAtoms::standby,
1164 nsGkAtoms::start,
1165 nsGkAtoms::step,
1166 nsGkAtoms::style,
1167 nsGkAtoms::summary,
1168 nsGkAtoms::tabindex,
1169 nsGkAtoms::target,
1170 nsGkAtoms::text,
1171 nsGkAtoms::title,
1172 nsGkAtoms::topmargin,
1173 nsGkAtoms::translate,
1174 nsGkAtoms::truespeed,
1175 // nsGkAtoms::trusttoken,
1176 nsGkAtoms::type,
1177 nsGkAtoms::usemap,
1178 nsGkAtoms::valign,
1179 nsGkAtoms::value,
1180 nsGkAtoms::valuetype,
1181 nsGkAtoms::version,
1182 // nsGkAtoms::virtualkeyboardpolicy,
1183 nsGkAtoms::vlink,
1184 nsGkAtoms::vspace,
1185 nsGkAtoms::webkitdirectory,
1186 nsGkAtoms::width,
1187 nsGkAtoms::wrap,
1188 // clang-format on
1191 // https://wicg.github.io/sanitizer-api/#baseline-elements
1192 constexpr const nsStaticAtom* const kBaselineElementAllowlist[] = {
1193 nsGkAtoms::a, nsGkAtoms::abbr, nsGkAtoms::acronym,
1194 nsGkAtoms::address, nsGkAtoms::area, nsGkAtoms::article,
1195 nsGkAtoms::aside, nsGkAtoms::audio, nsGkAtoms::b,
1196 nsGkAtoms::basefont, nsGkAtoms::bdi, nsGkAtoms::bdo,
1197 nsGkAtoms::bgsound, nsGkAtoms::big, nsGkAtoms::blockquote,
1198 nsGkAtoms::body, nsGkAtoms::br, nsGkAtoms::button,
1199 nsGkAtoms::canvas, nsGkAtoms::caption, nsGkAtoms::center,
1200 nsGkAtoms::cite, nsGkAtoms::code, nsGkAtoms::col,
1201 nsGkAtoms::colgroup, nsGkAtoms::command, nsGkAtoms::data,
1202 nsGkAtoms::datalist, nsGkAtoms::dd, nsGkAtoms::del,
1203 nsGkAtoms::details, nsGkAtoms::dfn, nsGkAtoms::dialog,
1204 nsGkAtoms::dir, nsGkAtoms::div, nsGkAtoms::dl,
1205 nsGkAtoms::dt, nsGkAtoms::em, nsGkAtoms::fieldset,
1206 nsGkAtoms::figcaption, nsGkAtoms::figure, nsGkAtoms::font,
1207 nsGkAtoms::footer, nsGkAtoms::form, nsGkAtoms::h1,
1208 nsGkAtoms::h2, nsGkAtoms::h3, nsGkAtoms::h4,
1209 nsGkAtoms::h5, nsGkAtoms::h6, nsGkAtoms::head,
1210 nsGkAtoms::header, nsGkAtoms::hgroup, nsGkAtoms::hr,
1211 nsGkAtoms::html, nsGkAtoms::i, nsGkAtoms::image,
1212 nsGkAtoms::img, nsGkAtoms::input, nsGkAtoms::ins,
1213 nsGkAtoms::kbd, nsGkAtoms::keygen, nsGkAtoms::label,
1214 nsGkAtoms::layer, nsGkAtoms::legend, nsGkAtoms::li,
1215 nsGkAtoms::link, nsGkAtoms::listing, nsGkAtoms::main,
1216 nsGkAtoms::map, nsGkAtoms::mark, nsGkAtoms::marquee,
1217 nsGkAtoms::menu, nsGkAtoms::meta, nsGkAtoms::meter,
1218 nsGkAtoms::nav, nsGkAtoms::nobr, nsGkAtoms::ol,
1219 nsGkAtoms::optgroup, nsGkAtoms::option, nsGkAtoms::output,
1220 nsGkAtoms::p, nsGkAtoms::picture, nsGkAtoms::plaintext,
1221 nsGkAtoms::popup, nsGkAtoms::portal, nsGkAtoms::pre,
1222 nsGkAtoms::progress, nsGkAtoms::q, nsGkAtoms::rb,
1223 nsGkAtoms::rp, nsGkAtoms::rt, nsGkAtoms::rtc,
1224 nsGkAtoms::ruby, nsGkAtoms::s, nsGkAtoms::samp,
1225 nsGkAtoms::section, nsGkAtoms::select, nsGkAtoms::selectmenu,
1226 nsGkAtoms::slot, nsGkAtoms::small, nsGkAtoms::source,
1227 nsGkAtoms::span, nsGkAtoms::strike, nsGkAtoms::strong,
1228 nsGkAtoms::style, nsGkAtoms::sub, nsGkAtoms::summary,
1229 nsGkAtoms::sup, nsGkAtoms::table, nsGkAtoms::tbody,
1230 nsGkAtoms::td, nsGkAtoms::_template, nsGkAtoms::textarea,
1231 nsGkAtoms::tfoot, nsGkAtoms::th, nsGkAtoms::thead,
1232 nsGkAtoms::time, nsGkAtoms::title, nsGkAtoms::tr,
1233 nsGkAtoms::track, nsGkAtoms::tt, nsGkAtoms::u,
1234 nsGkAtoms::ul, nsGkAtoms::var, nsGkAtoms::video,
1235 nsGkAtoms::wbr, nsGkAtoms::xmp,
1238 // https://wicg.github.io/sanitizer-api/#default-configuration
1239 // default configuration's attribute allow list.
1240 // Note: Currently all listed attributes are allowed for every element
1241 // (e.g. they use "*").
1242 // Compared to kBaselineAttributeAllowlist only deprecated allowpaymentrequest
1243 // attribute is missing.
1244 constexpr const nsStaticAtom* const kDefaultConfigurationAttributeAllowlist[] =
1246 nsGkAtoms::abbr,
1247 nsGkAtoms::accept,
1248 nsGkAtoms::acceptcharset,
1249 nsGkAtoms::charset,
1250 nsGkAtoms::accesskey,
1251 nsGkAtoms::action,
1252 nsGkAtoms::align,
1253 nsGkAtoms::alink,
1254 nsGkAtoms::allow,
1255 nsGkAtoms::allowfullscreen,
1256 nsGkAtoms::alt,
1257 nsGkAtoms::anchor,
1258 nsGkAtoms::archive,
1259 nsGkAtoms::as,
1260 nsGkAtoms::async,
1261 nsGkAtoms::autocapitalize,
1262 nsGkAtoms::autocomplete,
1263 // nsGkAtoms::autocorrect,
1264 nsGkAtoms::autofocus,
1265 // nsGkAtoms::autopictureinpicture,
1266 nsGkAtoms::autoplay,
1267 nsGkAtoms::axis,
1268 nsGkAtoms::background,
1269 nsGkAtoms::behavior,
1270 nsGkAtoms::bgcolor,
1271 nsGkAtoms::border,
1272 nsGkAtoms::bordercolor,
1273 nsGkAtoms::capture,
1274 nsGkAtoms::cellpadding,
1275 nsGkAtoms::cellspacing,
1276 // nsGkAtoms::challenge,
1277 nsGkAtoms::_char,
1278 nsGkAtoms::charoff,
1279 nsGkAtoms::charset,
1280 nsGkAtoms::checked,
1281 nsGkAtoms::cite,
1282 nsGkAtoms::_class,
1283 nsGkAtoms::classid,
1284 nsGkAtoms::clear,
1285 nsGkAtoms::code,
1286 nsGkAtoms::codebase,
1287 nsGkAtoms::codetype,
1288 nsGkAtoms::color,
1289 nsGkAtoms::cols,
1290 nsGkAtoms::colspan,
1291 nsGkAtoms::compact,
1292 nsGkAtoms::content,
1293 nsGkAtoms::contenteditable,
1294 nsGkAtoms::controls,
1295 // nsGkAtoms::controlslist,
1296 // nsGkAtoms::conversiondestination,
1297 nsGkAtoms::coords,
1298 nsGkAtoms::crossorigin,
1299 nsGkAtoms::csp,
1300 nsGkAtoms::data,
1301 nsGkAtoms::datetime,
1302 nsGkAtoms::declare,
1303 nsGkAtoms::decoding,
1304 nsGkAtoms::_default,
1305 nsGkAtoms::defer,
1306 nsGkAtoms::dir,
1307 nsGkAtoms::direction,
1308 // nsGkAtoms::dirname,
1309 nsGkAtoms::disabled,
1310 // nsGkAtoms::disablepictureinpicture,
1311 // nsGkAtoms::disableremoteplayback,
1312 // nsGkAtoms::disallowdocumentaccess,
1313 nsGkAtoms::download,
1314 nsGkAtoms::draggable,
1315 // nsGkAtoms::elementtiming,
1316 nsGkAtoms::enctype,
1317 nsGkAtoms::end,
1318 nsGkAtoms::enterkeyhint,
1319 nsGkAtoms::event,
1320 nsGkAtoms::exportparts,
1321 nsGkAtoms::face,
1322 nsGkAtoms::_for,
1323 nsGkAtoms::form,
1324 nsGkAtoms::formaction,
1325 nsGkAtoms::formenctype,
1326 nsGkAtoms::formmethod,
1327 nsGkAtoms::formnovalidate,
1328 nsGkAtoms::formtarget,
1329 nsGkAtoms::frame,
1330 nsGkAtoms::frameborder,
1331 nsGkAtoms::headers,
1332 nsGkAtoms::height,
1333 nsGkAtoms::hidden,
1334 nsGkAtoms::high,
1335 nsGkAtoms::href,
1336 nsGkAtoms::hreflang,
1337 // nsGkAtoms::hreftranslate,
1338 nsGkAtoms::hspace,
1339 nsGkAtoms::http,
1340 // nsGkAtoms::equiv,
1341 nsGkAtoms::id,
1342 nsGkAtoms::imagesizes,
1343 nsGkAtoms::imagesrcset,
1344 // nsGkAtoms::importance,
1345 // nsGkAtoms::impressiondata,
1346 // nsGkAtoms::impressionexpiry,
1347 // nsGkAtoms::incremental,
1348 nsGkAtoms::inert,
1349 nsGkAtoms::inputmode,
1350 nsGkAtoms::integrity,
1351 // nsGkAtoms::invisible,
1352 nsGkAtoms::is,
1353 nsGkAtoms::ismap,
1354 // nsGkAtoms::keytype,
1355 nsGkAtoms::kind,
1356 nsGkAtoms::label,
1357 nsGkAtoms::lang,
1358 nsGkAtoms::language,
1359 // nsGkAtoms::latencyhint,
1360 nsGkAtoms::leftmargin,
1361 nsGkAtoms::link,
1362 // nsGkAtoms::list,
1363 nsGkAtoms::loading,
1364 nsGkAtoms::longdesc,
1365 nsGkAtoms::loop,
1366 nsGkAtoms::low,
1367 nsGkAtoms::lowsrc,
1368 nsGkAtoms::manifest,
1369 nsGkAtoms::marginheight,
1370 nsGkAtoms::marginwidth,
1371 nsGkAtoms::max,
1372 nsGkAtoms::maxlength,
1373 // nsGkAtoms::mayscript,
1374 nsGkAtoms::media,
1375 nsGkAtoms::method,
1376 nsGkAtoms::min,
1377 nsGkAtoms::minlength,
1378 nsGkAtoms::multiple,
1379 nsGkAtoms::muted,
1380 nsGkAtoms::name,
1381 nsGkAtoms::nohref,
1382 nsGkAtoms::nomodule,
1383 nsGkAtoms::nonce,
1384 nsGkAtoms::noresize,
1385 nsGkAtoms::noshade,
1386 nsGkAtoms::novalidate,
1387 nsGkAtoms::nowrap,
1388 nsGkAtoms::object,
1389 nsGkAtoms::open,
1390 nsGkAtoms::optimum,
1391 nsGkAtoms::part,
1392 nsGkAtoms::pattern,
1393 nsGkAtoms::ping,
1394 nsGkAtoms::placeholder,
1395 // nsGkAtoms::playsinline,
1396 // nsGkAtoms::policy,
1397 nsGkAtoms::poster,
1398 nsGkAtoms::preload,
1399 // nsGkAtoms::pseudo,
1400 nsGkAtoms::readonly,
1401 nsGkAtoms::referrerpolicy,
1402 nsGkAtoms::rel,
1403 // nsGkAtoms::reportingorigin,
1404 nsGkAtoms::required,
1405 nsGkAtoms::resources,
1406 nsGkAtoms::rev,
1407 nsGkAtoms::reversed,
1408 nsGkAtoms::role,
1409 nsGkAtoms::rows,
1410 nsGkAtoms::rowspan,
1411 nsGkAtoms::rules,
1412 nsGkAtoms::sandbox,
1413 nsGkAtoms::scheme,
1414 nsGkAtoms::scope,
1415 // nsGkAtoms::scopes,
1416 nsGkAtoms::scrollamount,
1417 nsGkAtoms::scrolldelay,
1418 nsGkAtoms::scrolling,
1419 nsGkAtoms::select,
1420 nsGkAtoms::selected,
1421 // nsGkAtoms::shadowroot,
1422 // nsGkAtoms::shadowrootdelegatesfocus,
1423 nsGkAtoms::shape,
1424 nsGkAtoms::size,
1425 nsGkAtoms::sizes,
1426 nsGkAtoms::slot,
1427 nsGkAtoms::span,
1428 nsGkAtoms::spellcheck,
1429 nsGkAtoms::src,
1430 nsGkAtoms::srcdoc,
1431 nsGkAtoms::srclang,
1432 nsGkAtoms::srcset,
1433 nsGkAtoms::standby,
1434 nsGkAtoms::start,
1435 nsGkAtoms::step,
1436 nsGkAtoms::style,
1437 nsGkAtoms::summary,
1438 nsGkAtoms::tabindex,
1439 nsGkAtoms::target,
1440 nsGkAtoms::text,
1441 nsGkAtoms::title,
1442 nsGkAtoms::topmargin,
1443 nsGkAtoms::translate,
1444 nsGkAtoms::truespeed,
1445 // nsGkAtoms::trusttoken,
1446 nsGkAtoms::type,
1447 nsGkAtoms::usemap,
1448 nsGkAtoms::valign,
1449 nsGkAtoms::value,
1450 nsGkAtoms::valuetype,
1451 nsGkAtoms::version,
1452 // nsGkAtoms::virtualkeyboardpolicy,
1453 nsGkAtoms::vlink,
1454 nsGkAtoms::vspace,
1455 nsGkAtoms::webkitdirectory,
1456 nsGkAtoms::width,
1457 nsGkAtoms::wrap,
1460 // https://wicg.github.io/sanitizer-api/#default-configuration
1461 // default configuration's element allow list.
1462 constexpr const nsStaticAtom* const kDefaultConfigurationElementAllowlist[] = {
1463 nsGkAtoms::a, nsGkAtoms::abbr, nsGkAtoms::acronym,
1464 nsGkAtoms::address, nsGkAtoms::area, nsGkAtoms::article,
1465 nsGkAtoms::aside, nsGkAtoms::audio, nsGkAtoms::b,
1466 nsGkAtoms::bdi, nsGkAtoms::bdo, nsGkAtoms::bgsound,
1467 nsGkAtoms::big, nsGkAtoms::blockquote, nsGkAtoms::body,
1468 nsGkAtoms::br, nsGkAtoms::button, nsGkAtoms::canvas,
1469 nsGkAtoms::caption, nsGkAtoms::center, nsGkAtoms::cite,
1470 nsGkAtoms::code, nsGkAtoms::col, nsGkAtoms::colgroup,
1471 nsGkAtoms::datalist, nsGkAtoms::dd, nsGkAtoms::del,
1472 nsGkAtoms::details, nsGkAtoms::dfn, nsGkAtoms::dialog,
1473 nsGkAtoms::dir, nsGkAtoms::div, nsGkAtoms::dl,
1474 nsGkAtoms::dt, nsGkAtoms::em, nsGkAtoms::fieldset,
1475 nsGkAtoms::figcaption, nsGkAtoms::figure, nsGkAtoms::font,
1476 nsGkAtoms::footer, nsGkAtoms::form, nsGkAtoms::h1,
1477 nsGkAtoms::h2, nsGkAtoms::h3, nsGkAtoms::h4,
1478 nsGkAtoms::h5, nsGkAtoms::h6, nsGkAtoms::head,
1479 nsGkAtoms::header, nsGkAtoms::hgroup, nsGkAtoms::hr,
1480 nsGkAtoms::html, nsGkAtoms::i, nsGkAtoms::img,
1481 nsGkAtoms::input, nsGkAtoms::ins, nsGkAtoms::kbd,
1482 nsGkAtoms::keygen, nsGkAtoms::label, nsGkAtoms::layer,
1483 nsGkAtoms::legend, nsGkAtoms::li, nsGkAtoms::link,
1484 nsGkAtoms::listing, nsGkAtoms::main, nsGkAtoms::map,
1485 nsGkAtoms::mark, nsGkAtoms::marquee, nsGkAtoms::menu,
1486 nsGkAtoms::meta, nsGkAtoms::meter, nsGkAtoms::nav,
1487 nsGkAtoms::nobr, nsGkAtoms::ol, nsGkAtoms::optgroup,
1488 nsGkAtoms::option, nsGkAtoms::output, nsGkAtoms::p,
1489 nsGkAtoms::picture, nsGkAtoms::popup, nsGkAtoms::pre,
1490 nsGkAtoms::progress, nsGkAtoms::q, nsGkAtoms::rb,
1491 nsGkAtoms::rp, nsGkAtoms::rt, nsGkAtoms::rtc,
1492 nsGkAtoms::ruby, nsGkAtoms::s, nsGkAtoms::samp,
1493 nsGkAtoms::section, nsGkAtoms::select, nsGkAtoms::selectmenu,
1494 nsGkAtoms::small, nsGkAtoms::source, nsGkAtoms::span,
1495 nsGkAtoms::strike, nsGkAtoms::strong, nsGkAtoms::style,
1496 nsGkAtoms::sub, nsGkAtoms::summary, nsGkAtoms::sup,
1497 nsGkAtoms::table, nsGkAtoms::tbody, nsGkAtoms::td,
1498 nsGkAtoms::tfoot, nsGkAtoms::th, nsGkAtoms::thead,
1499 nsGkAtoms::time, nsGkAtoms::tr, nsGkAtoms::track,
1500 nsGkAtoms::tt, nsGkAtoms::u, nsGkAtoms::ul,
1501 nsGkAtoms::var, nsGkAtoms::video, nsGkAtoms::wbr,
1504 nsTreeSanitizer::AtomsTable* nsTreeSanitizer::sElementsHTML = nullptr;
1505 nsTreeSanitizer::AtomsTable* nsTreeSanitizer::sAttributesHTML = nullptr;
1506 nsTreeSanitizer::AtomsTable* nsTreeSanitizer::sPresAttributesHTML = nullptr;
1507 nsTreeSanitizer::AtomsTable* nsTreeSanitizer::sElementsSVG = nullptr;
1508 nsTreeSanitizer::AtomsTable* nsTreeSanitizer::sAttributesSVG = nullptr;
1509 nsTreeSanitizer::AtomsTable* nsTreeSanitizer::sElementsMathML = nullptr;
1510 nsTreeSanitizer::AtomsTable* nsTreeSanitizer::sAttributesMathML = nullptr;
1511 nsTreeSanitizer::AtomsTable* nsTreeSanitizer::sBaselineAttributeAllowlist =
1512 nullptr;
1513 nsTreeSanitizer::AtomsTable* nsTreeSanitizer::sBaselineElementAllowlist =
1514 nullptr;
1515 nsTreeSanitizer::AtomsTable*
1516 nsTreeSanitizer::sDefaultConfigurationAttributeAllowlist = nullptr;
1517 nsTreeSanitizer::AtomsTable*
1518 nsTreeSanitizer::sDefaultConfigurationElementAllowlist = nullptr;
1519 nsIPrincipal* nsTreeSanitizer::sNullPrincipal = nullptr;
1521 nsTreeSanitizer::nsTreeSanitizer(uint32_t aFlags)
1522 : mAllowStyles(aFlags & nsIParserUtils::SanitizerAllowStyle),
1523 mAllowComments(aFlags & nsIParserUtils::SanitizerAllowComments),
1524 mDropNonCSSPresentation(aFlags &
1525 nsIParserUtils::SanitizerDropNonCSSPresentation),
1526 mDropForms(aFlags & nsIParserUtils::SanitizerDropForms),
1527 mCidEmbedsOnly(aFlags & nsIParserUtils::SanitizerCidEmbedsOnly),
1528 mDropMedia(aFlags & nsIParserUtils::SanitizerDropMedia),
1529 mFullDocument(false),
1530 mLogRemovals(aFlags & nsIParserUtils::SanitizerLogRemovals) {
1531 if (mCidEmbedsOnly) {
1532 // Sanitizing styles for external references is not supported.
1533 mAllowStyles = false;
1536 if (!sElementsHTML) {
1537 // Initialize lazily to avoid having to initialize at all if the user
1538 // doesn't paste HTML or load feeds.
1539 InitializeStatics();
1543 bool nsTreeSanitizer::MustFlatten(int32_t aNamespace, nsAtom* aLocal) {
1544 if (mIsForSanitizerAPI) {
1545 return MustFlattenForSanitizerAPI(aNamespace, aLocal);
1548 if (aNamespace == kNameSpaceID_XHTML) {
1549 if (mDropNonCSSPresentation &&
1550 (nsGkAtoms::font == aLocal || nsGkAtoms::center == aLocal)) {
1551 return true;
1553 if (mDropForms &&
1554 (nsGkAtoms::form == aLocal || nsGkAtoms::input == aLocal ||
1555 nsGkAtoms::option == aLocal || nsGkAtoms::optgroup == aLocal)) {
1556 return true;
1558 if (mFullDocument &&
1559 (nsGkAtoms::title == aLocal || nsGkAtoms::html == aLocal ||
1560 nsGkAtoms::head == aLocal || nsGkAtoms::body == aLocal)) {
1561 return false;
1563 if (nsGkAtoms::_template == aLocal) {
1564 return false;
1566 return !sElementsHTML->Contains(aLocal);
1568 if (aNamespace == kNameSpaceID_SVG) {
1569 if (mCidEmbedsOnly || mDropMedia) {
1570 // Sanitizing CSS-based URL references inside SVG presentational
1571 // attributes is not supported, so flattening for cid: embed case.
1572 return true;
1574 return !sElementsSVG->Contains(aLocal);
1576 if (aNamespace == kNameSpaceID_MathML) {
1577 return !sElementsMathML->Contains(aLocal);
1579 return true;
1582 bool nsTreeSanitizer::MustFlattenForSanitizerAPI(int32_t aNamespace,
1583 nsAtom* aLocal) {
1584 // This implements everything in
1585 // https://wicg.github.io/sanitizer-api/#sanitize-action-for-an-element that
1586 // is supposed to be blocked.
1588 // Step 6. If element matches any name in config["blockElements"]: Return
1589 // block.
1590 if (mBlockElements &&
1591 MatchesElementName(*mBlockElements, aNamespace, aLocal)) {
1592 return true;
1595 // Step 7. Let allow list be null.
1596 // Step 8. If "allowElements" exists in config:
1597 // Step 8.1. Then : Set allow list to config["allowElements"].
1598 if (mAllowElements) {
1599 // Step 9. If element does not match any name in allow list:
1600 // Return block.
1601 if (!MatchesElementName(*mAllowElements, aNamespace, aLocal)) {
1602 return true;
1604 } else {
1605 // Step 8.2. Otherwise: Set allow list to the default configuration's
1606 // element allow list.
1608 // Step 9. If element does not match any name in allow list:
1609 // Return block.
1611 // The default configuration only contains HTML elements, so we can
1612 // reject everything else.
1613 if (aNamespace != kNameSpaceID_XHTML ||
1614 !sDefaultConfigurationElementAllowlist->Contains(aLocal)) {
1615 return true;
1619 // Step 10. Return keep.
1620 return false;
1623 bool nsTreeSanitizer::IsURL(const nsStaticAtom* const* aURLs,
1624 nsAtom* aLocalName) {
1625 const nsStaticAtom* atom;
1626 while ((atom = *aURLs)) {
1627 if (atom == aLocalName) {
1628 return true;
1630 ++aURLs;
1632 return false;
1635 bool nsTreeSanitizer::MustPrune(int32_t aNamespace, nsAtom* aLocal,
1636 mozilla::dom::Element* aElement) {
1637 if (mIsForSanitizerAPI) {
1638 return MustPruneForSanitizerAPI(aNamespace, aLocal, aElement);
1641 // To avoid attacks where a MathML script becomes something that gets
1642 // serialized in a way that it parses back as an HTML script, let's just
1643 // drop elements with the local name 'script' regardless of namespace.
1644 if (nsGkAtoms::script == aLocal) {
1645 return true;
1647 if (aNamespace == kNameSpaceID_XHTML) {
1648 if (nsGkAtoms::title == aLocal && !mFullDocument) {
1649 // emulate the quirks of the old parser
1650 return true;
1652 if (mDropForms &&
1653 (nsGkAtoms::select == aLocal || nsGkAtoms::button == aLocal ||
1654 nsGkAtoms::datalist == aLocal)) {
1655 return true;
1657 if (mDropMedia &&
1658 (nsGkAtoms::img == aLocal || nsGkAtoms::video == aLocal ||
1659 nsGkAtoms::audio == aLocal || nsGkAtoms::source == aLocal)) {
1660 return true;
1662 if (nsGkAtoms::meta == aLocal &&
1663 (aElement->HasAttr(nsGkAtoms::charset) ||
1664 aElement->HasAttr(nsGkAtoms::httpEquiv))) {
1665 // Throw away charset declarations even if they also have microdata
1666 // which they can't validly have.
1667 return true;
1669 if (((!mFullDocument && nsGkAtoms::meta == aLocal) ||
1670 nsGkAtoms::link == aLocal) &&
1671 !(aElement->HasAttr(nsGkAtoms::itemprop) ||
1672 aElement->HasAttr(nsGkAtoms::itemscope))) {
1673 // emulate old behavior for non-Microdata <meta> and <link> presumably
1674 // in <head>. <meta> and <link> are whitelisted in order to avoid
1675 // corrupting Microdata when they appear in <body>. Note that
1676 // SanitizeAttributes() will remove the rel attribute from <link> and
1677 // the name attribute from <meta>.
1678 return true;
1681 if (mAllowStyles) {
1682 return nsGkAtoms::style == aLocal && !(aNamespace == kNameSpaceID_XHTML ||
1683 aNamespace == kNameSpaceID_SVG);
1685 if (nsGkAtoms::style == aLocal) {
1686 return true;
1688 return false;
1691 enum class ElementKind {
1692 Regular,
1693 Custom,
1694 Unknown,
1697 // https://wicg.github.io/sanitizer-api/#element-kind
1698 static ElementKind GetElementKind(int32_t aNamespace, nsAtom* aLocal,
1699 Element* aElement) {
1700 // XXX(bug 1782926) The spec for this is known to be wrong.
1701 // https://github.com/WICG/sanitizer-api/issues/147
1703 // custom, if element’s local name is a valid custom element name,
1704 // XXX shouldn't this happen after unknown.
1705 if (nsContentUtils::IsCustomElementName(aLocal, kNameSpaceID_XHTML)) {
1706 return ElementKind::Custom;
1709 // unknown, if element is not in the [HTML] namespace
1710 // XXX this doesn't really make sense to me
1711 // https://github.com/WICG/sanitizer-api/issues/167
1712 if (aNamespace != kNameSpaceID_XHTML) {
1713 return ElementKind::Unknown;
1716 // or if element’s local name denotes an unknown element
1717 // — that is, if the element interface the [HTML] specification assigns to it
1718 // would be HTMLUnknownElement,
1719 if (nsCOMPtr<HTMLUnknownElement> el = do_QueryInterface(aElement)) {
1720 return ElementKind::Unknown;
1723 // regular, otherwise.
1724 return ElementKind::Regular;
1727 bool nsTreeSanitizer::MustPruneForSanitizerAPI(int32_t aNamespace,
1728 nsAtom* aLocal,
1729 Element* aElement) {
1730 // This implements everything in
1731 // https://wicg.github.io/sanitizer-api/#sanitize-action-for-an-element that
1732 // is supposed to be dropped.
1734 // Step 1. Let kind be element’s element kind.
1735 ElementKind kind = GetElementKind(aNamespace, aLocal, aElement);
1737 switch (kind) {
1738 case ElementKind::Regular:
1739 // Step 2. If kind is regular and element does not match any name in the
1740 // baseline element allow list: Return drop.
1741 if (!sBaselineElementAllowlist->Contains(aLocal)) {
1742 return true;
1744 break;
1746 case ElementKind::Custom:
1747 // Step 3. If kind is custom and if config["allowCustomElements"] does not
1748 // exist or if config["allowCustomElements"] is false: Return drop.
1749 if (!mAllowCustomElements) {
1750 return true;
1752 break;
1754 case ElementKind::Unknown:
1755 // Step 4. If kind is unknown and if config["allowUnknownMarkup"] does not
1756 // exist or it config["allowUnknownMarkup"] is false: Return drop.
1757 if (!mAllowUnknownMarkup) {
1758 return true;
1760 break;
1763 // Step 5. If element matches any name in config["dropElements"]: Return drop.
1764 if (mDropElements && MatchesElementName(*mDropElements, aNamespace, aLocal)) {
1765 return true;
1768 return false;
1772 * Parses a style sheet and reserializes it with unsafe styles removed.
1774 * @param aOriginal the original style sheet source
1775 * @param aSanitized the reserialization without dangerous CSS.
1776 * @param aDocument the document the style sheet belongs to
1777 * @param aBaseURI the base URI to use
1778 * @param aSanitizationKind the kind of style sanitization to use.
1780 static void SanitizeStyleSheet(const nsAString& aOriginal,
1781 nsAString& aSanitized, Document* aDocument,
1782 nsIURI* aBaseURI,
1783 StyleSanitizationKind aSanitizationKind) {
1784 aSanitized.Truncate();
1786 NS_ConvertUTF16toUTF8 style(aOriginal);
1787 nsIReferrerInfo* referrer =
1788 aDocument->ReferrerInfoForInternalCSSAndSVGResources();
1789 auto extraData =
1790 MakeRefPtr<URLExtraData>(aBaseURI, referrer, aDocument->NodePrincipal());
1791 RefPtr<StyleStylesheetContents> contents =
1792 Servo_StyleSheet_FromUTF8Bytes(
1793 /* loader = */ nullptr,
1794 /* stylesheet = */ nullptr,
1795 /* load_data = */ nullptr, &style,
1796 css::SheetParsingMode::eAuthorSheetFeatures, extraData.get(),
1797 aDocument->GetCompatibilityMode(),
1798 /* reusable_sheets = */ nullptr,
1799 /* use_counters = */ nullptr, StyleAllowImportRules::Yes,
1800 aSanitizationKind, &aSanitized)
1801 .Consume();
1804 bool nsTreeSanitizer::SanitizeInlineStyle(
1805 Element* aElement, StyleSanitizationKind aSanitizationKind) {
1806 MOZ_ASSERT(aElement);
1807 MOZ_ASSERT(aElement->IsHTMLElement(nsGkAtoms::style) ||
1808 aElement->IsSVGElement(nsGkAtoms::style));
1810 nsAutoString styleText;
1811 nsContentUtils::GetNodeTextContent(aElement, false, styleText);
1813 nsAutoString sanitizedStyle;
1814 SanitizeStyleSheet(styleText, sanitizedStyle, aElement->OwnerDoc(),
1815 aElement->GetBaseURI(), StyleSanitizationKind::Standard);
1816 RemoveAllAttributesFromDescendants(aElement);
1817 nsContentUtils::SetNodeTextContent(aElement, sanitizedStyle, true);
1819 return sanitizedStyle.Length() != styleText.Length();
1822 void nsTreeSanitizer::RemoveConditionalCSSFromSubtree(nsINode* aRoot) {
1823 AutoTArray<RefPtr<nsINode>, 10> nodesToSanitize;
1824 for (nsINode* node : ShadowIncludingTreeIterator(*aRoot)) {
1825 if (node->IsHTMLElement(nsGkAtoms::style) ||
1826 node->IsSVGElement(nsGkAtoms::style)) {
1827 nodesToSanitize.AppendElement(node);
1830 for (nsINode* node : nodesToSanitize) {
1831 SanitizeInlineStyle(node->AsElement(),
1832 StyleSanitizationKind::NoConditionalRules);
1836 template <size_t Len>
1837 static bool UTF16StringStartsWith(const char16_t* aStr, uint32_t aLength,
1838 const char16_t (&aNeedle)[Len]) {
1839 MOZ_ASSERT(aNeedle[Len - 1] == '\0',
1840 "needle should be a UTF-16 encoded string literal");
1842 if (aLength < Len - 1) {
1843 return false;
1845 for (size_t i = 0; i < Len - 1; i++) {
1846 if (aStr[i] != aNeedle[i]) {
1847 return false;
1850 return true;
1853 void nsTreeSanitizer::SanitizeAttributes(mozilla::dom::Element* aElement,
1854 AllowedAttributes aAllowed) {
1855 int32_t ac = (int)aElement->GetAttrCount();
1857 for (int32_t i = ac - 1; i >= 0; --i) {
1858 const nsAttrName* attrName = aElement->GetAttrNameAt(i);
1859 int32_t attrNs = attrName->NamespaceID();
1860 RefPtr<nsAtom> attrLocal = attrName->LocalName();
1862 if (mIsForSanitizerAPI) {
1863 if (MustDropAttribute(aElement, attrNs, attrLocal) ||
1864 MustDropFunkyAttribute(aElement, attrNs, attrLocal)) {
1865 aElement->UnsetAttr(kNameSpaceID_None, attrLocal, false);
1866 if (mLogRemovals) {
1867 LogMessage("Removed unsafe attribute.", aElement->OwnerDoc(),
1868 aElement, attrLocal);
1871 // in case the attribute removal shuffled the attribute order, start
1872 // the loop again.
1873 --ac;
1874 i = ac; // i will be decremented immediately thanks to the for loop
1876 continue;
1879 if (kNameSpaceID_None == attrNs) {
1880 if (aAllowed.mStyle && nsGkAtoms::style == attrLocal) {
1881 continue;
1883 if (aAllowed.mDangerousSrc && nsGkAtoms::src == attrLocal) {
1884 continue;
1886 if (IsURL(aAllowed.mURLs, attrLocal)) {
1887 bool fragmentOnly = aElement->IsSVGElement(nsGkAtoms::use);
1888 if (SanitizeURL(aElement, attrNs, attrLocal, fragmentOnly)) {
1889 // in case the attribute removal shuffled the attribute order, start
1890 // the loop again.
1891 --ac;
1892 i = ac; // i will be decremented immediately thanks to the for loop
1893 continue;
1895 // else fall through to see if there's another reason to drop this
1896 // attribute (in particular if the attribute is background="" on an
1897 // HTML element)
1899 if (!mDropNonCSSPresentation &&
1900 (aAllowed.mNames == sAttributesHTML) && // element is HTML
1901 sPresAttributesHTML->Contains(attrLocal)) {
1902 continue;
1904 if (aAllowed.mNames->Contains(attrLocal) &&
1905 !((attrLocal == nsGkAtoms::rel &&
1906 aElement->IsHTMLElement(nsGkAtoms::link)) ||
1907 (!mFullDocument && attrLocal == nsGkAtoms::name &&
1908 aElement->IsHTMLElement(nsGkAtoms::meta)))) {
1909 // name="" and rel="" are whitelisted, but treat them as blacklisted
1910 // for <meta name> (fragment case) and <link rel> (all cases) to avoid
1911 // document-wide metadata or styling overrides with non-conforming
1912 // <meta name itemprop> or
1913 // <link rel itemprop>
1914 continue;
1916 const char16_t* localStr = attrLocal->GetUTF16String();
1917 uint32_t localLen = attrLocal->GetLength();
1918 // Allow underscore to cater to the MCE editor library.
1919 // Allow data-* on SVG and MathML, too, as a forward-compat measure.
1920 // Allow aria-* on all for simplicity.
1921 if (UTF16StringStartsWith(localStr, localLen, u"_") ||
1922 UTF16StringStartsWith(localStr, localLen, u"data-") ||
1923 UTF16StringStartsWith(localStr, localLen, u"aria-")) {
1924 continue;
1926 // else not allowed
1927 } else if (kNameSpaceID_XML == attrNs) {
1928 if (nsGkAtoms::lang == attrLocal || nsGkAtoms::space == attrLocal) {
1929 continue;
1931 // else not allowed
1932 } else if (aAllowed.mXLink && kNameSpaceID_XLink == attrNs) {
1933 if (nsGkAtoms::href == attrLocal) {
1934 bool fragmentOnly = aElement->IsSVGElement(nsGkAtoms::use);
1935 if (SanitizeURL(aElement, attrNs, attrLocal, fragmentOnly)) {
1936 // in case the attribute removal shuffled the attribute order, start
1937 // the loop again.
1938 --ac;
1939 i = ac; // i will be decremented immediately thanks to the for loop
1941 continue;
1943 if (nsGkAtoms::type == attrLocal || nsGkAtoms::title == attrLocal ||
1944 nsGkAtoms::show == attrLocal || nsGkAtoms::actuate == attrLocal) {
1945 continue;
1947 // else not allowed
1949 aElement->UnsetAttr(kNameSpaceID_None, attrLocal, false);
1950 if (mLogRemovals) {
1951 LogMessage("Removed unsafe attribute.", aElement->OwnerDoc(), aElement,
1952 attrLocal);
1954 // in case the attribute removal shuffled the attribute order, start the
1955 // loop again.
1956 --ac;
1957 i = ac; // i will be decremented immediately thanks to the for loop
1960 // If we've got HTML audio or video, add the controls attribute, because
1961 // otherwise the content is unplayable with scripts removed.
1962 if (aElement->IsAnyOfHTMLElements(nsGkAtoms::video, nsGkAtoms::audio)) {
1963 aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::controls, u""_ns, false);
1967 // https://wicg.github.io/sanitizer-api/#element-matches-an-element-name
1968 bool nsTreeSanitizer::MatchesElementName(ElementNameSet& aNames,
1969 int32_t aNamespace,
1970 nsAtom* aLocalName) {
1971 return aNames.Contains(ElementName(aNamespace, aLocalName));
1974 // https://wicg.github.io/sanitizer-api/#attribute-match-list
1975 bool nsTreeSanitizer::MatchesAttributeMatchList(
1976 AttributesToElementsMap& aMatchList, Element& aElement,
1977 int32_t aAttrNamespace, nsAtom* aAttrLocalName) {
1978 // Step 1. If attribute’s local name does not match the attribute match list
1979 // list’s key and if the key is not "*": Return false.
1980 ElementNameSet* names;
1981 if (auto lookup =
1982 aMatchList.Lookup(AttributeName(aAttrNamespace, aAttrLocalName))) {
1983 names = lookup->get();
1984 } else {
1985 return false;
1988 // Step 2. Let element be the attribute’s Element.
1989 // Step 3. Let element name be element’s local name.
1990 // Step 4. If element is a in either the SVG or MathML namespaces (i.e., it’s
1991 // a foreign element), then prefix element name with the appropriate namespace
1992 // designator plus a whitespace character.
1994 // TODO: This is spec text is going to change.
1995 int32_t namespaceID = aElement.NodeInfo()->NamespaceID();
1996 RefPtr<nsAtom> nameAtom = aElement.NodeInfo()->NameAtom();
1998 // Step 5. If list’s value does not contain element name and value is not
1999 // ["*"]: Return false.
2000 // Step 6. Return true.
2002 // nullptr means star (*), i.e. any element.
2003 if (!names) {
2004 return true;
2006 return MatchesElementName(*names, namespaceID, nameAtom);
2009 // https://wicg.github.io/sanitizer-api/#sanitize-action-for-an-attribute
2010 bool nsTreeSanitizer::MustDropAttribute(Element* aElement,
2011 int32_t aAttrNamespace,
2012 nsAtom* aAttrLocalName) {
2013 // Step 1. Let kind be attribute’s attribute kind.
2014 // Step 2. If kind is unknown and if config["allowUnknownMarkup"] does not
2015 // exist or it config["allowUnknownMarkup"] is false: Return drop.
2017 // TODO: Not clear how to determine if something is an "unknown" attribute.
2018 // https://github.com/WICG/sanitizer-api/issues/147 should probably define
2019 // an explicit list.
2021 // Step 3. If kind is regular and attribute’s local name does not match any
2022 // name in the baseline attribute allow list: Return drop.
2023 if (!sBaselineAttributeAllowlist->Contains(aAttrLocalName)) {
2024 return true;
2027 // Step 4. If attribute matches any attribute match list in config’s attribute
2028 // drop list: Return drop.
2029 if (mDropAttributes &&
2030 MatchesAttributeMatchList(*mDropAttributes, *aElement, aAttrNamespace,
2031 aAttrLocalName)) {
2032 return true;
2035 // Step 5. If attribute allow list exists in config:
2036 if (mAllowAttributes) {
2037 // Step 5.1. Then let allow list be |config|["allowAttributes"].
2038 // Step 6. If attribute does not match any attribute match list in allow
2039 // list: Return drop.
2040 if (!MatchesAttributeMatchList(*mAllowAttributes, *aElement, aAttrNamespace,
2041 aAttrLocalName)) {
2042 return true;
2044 } else {
2045 // Step 5.2. Otherwise: Let allow list be the default configuration's
2046 // attribute allow list.
2047 // Step 6. If attribute does not match any attribute
2048 // match list in allow list: Return drop.
2049 if (!sDefaultConfigurationAttributeAllowlist->Contains(aAttrLocalName)) {
2050 return true;
2054 // Step 7. Return keep.
2055 return false;
2058 // https://wicg.github.io/sanitizer-api/#handle-funky-elements
2059 bool nsTreeSanitizer::MustDropFunkyAttribute(Element* aElement,
2060 int32_t aAttrNamespace,
2061 nsAtom* aAttrLocalName) {
2062 // Step 1. If element’s element interface is HTMLTemplateElement:
2063 // Note: This step is implemented in the main loop of SanitizeChildren.
2065 // Step 2. If element’s element interface has a HTMLHyperlinkElementUtils
2066 // mixin, and if element’s protocol property is "javascript:":
2067 // TODO(https://github.com/WICG/sanitizer-api/issues/168)
2068 if (aAttrLocalName == nsGkAtoms::href) {
2069 if (nsCOMPtr<Link> link = do_QueryInterface(aElement)) {
2070 nsCOMPtr<nsIURI> uri = link->GetURI();
2071 if (uri && uri->SchemeIs("javascript")) {
2072 // Step 2.1. Remove the `href` attribute from element.
2073 return true;
2078 // Step 3. if element’s element interface is HTMLFormElement, and if element’s
2079 // action attribute is a URL with "javascript:" protocol:
2080 if (auto* form = HTMLFormElement::FromNode(aElement)) {
2081 if (aAttrNamespace == kNameSpaceID_None &&
2082 aAttrLocalName == nsGkAtoms::action) {
2083 nsCOMPtr<nsIURI> uri;
2084 form->GetURIAttr(aAttrLocalName, nullptr, getter_AddRefs(uri));
2085 if (uri && uri->SchemeIs("javascript")) {
2086 // Step 3.1 Remove the `action` attribute from element.
2087 return true;
2092 // Step 4. if element’s element interface is HTMLInputElement or
2093 // HTMLButtonElement, and if element’s formaction attribute is a [URL] with
2094 // javascript: protocol
2095 if (aElement->IsAnyOfHTMLElements(nsGkAtoms::input, nsGkAtoms::button) &&
2096 aAttrNamespace == kNameSpaceID_None &&
2097 aAttrLocalName == nsGkAtoms::formaction) {
2098 // XXX nsGenericHTMLFormControlElementWithState::GetFormAction falls back to
2099 // the document URI.
2100 nsGenericHTMLElement* el = nsGenericHTMLElement::FromNode(aElement);
2101 nsCOMPtr<nsIURI> uri;
2102 el->GetURIAttr(aAttrLocalName, nullptr, getter_AddRefs(uri));
2103 if (uri && uri->SchemeIs("javascript")) {
2104 // Step 4.1 Remove the `formaction` attribute from element.
2105 return true;
2109 return false;
2112 bool nsTreeSanitizer::SanitizeURL(mozilla::dom::Element* aElement,
2113 int32_t aNamespace, nsAtom* aLocalName,
2114 bool aFragmentsOnly) {
2115 nsAutoString value;
2116 aElement->GetAttr(aNamespace, aLocalName, value);
2118 // Get value and remove mandatory quotes
2119 static const char* kWhitespace = "\n\r\t\b";
2120 const nsAString& v = nsContentUtils::TrimCharsInSet(kWhitespace, value);
2121 // Fragment-only url cannot be harmful.
2122 if (!v.IsEmpty() && v.First() == u'#') {
2123 return false;
2125 // if we allow only same-document fragment URLs, stop and remove here
2126 if (aFragmentsOnly) {
2127 aElement->UnsetAttr(aNamespace, aLocalName, false);
2128 if (mLogRemovals) {
2129 LogMessage("Removed unsafe URI from element attribute.",
2130 aElement->OwnerDoc(), aElement, aLocalName);
2132 return true;
2135 nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
2136 uint32_t flags = nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL;
2138 nsCOMPtr<nsIURI> attrURI;
2139 nsresult rv =
2140 NS_NewURI(getter_AddRefs(attrURI), v, nullptr, aElement->GetBaseURI());
2141 if (NS_SUCCEEDED(rv)) {
2142 if (mCidEmbedsOnly && kNameSpaceID_None == aNamespace) {
2143 if (nsGkAtoms::src == aLocalName || nsGkAtoms::background == aLocalName) {
2144 // comm-central uses a hack that makes nsIURIs created with cid: specs
2145 // actually have an about:blank spec. Therefore, nsIURI facilities are
2146 // useless for cid: when comm-central code is participating.
2147 if (!(v.Length() > 4 && (v[0] == 'c' || v[0] == 'C') &&
2148 (v[1] == 'i' || v[1] == 'I') && (v[2] == 'd' || v[2] == 'D') &&
2149 v[3] == ':')) {
2150 rv = NS_ERROR_FAILURE;
2152 } else if (nsGkAtoms::cdgroup_ == aLocalName ||
2153 nsGkAtoms::altimg_ == aLocalName ||
2154 nsGkAtoms::definitionURL_ == aLocalName) {
2155 // Gecko doesn't fetch these now and shouldn't in the future, but
2156 // in case someone goofs with these in the future, let's drop them.
2157 rv = NS_ERROR_FAILURE;
2158 } else {
2159 rv = secMan->CheckLoadURIWithPrincipal(sNullPrincipal, attrURI, flags,
2162 } else {
2163 rv = secMan->CheckLoadURIWithPrincipal(sNullPrincipal, attrURI, flags, 0);
2166 if (NS_FAILED(rv)) {
2167 aElement->UnsetAttr(aNamespace, aLocalName, false);
2168 if (mLogRemovals) {
2169 LogMessage("Removed unsafe URI from element attribute.",
2170 aElement->OwnerDoc(), aElement, aLocalName);
2172 return true;
2174 return false;
2177 void nsTreeSanitizer::Sanitize(DocumentFragment* aFragment) {
2178 // If you want to relax these preconditions, be sure to check the code in
2179 // here that notifies / does not notify or that fires mutation events if
2180 // in tree.
2181 MOZ_ASSERT(!aFragment->IsInUncomposedDoc(), "The fragment is in doc?");
2183 mFullDocument = false;
2184 SanitizeChildren(aFragment);
2187 void nsTreeSanitizer::Sanitize(Document* aDocument) {
2188 // If you want to relax these preconditions, be sure to check the code in
2189 // here that notifies / does not notify or that fires mutation events if
2190 // in tree.
2191 #ifdef DEBUG
2192 MOZ_ASSERT(!aDocument->GetContainer(), "The document is in a shell.");
2193 RefPtr<mozilla::dom::Element> root = aDocument->GetRootElement();
2194 MOZ_ASSERT(root->IsHTMLElement(nsGkAtoms::html), "Not HTML root.");
2195 #endif
2197 mFullDocument = true;
2198 SanitizeChildren(aDocument);
2201 void nsTreeSanitizer::SanitizeChildren(nsINode* aRoot) {
2202 nsIContent* node = aRoot->GetFirstChild();
2203 while (node) {
2204 if (node->IsElement()) {
2205 mozilla::dom::Element* elt = node->AsElement();
2206 mozilla::dom::NodeInfo* nodeInfo = node->NodeInfo();
2207 nsAtom* localName = nodeInfo->NameAtom();
2208 int32_t ns = nodeInfo->NamespaceID();
2210 if (MustPrune(ns, localName, elt)) {
2211 if (mLogRemovals) {
2212 LogMessage("Removing unsafe node.", elt->OwnerDoc(), elt);
2214 RemoveAllAttributes(elt);
2215 nsIContent* descendant = node;
2216 while ((descendant = descendant->GetNextNode(node))) {
2217 if (descendant->IsElement()) {
2218 RemoveAllAttributes(descendant->AsElement());
2221 nsIContent* next = node->GetNextNonChildNode(aRoot);
2222 node->RemoveFromParent();
2223 node = next;
2224 continue;
2226 if (auto* templateEl = HTMLTemplateElement::FromNode(elt)) {
2227 // traverse into the DocFragment content attribute of template elements
2228 bool wasFullDocument = mFullDocument;
2229 mFullDocument = false;
2230 RefPtr<DocumentFragment> frag = templateEl->Content();
2231 SanitizeChildren(frag);
2232 mFullDocument = wasFullDocument;
2234 if (!mIsForSanitizerAPI && nsGkAtoms::style == localName) {
2235 // If styles aren't allowed, style elements got pruned above. Even
2236 // if styles are allowed, non-HTML, non-SVG style elements got pruned
2237 // above.
2238 NS_ASSERTION(ns == kNameSpaceID_XHTML || ns == kNameSpaceID_SVG,
2239 "Should have only HTML or SVG here!");
2240 if (SanitizeInlineStyle(elt, StyleSanitizationKind::Standard) &&
2241 mLogRemovals) {
2242 LogMessage("Removed some rules and/or properties from stylesheet.",
2243 aRoot->OwnerDoc());
2246 AllowedAttributes allowed;
2247 allowed.mStyle = mAllowStyles;
2248 if (ns == kNameSpaceID_XHTML) {
2249 allowed.mNames = sAttributesHTML;
2250 allowed.mURLs = kURLAttributesHTML;
2251 } else {
2252 allowed.mNames = sAttributesSVG;
2253 allowed.mURLs = kURLAttributesSVG;
2254 allowed.mXLink = true;
2256 SanitizeAttributes(elt, allowed);
2257 node = node->GetNextNonChildNode(aRoot);
2258 continue;
2260 if (MustFlatten(ns, localName)) {
2261 if (mLogRemovals) {
2262 LogMessage("Flattening unsafe node (descendants are preserved).",
2263 elt->OwnerDoc(), elt);
2265 RemoveAllAttributes(elt);
2266 nsCOMPtr<nsIContent> next = node->GetNextNode(aRoot);
2267 nsCOMPtr<nsIContent> parent = node->GetParent();
2268 nsCOMPtr<nsIContent> child; // Must keep the child alive during move
2269 ErrorResult rv;
2270 while ((child = node->GetFirstChild())) {
2271 nsCOMPtr<nsINode> refNode = node;
2272 parent->InsertBefore(*child, refNode, rv);
2273 if (rv.Failed()) {
2274 break;
2277 node->RemoveFromParent();
2278 node = next;
2279 continue;
2281 NS_ASSERTION(ns == kNameSpaceID_XHTML || ns == kNameSpaceID_SVG ||
2282 ns == kNameSpaceID_MathML,
2283 "Should have only HTML, MathML or SVG here!");
2284 AllowedAttributes allowed;
2285 if (ns == kNameSpaceID_XHTML) {
2286 allowed.mNames = sAttributesHTML;
2287 allowed.mURLs = kURLAttributesHTML;
2288 allowed.mStyle = mAllowStyles;
2289 allowed.mDangerousSrc = nsGkAtoms::img == localName && !mCidEmbedsOnly;
2290 SanitizeAttributes(elt, allowed);
2291 } else if (ns == kNameSpaceID_SVG) {
2292 allowed.mNames = sAttributesSVG;
2293 allowed.mURLs = kURLAttributesSVG;
2294 allowed.mXLink = true;
2295 allowed.mStyle = mAllowStyles;
2296 SanitizeAttributes(elt, allowed);
2297 } else {
2298 allowed.mNames = sAttributesMathML;
2299 allowed.mURLs = kURLAttributesMathML;
2300 allowed.mXLink = true;
2301 SanitizeAttributes(elt, allowed);
2303 node = node->GetNextNode(aRoot);
2304 continue;
2306 NS_ASSERTION(!node->GetFirstChild(), "How come non-element node had kids?");
2307 nsIContent* next = node->GetNextNonChildNode(aRoot);
2308 if (!mAllowComments && node->IsComment()) {
2309 node->RemoveFromParent();
2311 node = next;
2315 void nsTreeSanitizer::RemoveAllAttributes(Element* aElement) {
2316 const nsAttrName* attrName;
2317 while ((attrName = aElement->GetAttrNameAt(0))) {
2318 int32_t attrNs = attrName->NamespaceID();
2319 RefPtr<nsAtom> attrLocal = attrName->LocalName();
2320 aElement->UnsetAttr(attrNs, attrLocal, false);
2324 void nsTreeSanitizer::RemoveAllAttributesFromDescendants(
2325 mozilla::dom::Element* aElement) {
2326 nsIContent* node = aElement->GetFirstChild();
2327 while (node) {
2328 if (node->IsElement()) {
2329 mozilla::dom::Element* elt = node->AsElement();
2330 RemoveAllAttributes(elt);
2332 node = node->GetNextNode(aElement);
2336 void nsTreeSanitizer::LogMessage(const char* aMessage, Document* aDoc,
2337 Element* aElement, nsAtom* aAttr) {
2338 if (mLogRemovals) {
2339 nsAutoString msg;
2340 msg.Assign(NS_ConvertASCIItoUTF16(aMessage));
2341 if (aElement) {
2342 msg.Append(u" Element: "_ns + aElement->LocalName() + u"."_ns);
2344 if (aAttr) {
2345 msg.Append(u" Attribute: "_ns + nsDependentAtomString(aAttr) + u"."_ns);
2348 if (mInnerWindowID) {
2349 nsContentUtils::ReportToConsoleByWindowID(
2350 msg, nsIScriptError::warningFlag, "DOM"_ns, mInnerWindowID);
2351 } else {
2352 nsContentUtils::ReportToConsoleNonLocalized(
2353 msg, nsIScriptError::warningFlag, "DOM"_ns, aDoc);
2358 void nsTreeSanitizer::InitializeStatics() {
2359 MOZ_ASSERT(!sElementsHTML, "Initializing a second time.");
2361 sElementsHTML = new AtomsTable(ArrayLength(kElementsHTML));
2362 for (uint32_t i = 0; kElementsHTML[i]; i++) {
2363 sElementsHTML->Insert(kElementsHTML[i]);
2366 sAttributesHTML = new AtomsTable(ArrayLength(kAttributesHTML));
2367 for (uint32_t i = 0; kAttributesHTML[i]; i++) {
2368 sAttributesHTML->Insert(kAttributesHTML[i]);
2371 sPresAttributesHTML = new AtomsTable(ArrayLength(kPresAttributesHTML));
2372 for (uint32_t i = 0; kPresAttributesHTML[i]; i++) {
2373 sPresAttributesHTML->Insert(kPresAttributesHTML[i]);
2376 sElementsSVG = new AtomsTable(ArrayLength(kElementsSVG));
2377 for (uint32_t i = 0; kElementsSVG[i]; i++) {
2378 sElementsSVG->Insert(kElementsSVG[i]);
2381 sAttributesSVG = new AtomsTable(ArrayLength(kAttributesSVG));
2382 for (uint32_t i = 0; kAttributesSVG[i]; i++) {
2383 sAttributesSVG->Insert(kAttributesSVG[i]);
2386 sElementsMathML = new AtomsTable(ArrayLength(kElementsMathML));
2387 for (uint32_t i = 0; kElementsMathML[i]; i++) {
2388 sElementsMathML->Insert(kElementsMathML[i]);
2391 sAttributesMathML = new AtomsTable(ArrayLength(kAttributesMathML));
2392 for (uint32_t i = 0; kAttributesMathML[i]; i++) {
2393 sAttributesMathML->Insert(kAttributesMathML[i]);
2396 sBaselineAttributeAllowlist =
2397 new AtomsTable(ArrayLength(kBaselineAttributeAllowlist));
2398 for (const auto* atom : kBaselineAttributeAllowlist) {
2399 sBaselineAttributeAllowlist->Insert(atom);
2402 sBaselineElementAllowlist =
2403 new AtomsTable(ArrayLength(kBaselineElementAllowlist));
2404 for (const auto* atom : kBaselineElementAllowlist) {
2405 sBaselineElementAllowlist->Insert(atom);
2408 sDefaultConfigurationAttributeAllowlist =
2409 new AtomsTable(ArrayLength(kDefaultConfigurationAttributeAllowlist));
2410 for (const auto* atom : kDefaultConfigurationAttributeAllowlist) {
2411 sDefaultConfigurationAttributeAllowlist->Insert(atom);
2414 sDefaultConfigurationElementAllowlist =
2415 new AtomsTable(ArrayLength(kDefaultConfigurationElementAllowlist));
2416 for (const auto* atom : kDefaultConfigurationElementAllowlist) {
2417 sDefaultConfigurationElementAllowlist->Insert(atom);
2420 nsCOMPtr<nsIPrincipal> principal =
2421 NullPrincipal::CreateWithoutOriginAttributes();
2422 principal.forget(&sNullPrincipal);
2425 void nsTreeSanitizer::ReleaseStatics() {
2426 delete sElementsHTML;
2427 sElementsHTML = nullptr;
2429 delete sAttributesHTML;
2430 sAttributesHTML = nullptr;
2432 delete sPresAttributesHTML;
2433 sPresAttributesHTML = nullptr;
2435 delete sElementsSVG;
2436 sElementsSVG = nullptr;
2438 delete sAttributesSVG;
2439 sAttributesSVG = nullptr;
2441 delete sElementsMathML;
2442 sElementsMathML = nullptr;
2444 delete sAttributesMathML;
2445 sAttributesMathML = nullptr;
2447 delete sBaselineAttributeAllowlist;
2448 sBaselineAttributeAllowlist = nullptr;
2450 delete sBaselineElementAllowlist;
2451 sBaselineElementAllowlist = nullptr;
2453 delete sDefaultConfigurationAttributeAllowlist;
2454 sDefaultConfigurationAttributeAllowlist = nullptr;
2456 delete sDefaultConfigurationElementAllowlist;
2457 sDefaultConfigurationElementAllowlist = nullptr;
2459 NS_IF_RELEASE(sNullPrincipal);
2462 static int32_t ConvertNamespaceString(const nsAString& aNamespace,
2463 bool aForAttribute,
2464 mozilla::ErrorResult& aRv) {
2465 int32_t namespaceID = nsNameSpaceManager::GetInstance()->GetNameSpaceID(
2466 aNamespace, /* aInChromeDoc */ false);
2467 if (namespaceID == kNameSpaceID_XHTML || namespaceID == kNameSpaceID_MathML ||
2468 namespaceID == kNameSpaceID_SVG) {
2469 return namespaceID;
2471 if (aForAttribute && (namespaceID == kNameSpaceID_XMLNS ||
2472 namespaceID == kNameSpaceID_XLink)) {
2473 return namespaceID;
2476 aRv.ThrowTypeError("Invalid namespace: \""_ns +
2477 NS_ConvertUTF16toUTF8(aNamespace) + "\"."_ns);
2478 return kNameSpaceID_Unknown;
2481 UniquePtr<nsTreeSanitizer::ElementNameSet> nsTreeSanitizer::ConvertElements(
2482 const nsTArray<OwningStringOrSanitizerElementNamespace>& aElements,
2483 mozilla::ErrorResult& aRv) {
2484 auto set = MakeUnique<ElementNameSet>(aElements.Length());
2485 for (const auto& entry : aElements) {
2486 if (entry.IsString()) {
2487 RefPtr<nsAtom> nameAtom = NS_AtomizeMainThread(entry.GetAsString());
2488 // The default namespace for elements is HTML.
2489 ElementName elemName(kNameSpaceID_XHTML, std::move(nameAtom));
2490 set->Insert(elemName);
2491 } else {
2492 const auto& elemNamespace = entry.GetAsSanitizerElementNamespace();
2494 int32_t namespaceID =
2495 ConvertNamespaceString(elemNamespace.mNamespace, false, aRv);
2496 if (aRv.Failed()) {
2497 return {};
2500 RefPtr<nsAtom> nameAtom = NS_AtomizeMainThread(elemNamespace.mName);
2501 ElementName elemName(namespaceID, std::move(nameAtom));
2502 set->Insert(elemName);
2506 return set;
2509 UniquePtr<nsTreeSanitizer::ElementNameSet> nsTreeSanitizer::ConvertElements(
2510 const OwningStarOrStringOrSanitizerElementNamespaceSequence& aElements,
2511 mozilla::ErrorResult& aRv) {
2512 if (aElements.IsStar()) {
2513 return nullptr;
2515 return ConvertElements(
2516 aElements.GetAsStringOrSanitizerElementNamespaceSequence(), aRv);
2519 UniquePtr<nsTreeSanitizer::AttributesToElementsMap>
2520 nsTreeSanitizer::ConvertAttributes(
2521 const nsTArray<SanitizerAttribute>& aAttributes, ErrorResult& aRv) {
2522 auto map = MakeUnique<AttributesToElementsMap>();
2524 for (const auto& entry : aAttributes) {
2525 // The default namespace for attributes is the "null" namespace.
2526 int32_t namespaceID = kNameSpaceID_None;
2527 if (!entry.mNamespace.IsVoid()) {
2528 namespaceID = ConvertNamespaceString(entry.mNamespace, true, aRv);
2529 if (aRv.Failed()) {
2530 return {};
2533 RefPtr<nsAtom> attrAtom = NS_AtomizeMainThread(entry.mName);
2534 AttributeName attrName(namespaceID, std::move(attrAtom));
2536 UniquePtr<ElementNameSet> elements = ConvertElements(entry.mElements, aRv);
2537 if (aRv.Failed()) {
2538 return {};
2540 map->InsertOrUpdate(attrName, std::move(elements));
2543 return map;
2546 void nsTreeSanitizer::WithWebSanitizerOptions(
2547 nsIGlobalObject* aGlobal, const mozilla::dom::SanitizerConfig& aOptions,
2548 ErrorResult& aRv) {
2549 if (StaticPrefs::dom_security_sanitizer_logging()) {
2550 mLogRemovals = true;
2551 if (nsPIDOMWindowInner* win = aGlobal->AsInnerWindow()) {
2552 mInnerWindowID = win->WindowID();
2556 mIsForSanitizerAPI = true;
2558 if (aOptions.mAllowComments.WasPassed()) {
2559 mAllowComments = aOptions.mAllowComments.Value();
2561 if (aOptions.mAllowCustomElements.WasPassed()) {
2562 mAllowCustomElements = aOptions.mAllowCustomElements.Value();
2564 if (aOptions.mAllowUnknownMarkup.WasPassed()) {
2565 mAllowUnknownMarkup = aOptions.mAllowUnknownMarkup.Value();
2568 if (aOptions.mAllowElements.WasPassed()) {
2569 mAllowElements = ConvertElements(aOptions.mAllowElements.Value(), aRv);
2570 if (aRv.Failed()) {
2571 return;
2575 if (aOptions.mBlockElements.WasPassed()) {
2576 mBlockElements = ConvertElements(aOptions.mBlockElements.Value(), aRv);
2577 if (aRv.Failed()) {
2578 return;
2582 if (aOptions.mDropElements.WasPassed()) {
2583 mDropElements = ConvertElements(aOptions.mDropElements.Value(), aRv);
2584 if (aRv.Failed()) {
2585 return;
2589 if (aOptions.mAllowAttributes.WasPassed()) {
2590 mAllowAttributes =
2591 ConvertAttributes(aOptions.mAllowAttributes.Value(), aRv);
2592 if (aRv.Failed()) {
2593 return;
2597 if (aOptions.mDropAttributes.WasPassed()) {
2598 mDropAttributes = ConvertAttributes(aOptions.mDropAttributes.Value(), aRv);