Skip to content

Latest commit

 

History

History
39 lines (34 loc) · 9.06 KB

errors.md

File metadata and controls

39 lines (34 loc) · 9.06 KB

Error Codes

Every code HtmlSecurityCheck reports, its message, and what to change so the content passes. The message is the template with the detail filled in at %s. Codes never change once released; message wording can, so match on code.

Code Message What to do
not-utf8 Content must be UTF-8, this is not: %s Convert the text to UTF-8 before the check. A Latin-1 é from an old export is the usual cause: mb_convert_encoding($html, 'UTF-8', 'Windows-1252') when the source encoding is known. Text typed into a form is already UTF-8.
control-character Content contains a control character: %s Remove the character; the detail names its byte offset. A NUL comes from a cut-off binary paste or a bad conversion, an escape (\033) from terminal output pasted in. Tab, LF and CR are fine.
element-not-allowed %s is not allowed Remove the tag. <script>: put the script in the page template. <?import ...>: bound a behavior in old IE; remove it. A tag inside <!--[if ...]>: the same fix as outside it. <form>, <input>, <button>, <select>, <textarea> and the other form elements: set HtmlSecurityCheck::$allowForms. <style>: $allowStyleElement. <iframe>: $allowEmbeds. <svg>: upload the file and use <img>. A custom element (<my-widget>): use a <div> or <span> with a class. <!DOCTYPE>, <html>, <head>, <body>, <meta>, <title>: paste only the body content, or use the editor's paste-from-Word for a Word document.
event-handler %s= event handler attributes are not allowed Remove the attribute. Put the behavior in the page's own script and select the element by a class or id.
attribute-not-allowed The %s attribute is not allowed Remove the attribute. data-* or another unknown name: use a class instead. srcdoc: use src with a listed host instead. xmlns:*: remove it; only Microsoft Office namespaces pass. formaction: set HtmlSecurityCheck::$allowForms. style: set $allowStyleAttribute, or move the styles to the site's stylesheet.
url-scheme-not-allowed %s uses a URL scheme that is not allowed Use an http:, https:, mailto: or tel: URL, or a relative path. A data: URL passes only as image/... on <img src>; anywhere else, upload the file and link it. A Windows path (\\server\x, `C
iframe-host Embedding frames from %s is not allowed Add the host to HtmlSecurityCheck::$iframeHosts, spelled as it appears in the embed code (player.vimeo.com, not vimeo.com), with no scheme, port or path. An <iframe> with no src has nothing to allow: remove it.
css-not-allowed CSS containing %s is not allowed Remove the construct. expression(, behavior:, -ms-behavior:, -moz-binding: old IE and Firefox only, nothing renders them now. @import: link the stylesheet from the page template. Any other function or at-rule (image-set(, cross-fade(, @layer) is not on the CSS allowlists: use a plain url() or a listed one, or move the rule to the site's stylesheet. [value^=, [href$=, [name*=: use an exact match ([value=) or a class; on style, src and class these selectors pass. unicode-range: drop it from @font-face. A backslash outside a comment or quoted string, or inside a quoted url(): write the character itself. url(data:...): upload the image and use its path. If the detail is the start of the block rather than a token, the block was too large or too complex to check: shorten it or move it to the site's stylesheet.
less-than-in-text A < where a browser reads text, not tags: %s The < is inside <style>, <iframe>, <textarea> or a comment that is not <!-- --> (<?php ... ?>, <!x ...>), where a browser reads it as text but strip_tags() with an allow list or an older DOM library reads it as a tag. In a <textarea> write &lt;. In <style>, write a media query range with min-width or max-width ((max-width: 599px), not (width < 600px)) and a < inside a string as \3C ; a <!-- there passes when its --> is in the same block. In an <iframe> remove the fallback content. A <?...> or <!...> comment: write it as <!-- ... --> or remove it. The detail starts at the < and runs to the end of the text.
unclosed-markup %s is not closed Close it: add the missing >, closing quote, --> or end tag (</style>, </iframe>, </textarea>). The detail starts where the open piece began, so the fix is at its end. A cut-off paste is the usual cause.
not-checked Content could not be checked: %s PHP's regex engine stopped at pcre.backtrack_limit or pcre.recursion_limit (the detail says which), so the rest of the content was never read. Only a limit set far below PHP's default does this; restore it in php.ini.

To translate a message, run template through your translation function and put detail back with sprintf(), then encode the whole result, since the detail holds <, > and quotes: echo htmlspecialchars(sprintf(t($violation->template), $violation->detail));. Violation::TEMPLATES holds every template keyed by code, so a translation system can register them all up front.

Three things to know when reading a result:

  • A byte error arrives alone. not-utf8 and control-character stop the check before the content is read as HTML. Fix the bytes and check again; the other problems are reported then.
  • A refused tag reports once. <script onload="x" src="javascript:1"></script> is one element-not-allowed, not three errors. Its attributes, and the content of a refused <style> or <textarea>, are not checked, since the tag is going away.
  • The same problem on five tags is reported once. Errors are deduplicated by code and detail: five <script> tags are one error, five different on* attributes are five. The list stops at HtmlSecurityCheck::$maxErrors distinct problems (50 by default), and unclosed-markup is last, except inside a <!--[if ...]> comment, where it ends at the comment's end.