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