Skip to content

feat(http): built-in dependency-free HTML sanitizer for untrusted markup #355

Description

@pathosDev

Follow-up to the HTML/XSS utilities (#352). A conservative, allowlist-based sanitizeHtml(input, options?): SafeHtml for untrusted rich-text, with zero external dependencies (runs on Bun/Node/Deno, no DOM).

Design (ready)

  • Own submodule src/http/sanitizer/: Tokenizer.ts (WHATWG-subset state machine, entity-decoding during tokenization to defeat jav&#x09;ascript:, rawtext mode for script/style, <-before-non-letter → text), Entities.ts (numeric clamping + curated named table; decode-once/re-escape-on-output invariant), Sanitizer.ts.
  • Category D (drop tag + content): script, style, iframe, object, embed, svg, math, template, … (svg/math dropped by default — mXSS posture). Category U (unwrap, keep children): everything else not allowlisted.
  • Attribute allowlist (on* and style always removed); URL-attribute protocol check after entity-decode + control/whitespace strip against http/https/mailto.
  • Output re-serialized from the parsed representation (never raw input slices); tag repair + EOF auto-close; maxInputLength cap → RangeError.
  • Returns SafeHtml so it composes with the html tagged template.

Notes

  • ~800–1000 LOC + tests. Honest residual-risk note required in JSDoc + docs (hand-rolled vs battle-tested DOMPurify/sanitize-html).
  • Docs: separate http/sanitizer page (EN+DE); the http/html-xss page links to it (replacing its "use a dedicated lib" paragraph).
  • Full design captured in the accepted implementation plan.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestpriority: lowNice-to-have / niche / demand-drivensecuritySecurity-relevant — see severity label for impact tierseverity: mediumModerate impact or requires specific conditions

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions