aboutsummaryrefslogtreecommitdiff
path: root/src/lib/Utility/sanitizeHtml.ts
diff options
context:
space:
mode:
authorFuwn <[email protected]>2026-06-01 15:45:01 +0000
committerFuwn <[email protected]>2026-06-01 15:45:01 +0000
commit6a7228c06d7af2a28ead1f4ae1830a258c05afae (patch)
tree26a1fc3cc8546bd15dac92910998afb8c2a67fd9 /src/lib/Utility/sanitizeHtml.ts
parentfix(security): allow-list web-push endpoints to stop SSRF (diff)
downloaddue.moe-6a7228c06d7af2a28ead1f4ae1830a258c05afae.tar.xz
due.moe-6a7228c06d7af2a28ead1f4ae1830a258c05afae.zip
fix(security): sanitize third-party RSS HTML before {@html}
The /updates page rendered manga/novel feed fields (content, titles, series names) from mangaupdates/syosetu/wlnupdates via {@html} with no sanitization. CSP already blocks script execution, but injected markup could still phish, redirect, or track. Add sanitizeFeedHtml (DOMPurify with a small safe allow-list) and apply it on ingest. A behaviour-gate test plus a check against the live mangaupdates feed confirm legitimate formatting (entities, <i>/<b>/<a href>) is preserved while <script>, event handlers, <iframe>/<meta>/<style> and javascript: URLs are removed.
Diffstat (limited to 'src/lib/Utility/sanitizeHtml.ts')
-rw-r--r--src/lib/Utility/sanitizeHtml.ts32
1 files changed, 32 insertions, 0 deletions
diff --git a/src/lib/Utility/sanitizeHtml.ts b/src/lib/Utility/sanitizeHtml.ts
new file mode 100644
index 00000000..3d0229e4
--- /dev/null
+++ b/src/lib/Utility/sanitizeHtml.ts
@@ -0,0 +1,32 @@
+import DOMPurify from "dompurify";
+
+const feedConfig = {
+ ALLOWED_TAGS: [
+ "a",
+ "b",
+ "i",
+ "em",
+ "strong",
+ "u",
+ "s",
+ "br",
+ "p",
+ "span",
+ "small",
+ "sup",
+ "sub",
+ "code",
+ ],
+ ALLOWED_ATTR: ["href", "title"],
+ ALLOWED_URI_REGEXP: /^(?:https?|mailto):/i,
+};
+
+/**
+ * Sanitise HTML coming from third-party RSS feeds before it reaches an `{@html}`
+ * sink. Keeps the light formatting these feeds actually use (HTML entities,
+ * `<i>`/`<b>`/`<a href>`) and strips anything that could inject content or
+ * behaviour: `<script>`, event-handler attributes, `<iframe>`/`<meta>`/`<style>`,
+ * `javascript:` URLs, and so on. Browser-only — call it from client code.
+ */
+export const sanitizeFeedHtml = (html: string | undefined | null): string =>
+ html ? DOMPurify.sanitize(html, feedConfig) : "";