Appearance
10. Security Model
This chapter is the normative safety contract of MdFlow. The prohibitions in §10.2 and the filters in §10.3 together constitute a sufficient condition for the following top-level guarantee:
10.1 Top-level guarantee
GUARANTEE (XSS-SAFE). For every MdFlow source document S (including untrusted, adversarially-crafted S), a conforming Class B or Class S implementation produces a DOM or HTML output that, when inserted into a host document, introduces:
- no executable script,
- no CSS with active resource URLs (
url(),@import), - no event handler attributes,
- no navigation to non-whitelisted URL schemes,
- no form submission.
A proof sketch is provided in §10.6.
10.2 Prohibitions
A conforming implementation MUST NOT, during any phase of parsing, rendering, or serialization, perform any of the following:
- P-1. Assign to
innerHTML,outerHTML,insertAdjacentHTML, or any API with equivalent raw-HTML injection semantics. - P-2. Invoke
eval,new Function(...),setTimeout(string, ...),setInterval(string, ...), or any API that evaluates source text as code. - P-3. Emit DOM
on*attributes (onclick,onerror, etc.) based on source content. - P-4. Emit a
<script>or<style>element, or any element whose tag is in the HTML scripting or metadata sub-tree, from source content. - P-5. Emit
javascript:,data:,vbscript:,file:, orblob:URLs inhref,src,srcset,xlink:href, or any URL-bearing attribute, unless explicitly whitelisted (§10.3.1). - P-6. Emit
styleattributes or<style>content containingurl(...),expression(...),javascript:, or@import. - P-7. Emit CSS custom properties (
--*) with values controlled by source text without first passing them through the attribute-value escaping of §10.3.2. - P-8. Parse code-block content or inline-code content as markup. Contents of
CodeBlockandCodenodes are opaque text.
10.3 Filters
10.3.1 URL schemes
A URL produced by parsing a Link, Image, or custom-element URL-valued attribute MUST match the following case-insensitive scheme whitelist before the first ::
- Links (
Link.url):https,http,mailto,tel, and relative URLs (starting with/,./,../,#, or?). - Images (
Image.url):https,http, and relative URLs. - Custom-element URL attributes: as specified per extension; core specification permits only the link and image sets.
10.3.1.1 Evasion resistance
Before scheme matching, the URL MUST be pre-processed as follows:
- Strip leading and trailing U+0000 through U+0020 (whitespace + NUL).
- Strip all U+0000 characters anywhere in the URL.
- Decode a single layer of percent-encoding of the first
:character only (to defeatjava%73cript:evasion). Do NOT recursively decode. - Case-fold the scheme (bytes before the first
:) to ASCII lowercase. - Match against the whitelist.
If any of steps 1–3 yield a scheme outside the whitelist, the URL MUST be replaced with the empty string "" and rendered as an inert anchor (<a href=""> with no navigation); the parsed Link node MUST have url: "".
A URL MUST NOT be further processed (e.g., resolved against a base) in a way that could change its scheme after whitelist matching.
10.3.2 Attribute value escaping
Every attribute value emitted in HTML output MUST be escaped such that:
&→&<→<>→>"→"- U+0000 → U+FFFD
Additionally, text emitted as text content MUST be escaped for &, <, and >. Implementations using the DOM APIs satisfy text escaping automatically via textContent or createTextNode.
10.3.3 Custom-element attribute filter
A custom-element attribute is admitted only if its name and value satisfy the grammar in §8.4. Names are ASCII-lowercased for comparison. Names matching on* are rejected regardless of content.
10.4 Content model
Text content MUST be emitted via DOM textContent / createTextNode APIs, or via HTML output that applies the escaping in §10.3.2. At no point in the pipeline MAY source-derived bytes be interpolated into a raw HTML string that is later parsed as HTML.
10.5 Auxiliary DOM hardening
Implementations SHOULD:
- Set
rel="noopener noreferrer"on<a target="_blank">by default. - Set
referrerpolicy="no-referrer-when-downgrade"or stricter on external links. - Use Content Security Policy compatibility (no
unsafe-inlinerequirement) — the specification's emission rules never require inline scripts or styles.
These are RECOMMENDED, not REQUIRED, as they concern host-page configuration rather than source semantics.
10.6 Proof sketch
(informative)
The XSS-SAFE guarantee follows from three lemmas:
- L-1 (No raw HTML). P-1 and P-4 together ensure no source-derived raw HTML ever reaches a DOM parser. All DOM is constructed node-by-node with element kinds from a closed set.
- L-2 (No scripts). P-2, P-3, P-4, and P-5 close every attack vector known to execute script: inline handlers, script elements,
javascript:URLs, and eval-family APIs. - L-3 (No CSS exfiltration). P-6 and P-7 close CSS-based attacks:
url()loading,@importloading,expression()execution.
Given L-1 through L-3, the only source-derived content reaching the DOM is (a) text within textContent, (b) attribute values matching the filter of §10.3.2 and §10.3.3, and (c) URLs matching the scheme whitelist of §10.3.1. Under the user-agent's HTML spec, none of these categories can cause script execution, CSS exfiltration, or navigation to non-whitelisted schemes.
A complete formal proof would require a model of the host DOM; this sketch is informative and identifies the primitive assumptions.
10.7 Plugin security contract
Every plugin registered with a conforming implementation MUST honor this chapter's prohibitions and filters when producing DOM. A plugin that violates them renders the implementation non-conforming. See §9.6 for the per-plugin conformance obligations.
10.8 Defensive depth
Implementations MAY employ defense-in-depth mechanisms (e.g., Trusted Types, sandboxed iframes for custom-element content). These are outside the scope of this specification and do not substitute for the prohibitions and filters above.
10.9 Cross-reference
Every prohibition and filter in this chapter is verified by a vector in the security/ suite of the conformance tests. See §13.4.