Security Model
Wikitext usually comes from untrusted users. The library aims to output only sanitized React elements — even when the source contains hostile HTML, URLs, or templates — without executing scripts or loading unauthorized media.
What the library guarantees
No HTML injection
- The library never uses
dangerouslySetInnerHTMLand never hands a wikitext or parser HTML string to React. - Output is produced from HAST through
hast-util-to-jsx-runtime. - Dangerous source tags (
script,style,iframe, form controls,svg, HTMLmath, and similar) are escaped as plain text by default; if configured as HTML or inserted into HAST by a plugin, they are dropped as whole pairs with a readable hint and never executed.
Fixed sanitization order
- Plugins run before final sanitization and cannot bypass it.
- The original parse snapshot is read-only; preparation works on a cloned tree.
- Finalization revalidates
target,rel, image authorization, and URL protocols.
Attribute and URL whitelists
- Source HTML keeps only
class,title,dir,lang, and table-related attributes. style,id, event attributes, andsrcdocnever reach the DOM.hrefallows onlyhttp:,https:, andmailto:;srcallows onlyhttp:andhttps:.- Entities are decoded before validation, preventing bypasses such as
javascript:. classis checked against the[A-Za-z0-9_-]safe character set;colspan/rowspanand similar values have bounds.
Image authorization
- Without
resolveImage, no<img>is generated. - Only a
srcreturned by the resolver and validated is authorized; finalization removes unauthorized images. - Authorized images carry
loading="lazy"anddecoding="async". - The library makes no network requests; the browser loads images as ordinary
<img>elements.
Expansion is still untrusted
expandWikitextonly processes template source supplied by the host and never executes HTML or scripts inside it.- Lua is not built in, and
#invokeis not executed. - Expanded output and template source go through the normal semantic normalization, HAST conversion, and final sanitization.
Error isolation
- Each top-level block is wrapped in an error boundary; one failing block does not affect the rest.
- A failure placeholder shows the node type and source and reports through
onRenderError. - Parse and prepare errors belong to the calling stage and are not handled by the view boundary.
What the host must handle
Trusted code
components, semanticComponents, handlers, wikitextPlugins, rehypePlugins, resolveLink, and resolveImage are host code and therefore trusted. They can emit DOM outside the whitelist or interpolate input into dangerous attributes; that output is not sanitized again. Review them like any other React component.
Routing and media addresses
Resolver URLs are protocol-checked, but whether they point to the right page or leak private resources is the host's decision. When integrating a router or media service:
- Use trusted mappings or validated page titles.
- Never interpolate unchecked user input into a position where
javascript:could reach. - Add image CDN hosts to the CSP
img-srcdirective.
Serialized snapshots
serializeWikitextRenderDocument produces plain data. restoreWikitextRenderDocument validates the schema, structure, and budget and re-sanitizes, but you should still restore only snapshots from a trusted server or trusted cache. Never pass arbitrary third-party HAST to WikitextView.
Policy changes
policy is the only adjustable security surface:
- Widening
extraTagsor reducingstripTagsexpands what can be emitted. allowRelativeLinks/allowRelativeImageschange URL validation.allowPluginImageslets rehype plugins insert images, still subject to protocol validation.
Confirm your threat model before changing these; the defaults target untrusted wikitext.
CSP
The library does not depend on eval. Inline styles keep only whitelisted declarations (color, font, alignment, size, border, spacing, and similar); any declaration using url(), expression(), var(), @import, or !important is dropped whole and reported as STYLE_DECLARATION_DROPPED, so styles never fetch remote resources. If CSP forbids inline styles via style-src, those declarations simply do not apply; no script runs. If a resolver authorizes remote images, allow the relevant img-src. External fonts or styles are governed by the host's own CSP.
Known boundaries
- The security model covers DOM and URLs, not users leaving the site through legitimate external links.
- Generated structures such as references, tables of contents, and categories carry no source
idand cannot collide with host DOM. - Custom components can produce arbitrary React output; that is inside the host's trust boundary.
- The parser is pinned to
wikiparser-node@1.48.1; upgrading it requires re-reviewing the rendering and security baseline. - There is no built-in post-sanitize audit or CSP report integration; add those at the host level if needed.
Checklist
- Import
react-wikitext/styles.cssand set the correctlang/diron the container. - Wire
resolveLink/resolveImageonly where needed. - Review all component overrides and plugins as trusted code.
- Restore serialized snapshots only from trusted sources.
- Configure CSP and image hosts for your site.
- Keep the default
policyfor untrusted input; do not loosen sanitization for styling.