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"
24 #include "nsCSSPropertyID.h"
25 #include "nsHashtablesFwd.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"
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
[] = {
62 nsGkAtoms::blockquote
,
63 // body checked specially
86 nsGkAtoms::figcaption
,
97 // head checked specially
101 // html checked specially
148 // style checked specially
152 // template checked and traversed specially
158 // title checked specially
171 const nsStaticAtom
* const kAttributesHTML
[] = {
175 nsGkAtoms::acceptcharset
,
176 nsGkAtoms::accesskey
,
180 nsGkAtoms::autocomplete
,
181 nsGkAtoms::autofocus
,
193 nsGkAtoms::contenteditable
,
194 nsGkAtoms::contextmenu
,
197 nsGkAtoms::crossorigin
,
201 nsGkAtoms::draggable
,
214 nsGkAtoms::integrity
,
219 nsGkAtoms::itemscope
,
229 nsGkAtoms::maxlength
,
233 nsGkAtoms::minlength
,
238 nsGkAtoms::novalidate
,
243 nsGkAtoms::placeholder
,
244 nsGkAtoms::playbackrate
,
249 nsGkAtoms::radiogroup
,
264 nsGkAtoms::spellcheck
,
281 const nsStaticAtom
* const kPresAttributesHTML
[] = {
284 nsGkAtoms::background
,
287 nsGkAtoms::cellpadding
,
288 nsGkAtoms::cellspacing
,
294 nsGkAtoms::pointSize
,
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
[] = {
312 nsGkAtoms::background
,
313 nsGkAtoms::formaction
,
321 const nsStaticAtom
* const kElementsSVG
[] = {
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::discard
, // discard
330 nsGkAtoms::ellipse
, // ellipse
331 nsGkAtoms::elevation
, // elevation
332 nsGkAtoms::erode
, // erode
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
371 nsGkAtoms::glyphRef
, // glyphRef
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
401 constexpr const nsStaticAtom
* const kAttributesSVG
[] = {
403 nsGkAtoms::accumulate
, // accumulate
404 nsGkAtoms::additive
, // additive
405 nsGkAtoms::alignment_baseline
, // alignment-baseline
407 nsGkAtoms::amplitude
, // amplitude
410 nsGkAtoms::attributeName
, // attributeName
411 nsGkAtoms::attributeType
, // attributeType
412 nsGkAtoms::azimuth
, // azimuth
413 nsGkAtoms::baseFrequency
, // baseFrequency
414 nsGkAtoms::baseline_shift
, // baseline-shift
417 nsGkAtoms::begin
, // begin
418 nsGkAtoms::bias
, // bias
420 nsGkAtoms::calcMode
, // calcMode
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
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
442 nsGkAtoms::edgeMode
, // edgeMode
443 nsGkAtoms::elevation
, // elevation
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
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
470 // glyph-orientation-horizontal
471 // glyph-orientation-vertical
472 nsGkAtoms::gradientTransform
, // gradientTransform
473 nsGkAtoms::gradientUnits
, // gradientUnits
474 nsGkAtoms::height
, // height
481 nsGkAtoms::image_rendering
, // image-rendering
483 nsGkAtoms::in2
, // in2
484 nsGkAtoms::intercept
, // intercept
491 nsGkAtoms::kernelMatrix
, // kernelMatrix
492 nsGkAtoms::kernelUnitLength
, // kernelUnitLength
493 nsGkAtoms::keyPoints
, // keyPoints
494 nsGkAtoms::keySplines
, // keySplines
495 nsGkAtoms::keyTimes
, // keyTimes
496 nsGkAtoms::lang
, // lang
498 nsGkAtoms::letter_spacing
, // letter-spacing
499 nsGkAtoms::lighting_color
, // lighting-color
500 nsGkAtoms::limitingConeAngle
, // limitingConeAngle
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
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
528 // overline-thickness
529 nsGkAtoms::overflow
, // overflow
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
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
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
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
592 nsGkAtoms::text_rendering
, // text-rendering
593 nsGkAtoms::title
, // title
595 nsGkAtoms::transform
, // transform
596 nsGkAtoms::transform_origin
, // transform-origin
597 nsGkAtoms::type
, // type
600 // underline-position
601 // underline-thickness
603 nsGkAtoms::unicode_bidi
, // unicode-bidi
610 nsGkAtoms::values
, // values
611 nsGkAtoms::vector_effect
, // vector-effect
615 nsGkAtoms::viewBox
, // viewBox
616 nsGkAtoms::viewTarget
, // viewTarget
617 nsGkAtoms::visibility
, // visibility
618 nsGkAtoms::width
, // width
620 nsGkAtoms::word_spacing
, // word-spacing
621 nsGkAtoms::writing_mode
, // writing-mode
626 nsGkAtoms::xChannelSelector
, // xChannelSelector
630 nsGkAtoms::yChannelSelector
, // yChannelSelector
632 nsGkAtoms::zoomAndPan
, // zoomAndPan
635 constexpr const nsStaticAtom
* const kURLAttributesSVG
[] = {nsGkAtoms::href
,
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
;
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
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
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
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
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
961 const nsStaticAtom
* const kURLAttributesMathML
[] = {
967 nsGkAtoms::definitionURL_
,
972 // https://wicg.github.io/sanitizer-api/#baseline-attribute-allow-list
973 constexpr const nsStaticAtom
* const kBaselineAttributeAllowlist
[] = {
977 nsGkAtoms::acceptcharset
,
979 nsGkAtoms::accesskey
,
984 nsGkAtoms::allowfullscreen
,
985 // nsGkAtoms::allowpaymentrequest,
991 nsGkAtoms::autocapitalize
,
992 nsGkAtoms::autocomplete
,
993 // nsGkAtoms::autocorrect,
994 nsGkAtoms::autofocus
,
995 // nsGkAtoms::autopictureinpicture,
998 nsGkAtoms::background
,
1002 nsGkAtoms::bordercolor
,
1004 nsGkAtoms::cellpadding
,
1005 nsGkAtoms::cellspacing
,
1006 // nsGkAtoms::challenge,
1016 nsGkAtoms::codebase
,
1017 nsGkAtoms::codetype
,
1023 nsGkAtoms::contenteditable
,
1024 nsGkAtoms::controls
,
1025 // nsGkAtoms::controlslist,
1026 // nsGkAtoms::conversiondestination,
1028 nsGkAtoms::crossorigin
,
1031 nsGkAtoms::datetime
,
1033 nsGkAtoms::decoding
,
1034 nsGkAtoms::_default
,
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,
1048 nsGkAtoms::enterkeyhint
,
1050 nsGkAtoms::exportparts
,
1054 nsGkAtoms::formaction
,
1055 nsGkAtoms::formenctype
,
1056 nsGkAtoms::formmethod
,
1057 nsGkAtoms::formnovalidate
,
1058 nsGkAtoms::formtarget
,
1060 nsGkAtoms::frameborder
,
1066 nsGkAtoms::hreflang
,
1067 // nsGkAtoms::hreftranslate,
1070 // nsGkAtoms::equiv,
1072 nsGkAtoms::imagesizes
,
1073 nsGkAtoms::imagesrcset
,
1074 // nsGkAtoms::importance,
1075 // nsGkAtoms::impressiondata,
1076 // nsGkAtoms::impressionexpiry,
1077 // nsGkAtoms::incremental,
1079 nsGkAtoms::inputmode
,
1080 nsGkAtoms::integrity
,
1081 // nsGkAtoms::invisible,
1084 // nsGkAtoms::keytype,
1088 nsGkAtoms::language
,
1089 // nsGkAtoms::latencyhint,
1090 nsGkAtoms::leftmargin
,
1094 nsGkAtoms::longdesc
,
1098 nsGkAtoms::manifest
,
1099 nsGkAtoms::marginheight
,
1100 nsGkAtoms::marginwidth
,
1102 nsGkAtoms::maxlength
,
1103 // nsGkAtoms::mayscript,
1107 nsGkAtoms::minlength
,
1108 nsGkAtoms::multiple
,
1112 nsGkAtoms::nomodule
,
1114 nsGkAtoms::noresize
,
1116 nsGkAtoms::novalidate
,
1124 nsGkAtoms::placeholder
,
1125 // nsGkAtoms::playsinline,
1126 // nsGkAtoms::policy,
1129 // nsGkAtoms::pseudo,
1130 nsGkAtoms::readonly
,
1131 nsGkAtoms::referrerpolicy
,
1133 // nsGkAtoms::reportingorigin,
1134 nsGkAtoms::required
,
1135 nsGkAtoms::resources
,
1137 nsGkAtoms::reversed
,
1145 // nsGkAtoms::scopes,
1146 nsGkAtoms::scrollamount
,
1147 nsGkAtoms::scrolldelay
,
1148 nsGkAtoms::scrolling
,
1150 nsGkAtoms::selected
,
1151 // nsGkAtoms::shadowroot,
1152 // nsGkAtoms::shadowrootdelegatesfocus,
1158 nsGkAtoms::spellcheck
,
1168 nsGkAtoms::tabindex
,
1172 nsGkAtoms::topmargin
,
1173 nsGkAtoms::translate
,
1174 nsGkAtoms::truespeed
,
1175 // nsGkAtoms::trusttoken,
1180 nsGkAtoms::valuetype
,
1182 // nsGkAtoms::virtualkeyboardpolicy,
1185 nsGkAtoms::webkitdirectory
,
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
[] =
1248 nsGkAtoms::acceptcharset
,
1250 nsGkAtoms::accesskey
,
1255 nsGkAtoms::allowfullscreen
,
1261 nsGkAtoms::autocapitalize
,
1262 nsGkAtoms::autocomplete
,
1263 // nsGkAtoms::autocorrect,
1264 nsGkAtoms::autofocus
,
1265 // nsGkAtoms::autopictureinpicture,
1266 nsGkAtoms::autoplay
,
1268 nsGkAtoms::background
,
1269 nsGkAtoms::behavior
,
1272 nsGkAtoms::bordercolor
,
1274 nsGkAtoms::cellpadding
,
1275 nsGkAtoms::cellspacing
,
1276 // nsGkAtoms::challenge,
1286 nsGkAtoms::codebase
,
1287 nsGkAtoms::codetype
,
1293 nsGkAtoms::contenteditable
,
1294 nsGkAtoms::controls
,
1295 // nsGkAtoms::controlslist,
1296 // nsGkAtoms::conversiondestination,
1298 nsGkAtoms::crossorigin
,
1301 nsGkAtoms::datetime
,
1303 nsGkAtoms::decoding
,
1304 nsGkAtoms::_default
,
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,
1318 nsGkAtoms::enterkeyhint
,
1320 nsGkAtoms::exportparts
,
1324 nsGkAtoms::formaction
,
1325 nsGkAtoms::formenctype
,
1326 nsGkAtoms::formmethod
,
1327 nsGkAtoms::formnovalidate
,
1328 nsGkAtoms::formtarget
,
1330 nsGkAtoms::frameborder
,
1336 nsGkAtoms::hreflang
,
1337 // nsGkAtoms::hreftranslate,
1340 // nsGkAtoms::equiv,
1342 nsGkAtoms::imagesizes
,
1343 nsGkAtoms::imagesrcset
,
1344 // nsGkAtoms::importance,
1345 // nsGkAtoms::impressiondata,
1346 // nsGkAtoms::impressionexpiry,
1347 // nsGkAtoms::incremental,
1349 nsGkAtoms::inputmode
,
1350 nsGkAtoms::integrity
,
1351 // nsGkAtoms::invisible,
1354 // nsGkAtoms::keytype,
1358 nsGkAtoms::language
,
1359 // nsGkAtoms::latencyhint,
1360 nsGkAtoms::leftmargin
,
1364 nsGkAtoms::longdesc
,
1368 nsGkAtoms::manifest
,
1369 nsGkAtoms::marginheight
,
1370 nsGkAtoms::marginwidth
,
1372 nsGkAtoms::maxlength
,
1373 // nsGkAtoms::mayscript,
1377 nsGkAtoms::minlength
,
1378 nsGkAtoms::multiple
,
1382 nsGkAtoms::nomodule
,
1384 nsGkAtoms::noresize
,
1386 nsGkAtoms::novalidate
,
1394 nsGkAtoms::placeholder
,
1395 // nsGkAtoms::playsinline,
1396 // nsGkAtoms::policy,
1399 // nsGkAtoms::pseudo,
1400 nsGkAtoms::readonly
,
1401 nsGkAtoms::referrerpolicy
,
1403 // nsGkAtoms::reportingorigin,
1404 nsGkAtoms::required
,
1405 nsGkAtoms::resources
,
1407 nsGkAtoms::reversed
,
1415 // nsGkAtoms::scopes,
1416 nsGkAtoms::scrollamount
,
1417 nsGkAtoms::scrolldelay
,
1418 nsGkAtoms::scrolling
,
1420 nsGkAtoms::selected
,
1421 // nsGkAtoms::shadowroot,
1422 // nsGkAtoms::shadowrootdelegatesfocus,
1428 nsGkAtoms::spellcheck
,
1438 nsGkAtoms::tabindex
,
1442 nsGkAtoms::topmargin
,
1443 nsGkAtoms::translate
,
1444 nsGkAtoms::truespeed
,
1445 // nsGkAtoms::trusttoken,
1450 nsGkAtoms::valuetype
,
1452 // nsGkAtoms::virtualkeyboardpolicy,
1455 nsGkAtoms::webkitdirectory
,
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
=
1513 nsTreeSanitizer::AtomsTable
* nsTreeSanitizer::sBaselineElementAllowlist
=
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
)) {
1554 (nsGkAtoms::form
== aLocal
|| nsGkAtoms::input
== aLocal
||
1555 nsGkAtoms::option
== aLocal
|| nsGkAtoms::optgroup
== aLocal
)) {
1558 if (mFullDocument
&&
1559 (nsGkAtoms::title
== aLocal
|| nsGkAtoms::html
== aLocal
||
1560 nsGkAtoms::head
== aLocal
|| nsGkAtoms::body
== aLocal
)) {
1563 if (nsGkAtoms::_template
== aLocal
) {
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.
1574 return !sElementsSVG
->Contains(aLocal
);
1576 if (aNamespace
== kNameSpaceID_MathML
) {
1577 return !sElementsMathML
->Contains(aLocal
);
1582 bool nsTreeSanitizer::MustFlattenForSanitizerAPI(int32_t aNamespace
,
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
1590 if (mReplaceWithChildrenElements
&&
1591 MatchesElementName(*mReplaceWithChildrenElements
, aNamespace
, aLocal
)) {
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"].
1599 // Step 9. If element does not match any name in allow list:
1601 if (!mElements
->Contains(ElementName(aNamespace
, aLocal
))) {
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:
1611 // The default configuration only contains HTML elements, so we can
1612 // reject everything else.
1613 if (aNamespace
!= kNameSpaceID_XHTML
||
1614 !sDefaultConfigurationElementAllowlist
->Contains(aLocal
)) {
1619 // Step 10. Return keep.
1623 bool nsTreeSanitizer::IsURL(const nsStaticAtom
* const* aURLs
,
1624 nsAtom
* aLocalName
) {
1625 const nsStaticAtom
* atom
;
1626 while ((atom
= *aURLs
)) {
1627 if (atom
== aLocalName
) {
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
) {
1647 if (aNamespace
== kNameSpaceID_XHTML
) {
1648 if (nsGkAtoms::title
== aLocal
&& !mFullDocument
) {
1649 // emulate the quirks of the old parser
1653 (nsGkAtoms::select
== aLocal
|| nsGkAtoms::button
== aLocal
||
1654 nsGkAtoms::datalist
== aLocal
)) {
1658 (nsGkAtoms::img
== aLocal
|| nsGkAtoms::video
== aLocal
||
1659 nsGkAtoms::audio
== aLocal
|| nsGkAtoms::source
== aLocal
)) {
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.
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>.
1682 return nsGkAtoms::style
== aLocal
&& !(aNamespace
== kNameSpaceID_XHTML
||
1683 aNamespace
== kNameSpaceID_SVG
);
1685 if (nsGkAtoms::style
== aLocal
) {
1691 enum class ElementKind
{
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
,
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
);
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
)) {
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
) {
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
) {
1763 // Step 5. If element matches any name in config["dropElements"]: Return drop.
1764 if (mRemoveElements
&&
1765 MatchesElementName(*mRemoveElements
, aNamespace
, aLocal
)) {
1773 * Parses a style sheet and reserializes it with unsafe styles removed.
1775 * @param aOriginal the original style sheet source
1776 * @param aSanitized the reserialization without dangerous CSS.
1777 * @param aDocument the document the style sheet belongs to
1778 * @param aBaseURI the base URI to use
1779 * @param aSanitizationKind the kind of style sanitization to use.
1781 static void SanitizeStyleSheet(const nsAString
& aOriginal
,
1782 nsAString
& aSanitized
, Document
* aDocument
,
1784 StyleSanitizationKind aSanitizationKind
) {
1785 aSanitized
.Truncate();
1787 NS_ConvertUTF16toUTF8
style(aOriginal
);
1788 nsIReferrerInfo
* referrer
=
1789 aDocument
->ReferrerInfoForInternalCSSAndSVGResources();
1791 MakeRefPtr
<URLExtraData
>(aBaseURI
, referrer
, aDocument
->NodePrincipal());
1792 RefPtr
<StyleStylesheetContents
> contents
=
1793 Servo_StyleSheet_FromUTF8Bytes(
1794 /* loader = */ nullptr,
1795 /* stylesheet = */ nullptr,
1796 /* load_data = */ nullptr, &style
,
1797 css::SheetParsingMode::eAuthorSheetFeatures
, extraData
.get(),
1798 aDocument
->GetCompatibilityMode(),
1799 /* reusable_sheets = */ nullptr,
1800 /* use_counters = */ nullptr, StyleAllowImportRules::Yes
,
1801 aSanitizationKind
, &aSanitized
)
1805 bool nsTreeSanitizer::SanitizeInlineStyle(
1806 Element
* aElement
, StyleSanitizationKind aSanitizationKind
) {
1807 MOZ_ASSERT(aElement
);
1808 MOZ_ASSERT(aElement
->IsHTMLElement(nsGkAtoms::style
) ||
1809 aElement
->IsSVGElement(nsGkAtoms::style
));
1811 nsAutoString styleText
;
1812 nsContentUtils::GetNodeTextContent(aElement
, false, styleText
);
1814 nsAutoString sanitizedStyle
;
1815 SanitizeStyleSheet(styleText
, sanitizedStyle
, aElement
->OwnerDoc(),
1816 aElement
->GetBaseURI(), StyleSanitizationKind::Standard
);
1817 RemoveAllAttributesFromDescendants(aElement
);
1818 nsContentUtils::SetNodeTextContent(aElement
, sanitizedStyle
, true);
1820 return sanitizedStyle
.Length() != styleText
.Length();
1823 void nsTreeSanitizer::RemoveConditionalCSSFromSubtree(nsINode
* aRoot
) {
1824 AutoTArray
<RefPtr
<nsINode
>, 10> nodesToSanitize
;
1825 for (nsINode
* node
: ShadowIncludingTreeIterator(*aRoot
)) {
1826 if (node
->IsHTMLElement(nsGkAtoms::style
) ||
1827 node
->IsSVGElement(nsGkAtoms::style
)) {
1828 nodesToSanitize
.AppendElement(node
);
1831 for (nsINode
* node
: nodesToSanitize
) {
1832 SanitizeInlineStyle(node
->AsElement(),
1833 StyleSanitizationKind::NoConditionalRules
);
1837 template <size_t Len
>
1838 static bool UTF16StringStartsWith(const char16_t
* aStr
, uint32_t aLength
,
1839 const char16_t (&aNeedle
)[Len
]) {
1840 MOZ_ASSERT(aNeedle
[Len
- 1] == '\0',
1841 "needle should be a UTF-16 encoded string literal");
1843 if (aLength
< Len
- 1) {
1846 for (size_t i
= 0; i
< Len
- 1; i
++) {
1847 if (aStr
[i
] != aNeedle
[i
]) {
1854 void nsTreeSanitizer::SanitizeAttributes(mozilla::dom::Element
* aElement
,
1855 AllowedAttributes aAllowed
) {
1856 int32_t ac
= (int)aElement
->GetAttrCount();
1858 for (int32_t i
= ac
- 1; i
>= 0; --i
) {
1859 const nsAttrName
* attrName
= aElement
->GetAttrNameAt(i
);
1860 int32_t attrNs
= attrName
->NamespaceID();
1861 RefPtr
<nsAtom
> attrLocal
= attrName
->LocalName();
1863 if (mIsForSanitizerAPI
) {
1864 if (MustDropAttribute(aElement
, attrNs
, attrLocal
) ||
1865 MustDropFunkyAttribute(aElement
, attrNs
, attrLocal
)) {
1866 aElement
->UnsetAttr(kNameSpaceID_None
, attrLocal
, false);
1868 LogMessage("Removed unsafe attribute.", aElement
->OwnerDoc(),
1869 aElement
, attrLocal
);
1872 // in case the attribute removal shuffled the attribute order, start
1875 i
= ac
; // i will be decremented immediately thanks to the for loop
1880 if (kNameSpaceID_None
== attrNs
) {
1881 if (aAllowed
.mStyle
&& nsGkAtoms::style
== attrLocal
) {
1884 if (aAllowed
.mDangerousSrc
&& nsGkAtoms::src
== attrLocal
) {
1887 if (IsURL(aAllowed
.mURLs
, attrLocal
)) {
1888 bool fragmentOnly
= aElement
->IsSVGElement(nsGkAtoms::use
);
1889 if (SanitizeURL(aElement
, attrNs
, attrLocal
, fragmentOnly
)) {
1890 // in case the attribute removal shuffled the attribute order, start
1893 i
= ac
; // i will be decremented immediately thanks to the for loop
1896 // else fall through to see if there's another reason to drop this
1897 // attribute (in particular if the attribute is background="" on an
1900 if (!mDropNonCSSPresentation
&&
1901 (aAllowed
.mNames
== sAttributesHTML
) && // element is HTML
1902 sPresAttributesHTML
->Contains(attrLocal
)) {
1905 if (aAllowed
.mNames
->Contains(attrLocal
) &&
1906 !((attrLocal
== nsGkAtoms::rel
&&
1907 aElement
->IsHTMLElement(nsGkAtoms::link
)) ||
1908 (!mFullDocument
&& attrLocal
== nsGkAtoms::name
&&
1909 aElement
->IsHTMLElement(nsGkAtoms::meta
)))) {
1910 // name="" and rel="" are whitelisted, but treat them as blacklisted
1911 // for <meta name> (fragment case) and <link rel> (all cases) to avoid
1912 // document-wide metadata or styling overrides with non-conforming
1913 // <meta name itemprop> or
1914 // <link rel itemprop>
1917 const char16_t
* localStr
= attrLocal
->GetUTF16String();
1918 uint32_t localLen
= attrLocal
->GetLength();
1919 // Allow underscore to cater to the MCE editor library.
1920 // Allow data-* on SVG and MathML, too, as a forward-compat measure.
1921 // Allow aria-* on all for simplicity.
1922 if (UTF16StringStartsWith(localStr
, localLen
, u
"_") ||
1923 UTF16StringStartsWith(localStr
, localLen
, u
"data-") ||
1924 UTF16StringStartsWith(localStr
, localLen
, u
"aria-")) {
1928 } else if (kNameSpaceID_XML
== attrNs
) {
1929 if (nsGkAtoms::lang
== attrLocal
|| nsGkAtoms::space
== attrLocal
) {
1933 } else if (aAllowed
.mXLink
&& kNameSpaceID_XLink
== attrNs
) {
1934 if (nsGkAtoms::href
== attrLocal
) {
1935 bool fragmentOnly
= aElement
->IsSVGElement(nsGkAtoms::use
);
1936 if (SanitizeURL(aElement
, attrNs
, attrLocal
, fragmentOnly
)) {
1937 // in case the attribute removal shuffled the attribute order, start
1940 i
= ac
; // i will be decremented immediately thanks to the for loop
1944 if (nsGkAtoms::type
== attrLocal
|| nsGkAtoms::title
== attrLocal
||
1945 nsGkAtoms::show
== attrLocal
|| nsGkAtoms::actuate
== attrLocal
) {
1950 aElement
->UnsetAttr(kNameSpaceID_None
, attrLocal
, false);
1952 LogMessage("Removed unsafe attribute.", aElement
->OwnerDoc(), aElement
,
1955 // in case the attribute removal shuffled the attribute order, start the
1958 i
= ac
; // i will be decremented immediately thanks to the for loop
1961 // If we've got HTML audio or video, add the controls attribute, because
1962 // otherwise the content is unplayable with scripts removed.
1963 if (aElement
->IsAnyOfHTMLElements(nsGkAtoms::video
, nsGkAtoms::audio
)) {
1964 aElement
->SetAttr(kNameSpaceID_None
, nsGkAtoms::controls
, u
""_ns
, false);
1968 // https://wicg.github.io/sanitizer-api/#element-matches-an-element-name
1969 bool nsTreeSanitizer::MatchesElementName(ElementNameSet
& aNames
,
1971 nsAtom
* aLocalName
) {
1972 return aNames
.Contains(ElementName(aNamespace
, aLocalName
));
1975 bool nsTreeSanitizer::MatchesAttributeName(AttributeNameSet
& aNames
,
1977 nsAtom
* aLocalName
) {
1978 return aNames
.Contains(AttributeName(aNamespace
, aLocalName
));
1981 // https://wicg.github.io/sanitizer-api/#sanitize-action-for-an-attribute
1982 bool nsTreeSanitizer::MustDropAttribute(Element
* aElement
,
1983 int32_t aAttrNamespace
,
1984 nsAtom
* aAttrLocalName
) {
1985 // Step 1. Let kind be attribute’s attribute kind.
1986 // Step 2. If kind is unknown and if config["allowUnknownMarkup"] does not
1987 // exist or it config["allowUnknownMarkup"] is false: Return drop.
1989 // TODO: Not clear how to determine if something is an "unknown" attribute.
1990 // https://github.com/WICG/sanitizer-api/issues/147 should probably define
1991 // an explicit list.
1993 // Step 3. If kind is regular and attribute’s local name does not match any
1994 // name in the baseline attribute allow list: Return drop.
1995 if (!sBaselineAttributeAllowlist
->Contains(aAttrLocalName
)) {
1999 // TODO(not specified yet): An element to attributes mapping that is
2000 // considered before the attributes/removeAttributes lists that apply to
2003 int32_t namespaceID
= aElement
->NodeInfo()->NamespaceID();
2004 RefPtr
<nsAtom
> nameAtom
= aElement
->NodeInfo()->NameAtom();
2006 if (auto entry
= mElements
->Lookup(ElementName(namespaceID
, nameAtom
))) {
2007 if (entry
->mRemoveAttributes
&&
2008 MatchesAttributeName(*entry
->mRemoveAttributes
, aAttrNamespace
,
2013 if (entry
->mAttributes
) {
2014 if (!MatchesAttributeName(*entry
->mAttributes
, aAttrNamespace
,
2018 // Fall-through to the removeAttributes/attributes lists below.
2023 // Step 4. If attribute matches any attribute match list in config’s attribute
2024 // drop list: Return drop.
2025 if (mRemoveAttributes
&&
2026 MatchesAttributeName(*mRemoveAttributes
, aAttrNamespace
,
2031 // Step 5. If attribute allow list exists in config:
2033 // Step 5.1. Then let allow list be |config|["allowAttributes"].
2034 // Step 6. If attribute does not match any attribute match list in allow
2035 // list: Return drop.
2036 if (!MatchesAttributeName(*mAttributes
, aAttrNamespace
, aAttrLocalName
)) {
2040 // Step 5.2. Otherwise: Let allow list be the default configuration's
2041 // attribute allow list.
2042 // Step 6. If attribute does not match any attribute
2043 // match list in allow list: Return drop.
2044 if (!sDefaultConfigurationAttributeAllowlist
->Contains(aAttrLocalName
)) {
2049 // Step 7. Return keep.
2053 // https://wicg.github.io/sanitizer-api/#handle-funky-elements
2054 bool nsTreeSanitizer::MustDropFunkyAttribute(Element
* aElement
,
2055 int32_t aAttrNamespace
,
2056 nsAtom
* aAttrLocalName
) {
2057 // Step 1. If element’s element interface is HTMLTemplateElement:
2058 // Note: This step is implemented in the main loop of SanitizeChildren.
2060 // Step 2. If element’s element interface has a HTMLHyperlinkElementUtils
2061 // mixin, and if element’s protocol property is "javascript:":
2062 // TODO(https://github.com/WICG/sanitizer-api/issues/168)
2063 if (aAttrLocalName
== nsGkAtoms::href
) {
2064 if (nsCOMPtr
<Link
> link
= do_QueryInterface(aElement
)) {
2065 nsCOMPtr
<nsIURI
> uri
= link
->GetURI();
2066 if (uri
&& uri
->SchemeIs("javascript")) {
2067 // Step 2.1. Remove the `href` attribute from element.
2073 // Step 3. if element’s element interface is HTMLFormElement, and if element’s
2074 // action attribute is a URL with "javascript:" protocol:
2075 if (auto* form
= HTMLFormElement::FromNode(aElement
)) {
2076 if (aAttrNamespace
== kNameSpaceID_None
&&
2077 aAttrLocalName
== nsGkAtoms::action
) {
2078 nsCOMPtr
<nsIURI
> uri
;
2079 form
->GetURIAttr(aAttrLocalName
, nullptr, getter_AddRefs(uri
));
2080 if (uri
&& uri
->SchemeIs("javascript")) {
2081 // Step 3.1 Remove the `action` attribute from element.
2087 // Step 4. if element’s element interface is HTMLInputElement or
2088 // HTMLButtonElement, and if element’s formaction attribute is a [URL] with
2089 // javascript: protocol
2090 if (aElement
->IsAnyOfHTMLElements(nsGkAtoms::input
, nsGkAtoms::button
) &&
2091 aAttrNamespace
== kNameSpaceID_None
&&
2092 aAttrLocalName
== nsGkAtoms::formaction
) {
2093 // XXX nsGenericHTMLFormControlElementWithState::GetFormAction falls back to
2094 // the document URI.
2095 nsGenericHTMLElement
* el
= nsGenericHTMLElement::FromNode(aElement
);
2096 nsCOMPtr
<nsIURI
> uri
;
2097 el
->GetURIAttr(aAttrLocalName
, nullptr, getter_AddRefs(uri
));
2098 if (uri
&& uri
->SchemeIs("javascript")) {
2099 // Step 4.1 Remove the `formaction` attribute from element.
2107 bool nsTreeSanitizer::SanitizeURL(mozilla::dom::Element
* aElement
,
2108 int32_t aNamespace
, nsAtom
* aLocalName
,
2109 bool aFragmentsOnly
) {
2111 aElement
->GetAttr(aNamespace
, aLocalName
, value
);
2113 // Get value and remove mandatory quotes
2114 static const char* kWhitespace
= "\n\r\t\b";
2115 const nsAString
& v
= nsContentUtils::TrimCharsInSet(kWhitespace
, value
);
2116 // Fragment-only url cannot be harmful.
2117 if (!v
.IsEmpty() && v
.First() == u
'#') {
2120 // if we allow only same-document fragment URLs, stop and remove here
2121 if (aFragmentsOnly
) {
2122 aElement
->UnsetAttr(aNamespace
, aLocalName
, false);
2124 LogMessage("Removed unsafe URI from element attribute.",
2125 aElement
->OwnerDoc(), aElement
, aLocalName
);
2130 nsIScriptSecurityManager
* secMan
= nsContentUtils::GetSecurityManager();
2131 uint32_t flags
= nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL
;
2133 nsCOMPtr
<nsIURI
> attrURI
;
2135 NS_NewURI(getter_AddRefs(attrURI
), v
, nullptr, aElement
->GetBaseURI());
2136 if (NS_SUCCEEDED(rv
)) {
2137 if (mCidEmbedsOnly
&& kNameSpaceID_None
== aNamespace
) {
2138 if (nsGkAtoms::src
== aLocalName
|| nsGkAtoms::background
== aLocalName
) {
2139 // comm-central uses a hack that makes nsIURIs created with cid: specs
2140 // actually have an about:blank spec. Therefore, nsIURI facilities are
2141 // useless for cid: when comm-central code is participating.
2142 if (!(v
.Length() > 4 && (v
[0] == 'c' || v
[0] == 'C') &&
2143 (v
[1] == 'i' || v
[1] == 'I') && (v
[2] == 'd' || v
[2] == 'D') &&
2145 rv
= NS_ERROR_FAILURE
;
2147 } else if (nsGkAtoms::cdgroup_
== aLocalName
||
2148 nsGkAtoms::altimg_
== aLocalName
||
2149 nsGkAtoms::definitionURL_
== aLocalName
) {
2150 // Gecko doesn't fetch these now and shouldn't in the future, but
2151 // in case someone goofs with these in the future, let's drop them.
2152 rv
= NS_ERROR_FAILURE
;
2154 rv
= secMan
->CheckLoadURIWithPrincipal(sNullPrincipal
, attrURI
, flags
,
2158 rv
= secMan
->CheckLoadURIWithPrincipal(sNullPrincipal
, attrURI
, flags
, 0);
2161 if (NS_FAILED(rv
)) {
2162 aElement
->UnsetAttr(aNamespace
, aLocalName
, false);
2164 LogMessage("Removed unsafe URI from element attribute.",
2165 aElement
->OwnerDoc(), aElement
, aLocalName
);
2172 void nsTreeSanitizer::Sanitize(DocumentFragment
* aFragment
) {
2173 // If you want to relax these preconditions, be sure to check the code in
2174 // here that notifies / does not notify or that fires mutation events if
2176 MOZ_ASSERT(!aFragment
->IsInUncomposedDoc(), "The fragment is in doc?");
2178 mFullDocument
= false;
2179 SanitizeChildren(aFragment
);
2182 void nsTreeSanitizer::Sanitize(Document
* aDocument
) {
2183 // If you want to relax these preconditions, be sure to check the code in
2184 // here that notifies / does not notify or that fires mutation events if
2187 MOZ_ASSERT(!aDocument
->GetContainer(), "The document is in a shell.");
2188 RefPtr
<mozilla::dom::Element
> root
= aDocument
->GetRootElement();
2189 MOZ_ASSERT(root
->IsHTMLElement(nsGkAtoms::html
), "Not HTML root.");
2192 mFullDocument
= true;
2193 SanitizeChildren(aDocument
);
2196 void nsTreeSanitizer::SanitizeChildren(nsINode
* aRoot
) {
2197 nsIContent
* node
= aRoot
->GetFirstChild();
2199 if (node
->IsElement()) {
2200 mozilla::dom::Element
* elt
= node
->AsElement();
2201 mozilla::dom::NodeInfo
* nodeInfo
= node
->NodeInfo();
2202 nsAtom
* localName
= nodeInfo
->NameAtom();
2203 int32_t ns
= nodeInfo
->NamespaceID();
2205 if (MustPrune(ns
, localName
, elt
)) {
2207 LogMessage("Removing unsafe node.", elt
->OwnerDoc(), elt
);
2209 RemoveAllAttributes(elt
);
2210 nsIContent
* descendant
= node
;
2211 while ((descendant
= descendant
->GetNextNode(node
))) {
2212 if (descendant
->IsElement()) {
2213 RemoveAllAttributes(descendant
->AsElement());
2216 nsIContent
* next
= node
->GetNextNonChildNode(aRoot
);
2217 node
->RemoveFromParent();
2221 if (auto* templateEl
= HTMLTemplateElement::FromNode(elt
)) {
2222 // traverse into the DocFragment content attribute of template elements
2223 bool wasFullDocument
= mFullDocument
;
2224 mFullDocument
= false;
2225 RefPtr
<DocumentFragment
> frag
= templateEl
->Content();
2226 SanitizeChildren(frag
);
2227 mFullDocument
= wasFullDocument
;
2229 if (!mIsForSanitizerAPI
&& nsGkAtoms::style
== localName
) {
2230 // If styles aren't allowed, style elements got pruned above. Even
2231 // if styles are allowed, non-HTML, non-SVG style elements got pruned
2233 NS_ASSERTION(ns
== kNameSpaceID_XHTML
|| ns
== kNameSpaceID_SVG
,
2234 "Should have only HTML or SVG here!");
2235 if (SanitizeInlineStyle(elt
, StyleSanitizationKind::Standard
) &&
2237 LogMessage("Removed some rules and/or properties from stylesheet.",
2241 AllowedAttributes allowed
;
2242 allowed
.mStyle
= mAllowStyles
;
2243 if (ns
== kNameSpaceID_XHTML
) {
2244 allowed
.mNames
= sAttributesHTML
;
2245 allowed
.mURLs
= kURLAttributesHTML
;
2247 allowed
.mNames
= sAttributesSVG
;
2248 allowed
.mURLs
= kURLAttributesSVG
;
2249 allowed
.mXLink
= true;
2251 SanitizeAttributes(elt
, allowed
);
2252 node
= node
->GetNextNonChildNode(aRoot
);
2255 if (MustFlatten(ns
, localName
)) {
2257 LogMessage("Flattening unsafe node (descendants are preserved).",
2258 elt
->OwnerDoc(), elt
);
2260 RemoveAllAttributes(elt
);
2261 nsCOMPtr
<nsIContent
> next
= node
->GetNextNode(aRoot
);
2262 nsCOMPtr
<nsIContent
> parent
= node
->GetParent();
2263 nsCOMPtr
<nsIContent
> child
; // Must keep the child alive during move
2265 while ((child
= node
->GetFirstChild())) {
2266 nsCOMPtr
<nsINode
> refNode
= node
;
2267 parent
->InsertBefore(*child
, refNode
, rv
);
2272 node
->RemoveFromParent();
2276 NS_ASSERTION(ns
== kNameSpaceID_XHTML
|| ns
== kNameSpaceID_SVG
||
2277 ns
== kNameSpaceID_MathML
,
2278 "Should have only HTML, MathML or SVG here!");
2279 AllowedAttributes allowed
;
2280 if (ns
== kNameSpaceID_XHTML
) {
2281 allowed
.mNames
= sAttributesHTML
;
2282 allowed
.mURLs
= kURLAttributesHTML
;
2283 allowed
.mStyle
= mAllowStyles
;
2284 allowed
.mDangerousSrc
= nsGkAtoms::img
== localName
&& !mCidEmbedsOnly
;
2285 SanitizeAttributes(elt
, allowed
);
2286 } else if (ns
== kNameSpaceID_SVG
) {
2287 allowed
.mNames
= sAttributesSVG
;
2288 allowed
.mURLs
= kURLAttributesSVG
;
2289 allowed
.mXLink
= true;
2290 allowed
.mStyle
= mAllowStyles
;
2291 SanitizeAttributes(elt
, allowed
);
2293 allowed
.mNames
= sAttributesMathML
;
2294 allowed
.mURLs
= kURLAttributesMathML
;
2295 allowed
.mXLink
= true;
2296 SanitizeAttributes(elt
, allowed
);
2298 node
= node
->GetNextNode(aRoot
);
2301 NS_ASSERTION(!node
->GetFirstChild(), "How come non-element node had kids?");
2302 nsIContent
* next
= node
->GetNextNonChildNode(aRoot
);
2303 if (!mAllowComments
&& node
->IsComment()) {
2304 node
->RemoveFromParent();
2310 void nsTreeSanitizer::RemoveAllAttributes(Element
* aElement
) {
2311 const nsAttrName
* attrName
;
2312 while ((attrName
= aElement
->GetAttrNameAt(0))) {
2313 int32_t attrNs
= attrName
->NamespaceID();
2314 RefPtr
<nsAtom
> attrLocal
= attrName
->LocalName();
2315 aElement
->UnsetAttr(attrNs
, attrLocal
, false);
2319 void nsTreeSanitizer::RemoveAllAttributesFromDescendants(
2320 mozilla::dom::Element
* aElement
) {
2321 nsIContent
* node
= aElement
->GetFirstChild();
2323 if (node
->IsElement()) {
2324 mozilla::dom::Element
* elt
= node
->AsElement();
2325 RemoveAllAttributes(elt
);
2327 node
= node
->GetNextNode(aElement
);
2331 void nsTreeSanitizer::LogMessage(const char* aMessage
, Document
* aDoc
,
2332 Element
* aElement
, nsAtom
* aAttr
) {
2335 msg
.AssignASCII(aMessage
);
2337 msg
.Append(u
" Element: "_ns
+ aElement
->LocalName() + u
"."_ns
);
2340 msg
.Append(u
" Attribute: "_ns
+ nsDependentAtomString(aAttr
) + u
"."_ns
);
2343 if (mInnerWindowID
) {
2344 nsContentUtils::ReportToConsoleByWindowID(
2345 msg
, nsIScriptError::warningFlag
, "DOM"_ns
, mInnerWindowID
);
2347 nsContentUtils::ReportToConsoleNonLocalized(
2348 msg
, nsIScriptError::warningFlag
, "DOM"_ns
, aDoc
);
2353 void nsTreeSanitizer::InitializeStatics() {
2354 MOZ_ASSERT(!sElementsHTML
, "Initializing a second time.");
2356 sElementsHTML
= new AtomsTable(std::size(kElementsHTML
));
2357 for (uint32_t i
= 0; kElementsHTML
[i
]; i
++) {
2358 sElementsHTML
->Insert(kElementsHTML
[i
]);
2361 sAttributesHTML
= new AtomsTable(std::size(kAttributesHTML
));
2362 for (uint32_t i
= 0; kAttributesHTML
[i
]; i
++) {
2363 sAttributesHTML
->Insert(kAttributesHTML
[i
]);
2366 sPresAttributesHTML
= new AtomsTable(std::size(kPresAttributesHTML
));
2367 for (uint32_t i
= 0; kPresAttributesHTML
[i
]; i
++) {
2368 sPresAttributesHTML
->Insert(kPresAttributesHTML
[i
]);
2371 sElementsSVG
= new AtomsTable(std::size(kElementsSVG
));
2372 for (uint32_t i
= 0; kElementsSVG
[i
]; i
++) {
2373 sElementsSVG
->Insert(kElementsSVG
[i
]);
2376 sAttributesSVG
= new AtomsTable(std::size(kAttributesSVG
));
2377 for (uint32_t i
= 0; kAttributesSVG
[i
]; i
++) {
2378 sAttributesSVG
->Insert(kAttributesSVG
[i
]);
2381 sElementsMathML
= new AtomsTable(std::size(kElementsMathML
));
2382 for (uint32_t i
= 0; kElementsMathML
[i
]; i
++) {
2383 sElementsMathML
->Insert(kElementsMathML
[i
]);
2386 sAttributesMathML
= new AtomsTable(std::size(kAttributesMathML
));
2387 for (uint32_t i
= 0; kAttributesMathML
[i
]; i
++) {
2388 sAttributesMathML
->Insert(kAttributesMathML
[i
]);
2391 sBaselineAttributeAllowlist
=
2392 new AtomsTable(std::size(kBaselineAttributeAllowlist
));
2393 for (const auto* atom
: kBaselineAttributeAllowlist
) {
2394 sBaselineAttributeAllowlist
->Insert(atom
);
2397 sBaselineElementAllowlist
=
2398 new AtomsTable(std::size(kBaselineElementAllowlist
));
2399 for (const auto* atom
: kBaselineElementAllowlist
) {
2400 sBaselineElementAllowlist
->Insert(atom
);
2403 sDefaultConfigurationAttributeAllowlist
=
2404 new AtomsTable(std::size(kDefaultConfigurationAttributeAllowlist
));
2405 for (const auto* atom
: kDefaultConfigurationAttributeAllowlist
) {
2406 sDefaultConfigurationAttributeAllowlist
->Insert(atom
);
2409 sDefaultConfigurationElementAllowlist
=
2410 new AtomsTable(std::size(kDefaultConfigurationElementAllowlist
));
2411 for (const auto* atom
: kDefaultConfigurationElementAllowlist
) {
2412 sDefaultConfigurationElementAllowlist
->Insert(atom
);
2415 nsCOMPtr
<nsIPrincipal
> principal
=
2416 NullPrincipal::CreateWithoutOriginAttributes();
2417 principal
.forget(&sNullPrincipal
);
2420 void nsTreeSanitizer::ReleaseStatics() {
2421 delete sElementsHTML
;
2422 sElementsHTML
= nullptr;
2424 delete sAttributesHTML
;
2425 sAttributesHTML
= nullptr;
2427 delete sPresAttributesHTML
;
2428 sPresAttributesHTML
= nullptr;
2430 delete sElementsSVG
;
2431 sElementsSVG
= nullptr;
2433 delete sAttributesSVG
;
2434 sAttributesSVG
= nullptr;
2436 delete sElementsMathML
;
2437 sElementsMathML
= nullptr;
2439 delete sAttributesMathML
;
2440 sAttributesMathML
= nullptr;
2442 delete sBaselineAttributeAllowlist
;
2443 sBaselineAttributeAllowlist
= nullptr;
2445 delete sBaselineElementAllowlist
;
2446 sBaselineElementAllowlist
= nullptr;
2448 delete sDefaultConfigurationAttributeAllowlist
;
2449 sDefaultConfigurationAttributeAllowlist
= nullptr;
2451 delete sDefaultConfigurationElementAllowlist
;
2452 sDefaultConfigurationElementAllowlist
= nullptr;
2454 NS_IF_RELEASE(sNullPrincipal
);
2457 static int32_t ConvertNamespaceString(const nsAString
& aNamespace
,
2459 mozilla::ErrorResult
& aRv
) {
2460 if (aNamespace
.IsVoid()) {
2461 // NOTE: Currently this ?should? never match any elements, only
2463 return kNameSpaceID_None
;
2466 int32_t namespaceID
= nsNameSpaceManager::GetInstance()->GetNameSpaceID(
2467 aNamespace
, /* aInChromeDoc */ false);
2468 if (namespaceID
== kNameSpaceID_XHTML
|| namespaceID
== kNameSpaceID_MathML
||
2469 namespaceID
== kNameSpaceID_SVG
) {
2472 if (aForAttribute
&& (namespaceID
== kNameSpaceID_XMLNS
||
2473 namespaceID
== kNameSpaceID_XLink
)) {
2477 aRv
.ThrowTypeError("Invalid namespace: \""_ns
+
2478 NS_ConvertUTF16toUTF8(aNamespace
) + "\"."_ns
);
2479 return kNameSpaceID_Unknown
;
2482 nsTreeSanitizer::ElementNameSet
nsTreeSanitizer::ConvertElements(
2483 const nsTArray
<OwningStringOrSanitizerElementNamespace
>& aElements
,
2484 mozilla::ErrorResult
& aRv
) {
2485 ElementNameSet
set(aElements
.Length());
2487 for (const auto& entry
: aElements
) {
2488 if (entry
.IsString()) {
2489 RefPtr
<nsAtom
> nameAtom
= NS_AtomizeMainThread(entry
.GetAsString());
2490 // The default namespace for elements is HTML.
2491 ElementName
elemName(kNameSpaceID_XHTML
, std::move(nameAtom
));
2492 set
.Insert(elemName
);
2494 const auto& elemNamespace
= entry
.GetAsSanitizerElementNamespace();
2496 int32_t namespaceID
=
2497 ConvertNamespaceString(elemNamespace
.mNamespace
, false, aRv
);
2501 RefPtr
<nsAtom
> nameAtom
= NS_AtomizeMainThread(elemNamespace
.mName
);
2502 ElementName
elemName(namespaceID
, std::move(nameAtom
));
2503 set
.Insert(elemName
);
2510 nsTreeSanitizer::ElementsToAttributesMap
2511 nsTreeSanitizer::ConvertElementsWithAttributes(
2512 const nsTArray
<OwningStringOrSanitizerElementNamespaceWithAttributes
>&
2514 mozilla::ErrorResult
& aRv
) {
2515 ElementsToAttributesMap map
;
2517 for (const auto& entry
: aElements
) {
2518 if (entry
.IsString()) {
2519 RefPtr
<nsAtom
> nameAtom
= NS_AtomizeMainThread(entry
.GetAsString());
2520 // The default namespace for elements is HTML.
2521 ElementName
elemName(kNameSpaceID_XHTML
, std::move(nameAtom
));
2522 // No explicit list of attributes to allow/remove.
2523 map
.InsertOrUpdate(elemName
, ElementWithAttributes
{});
2525 const auto& elemNamespace
=
2526 entry
.GetAsSanitizerElementNamespaceWithAttributes();
2528 ElementWithAttributes elemWithAttributes
;
2530 if (elemNamespace
.mAttributes
.WasPassed()) {
2531 elemWithAttributes
.mAttributes
.emplace(
2532 ConvertAttributes(elemNamespace
.mAttributes
.Value(), aRv
));
2538 if (elemNamespace
.mRemoveAttributes
.WasPassed()) {
2539 elemWithAttributes
.mRemoveAttributes
.emplace(
2540 ConvertAttributes(elemNamespace
.mRemoveAttributes
.Value(), aRv
));
2546 int32_t namespaceID
=
2547 ConvertNamespaceString(elemNamespace
.mNamespace
, false, aRv
);
2552 RefPtr
<nsAtom
> nameAtom
= NS_AtomizeMainThread(elemNamespace
.mName
);
2553 ElementName
elemName(namespaceID
, std::move(nameAtom
));
2555 map
.InsertOrUpdate(elemName
, std::move(elemWithAttributes
));
2562 nsTreeSanitizer::AttributeNameSet
nsTreeSanitizer::ConvertAttributes(
2563 const nsTArray
<OwningStringOrSanitizerAttributeNamespace
>& aAttributes
,
2565 AttributeNameSet
set(aAttributes
.Length());
2566 for (const auto& entry
: aAttributes
) {
2567 if (entry
.IsString()) {
2568 RefPtr
<nsAtom
> nameAtom
= NS_AtomizeMainThread(entry
.GetAsString());
2569 // The default namespace for attributes is the "null" namespace.
2570 AttributeName
attrName(kNameSpaceID_None
, std::move(nameAtom
));
2571 set
.Insert(attrName
);
2573 const auto& attrNamespace
= entry
.GetAsSanitizerAttributeNamespace();
2574 int32_t namespaceID
=
2575 ConvertNamespaceString(attrNamespace
.mNamespace
, true, aRv
);
2579 RefPtr
<nsAtom
> attrAtom
= NS_AtomizeMainThread(attrNamespace
.mName
);
2580 AttributeName
attrName(namespaceID
, std::move(attrAtom
));
2581 set
.Insert(attrName
);
2587 void nsTreeSanitizer::WithWebSanitizerOptions(
2588 nsIGlobalObject
* aGlobal
, const mozilla::dom::SanitizerConfig
& aOptions
,
2590 if (StaticPrefs::dom_security_sanitizer_logging()) {
2591 mLogRemovals
= true;
2592 if (nsPIDOMWindowInner
* win
= aGlobal
->GetAsInnerWindow()) {
2593 mInnerWindowID
= win
->WindowID();
2597 mIsForSanitizerAPI
= true;
2599 if (aOptions
.mComments
.WasPassed()) {
2600 mAllowComments
= aOptions
.mComments
.Value();
2602 if (aOptions
.mCustomElements
.WasPassed()) {
2603 mAllowCustomElements
= aOptions
.mCustomElements
.Value();
2605 if (aOptions
.mUnknownMarkup
.WasPassed()) {
2606 mAllowUnknownMarkup
= aOptions
.mUnknownMarkup
.Value();
2609 if (aOptions
.mElements
.WasPassed()) {
2611 ConvertElementsWithAttributes(aOptions
.mElements
.Value(), aRv
));
2617 if (aOptions
.mRemoveElements
.WasPassed()) {
2618 mRemoveElements
.emplace(
2619 ConvertElements(aOptions
.mRemoveElements
.Value(), aRv
));
2625 if (aOptions
.mReplaceWithChildrenElements
.WasPassed()) {
2626 mReplaceWithChildrenElements
.emplace(
2627 ConvertElements(aOptions
.mReplaceWithChildrenElements
.Value(), aRv
));
2633 if (aOptions
.mAttributes
.WasPassed()) {
2634 mAttributes
.emplace(ConvertAttributes(aOptions
.mAttributes
.Value(), aRv
));
2640 if (aOptions
.mRemoveAttributes
.WasPassed()) {
2641 mRemoveAttributes
.emplace(
2642 ConvertAttributes(aOptions
.mRemoveAttributes
.Value(), aRv
));