Skip to content

Commit f2ed678

Browse files
authored
fix(security): add dompurify for raw document string pre-cleaning on readability to avoid xss attack (#2000)
1 parent 8de8501 commit f2ed678

File tree

3 files changed

+44
-4
lines changed

3 files changed

+44
-4
lines changed

apps/main/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"@openpanel/web": "1.0.1",
3232
"@sentry/electron": "5.7.0",
3333
"builder-util-runtime": "9.2.10",
34+
"dompurify": "~3.2.2",
3435
"electron-context-menu": "4.0.4",
3536
"electron-log": "5.2.3",
3637
"electron-squirrel-startup": "1.0.1",

apps/main/src/lib/readability.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Readability } from "@mozilla/readability"
22
import { name, version } from "@pkg"
3+
import DOMPurify from "dompurify"
34
import { parseHTML } from "linkedom"
45
import { fetch } from "ofetch"
56

@@ -8,7 +9,7 @@ import { isDev } from "~/env"
89
const userAgents = `Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 ${name}/${version}`
910

1011
export async function readability(url: string) {
11-
const documentString = await fetch(url, {
12+
const dirtyDocumentString = await fetch(url, {
1213
headers: {
1314
"User-Agent": userAgents,
1415
Accept: "text/html",
@@ -26,11 +27,14 @@ export async function readability(url: string) {
2627
return res.text()
2728
})
2829

30+
// For avoid xss attack from readability, the raw document string should be purified.
31+
const cleanedDocumentString = DOMPurify.sanitize(dirtyDocumentString)
32+
2933
// FIXME: linkedom does not handle relative addresses in strings. Refer to
3034
// @see https://github.com/WebReflection/linkedom/issues/153
3135
// JSDOM handles it correctly, but JSDOM introduces canvas binding.
3236

33-
const { document } = parseHTML(documentString)
37+
const { document } = parseHTML(cleanedDocumentString)
3438
const baseUrl = new URL(url).origin
3539

3640
document.querySelectorAll("a").forEach((a) => {

pnpm-lock.yaml

Lines changed: 37 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)