# Safe content The only sanctioned way to render provider content (posts, bios, comments, messages, link previews, display names) in the web UI. Proposal §4.5. Provider text becomes a closed rich-text AST (`text`, `linebreak`, `emoji`, `link`, `mention`, `hashtag` inside `paragraph`s) before it reaches React. No node can hold HTML, attributes or styles. - `parsePlainText` handles plain provider text. `parseProviderHtml` handles the Mastodon/PeerTube HTML subset. Neither renders HTML. `script`, `style`, `iframe`, `svg`, `math`, `form`, `template` and similar elements are dropped along with their content. Other tags are unwrapped to text. - Links must be absolute http(s) URLs with no credentials, checked by `parseSafeHttpUrl`. Anything else stays as plain text that can't be clicked. Hosts are shown in punycode, and the real host is shown when a link's label doesn't start with it. - All media (`emoji`, preview images) goes through `toProxiedMediaUrl` (default `/api/media-proxy?url=…`). The renderer drops any `src` that isn't a canonical proxy URL. - Bidi override/isolate characters are stripped from all text. Display names also lose zero-width characters, and `DisplayName` flags mixed-script names that use look-alike letters. - Limits: 20k input chars, 2,000 nodes, nesting depth 32, 2,048-char URLs. The tokenizer makes one forward pass, so its run time grows linearly with input size. `@tactical-media-broadcast-hub/safe-content/react` exports `RichText`, `LinkPreviewCard`, `DisplayName` and `SafeLink`. They re-validate every prop with `coerceRichTextDocument`/`parseLinkPreview`, so an AST loaded from the DB or the network is as safe as a freshly parsed one. `@tactical-media-broadcast-hub/safe-content/eslint` exports `noRawHtmlSinks`, a flat-config block that bans `dangerouslySetInnerHTML`, `innerHTML`/`outerHTML`, `insertAdjacentHTML`, `document.write`, `DOMParser.parseFromString`, `eval` and `new Function` outside this package. Spread it into the root `eslint.config.mjs`. `@tactical-media-broadcast-hub/safe-content/corpus` exports the malicious-content corpus for `packages/testing` and the Playwright suites.