Merge pull request #1326 from PicPeak/fix/sanitize-html-2.17.7-main

fix(security): bump sanitize-html to 2.17.7
This commit is contained in:
Paul Nothaft
2026-09-07 09:18:27 +02:00
committed by GitHub
5 changed files with 149 additions and 16 deletions
+5 -1
View File
@@ -13,5 +13,9 @@ module.exports = {
testMatch: [
'**/__tests__/**/*.test.js'
],
setupFilesAfterEnv: ['<rootDir>/jest.setup.js']
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
// sanitize-html's htmlparser2 12 is ESM-only; see jest.sanitizeHtml.js.
moduleNameMapper: {
'^sanitize-html$': '<rootDir>/jest.sanitizeHtml.js'
}
};
+18
View File
@@ -0,0 +1,18 @@
/**
* sanitize-html 2.17.6+ depends on htmlparser2 12, which ships ESM only.
* Node 22.12+ loads it fine through require(esm); Jest 29's CommonJS module
* registry cannot evaluate an ESM file and fails every suite that imports a
* route or service using the sanitiser. Rather than bolting a Babel
* transform onto node_modules for one dependency, hand this single module to
* Node's own loader.
*
* process.getBuiltinModule (Node 22.3+) is the real core `module` even inside
* Jest — a plain require('module') here returns Jest's wrapper, whose
* createRequire() hands back an empty object for this package. createRequire()
* on the real one resolves from backend/node_modules exactly like production.
*
* Wired in via moduleNameMapper in jest.config.js. The module is stateless,
* so sharing one instance across test files changes nothing; it just cannot
* be jest.mock()ed, and nothing mocks it.
*/
module.exports = process.getBuiltinModule('module').createRequire(__filename)('sanitize-html');
+110 -6
View File
@@ -52,7 +52,7 @@
"postcss": "8.5.23",
"qrcode": "^1.5.4",
"react-i18next": "^15.6.0",
"sanitize-html": "2.17.5",
"sanitize-html": "2.17.7",
"sharp": "0.35.3",
"sqlite3": "^5.1.6",
"swagger-jsdoc": "^6.2.8",
@@ -71,7 +71,7 @@
"supertest": "^6.3.3"
},
"engines": {
"node": "^20.19.0 || >=22"
"node": ">=22.12.0"
}
},
"node_modules/@apidevtools/json-schema-ref-parser": {
@@ -11050,18 +11050,122 @@
"license": "MIT"
},
"node_modules/sanitize-html": {
"version": "2.17.5",
"resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.17.5.tgz",
"integrity": "sha512-ZmU1joGRrvoyctKIiuwUxqR6moLoU2Wk+2bMccN6f7UwhAmwYDvWziqPxRDDN2Qip62NqnIrVrT9akbL6Wretg==",
"version": "2.17.7",
"resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.17.7.tgz",
"integrity": "sha512-PGtEkc9cbnedU3s9TmzDbpsZ8w086g/0Q8k8/oIO1NLNU3i5k9yn835CrjJSajp1KMmkisbO1qPXxNKO3welAg==",
"license": "MIT",
"dependencies": {
"deepmerge": "^4.2.2",
"escape-string-regexp": "^4.0.0",
"htmlparser2": "^10.1.0",
"htmlparser2": "^12.0.0",
"is-plain-object": "^5.0.0",
"launder": "^1.7.1",
"parse-srcset": "^1.0.2",
"postcss": "^8.3.11"
},
"engines": {
"node": ">=22.12.0"
}
},
"node_modules/sanitize-html/node_modules/dom-serializer": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-3.1.1.tgz",
"integrity": "sha512-4MEa38/QexBob6gFNwu+EGdWvhJ1OKuNwdYY3Y3NyeWDQfnGeDYQUDfIRzWu5B5gsv03so2Uxd28YC6zrsx3Lw==",
"license": "MIT",
"dependencies": {
"domelementtype": "^3.0.0",
"domhandler": "^6.0.0",
"entities": "^8.0.0"
},
"engines": {
"node": ">=20.19.0"
},
"funding": {
"type": "github",
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
}
},
"node_modules/sanitize-html/node_modules/domelementtype": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-3.0.0.tgz",
"integrity": "sha512-umCQid3jKbDmVjx8jGaW7uUykm4DEUeyV21hPxNMo2nV955DhUThwqyOIDtreepP31hl84X7G5U9ZfsWvIB3Pg==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fb55"
}
],
"license": "BSD-2-Clause",
"engines": {
"node": ">=20.19.0"
}
},
"node_modules/sanitize-html/node_modules/domhandler": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-6.0.1.tgz",
"integrity": "sha512-gYzvtM72ZtxQO0T048kd6HWSbbGCNOUwcnfQ01cqIJ4X2IYKFFHZ5mKvrQETcFXxsRObZulDaKmy//R7TPtsBg==",
"license": "BSD-2-Clause",
"dependencies": {
"domelementtype": "^3.0.0"
},
"engines": {
"node": ">=20.19.0"
},
"funding": {
"type": "github",
"url": "https://github.com/fb55/domhandler?sponsor=1"
}
},
"node_modules/sanitize-html/node_modules/domutils": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-4.0.2.tgz",
"integrity": "sha512-qI4JLRKnSzqFqr7hAlS5xQDusBCjKSEG4t4+7aNrIQMHBcsC2TGEhuyABJdYkgSewL57PNLYEiibY2iPKhKpaA==",
"license": "BSD-2-Clause",
"dependencies": {
"dom-serializer": "^3.0.0",
"domelementtype": "^3.0.0",
"domhandler": "^6.0.0"
},
"engines": {
"node": ">=20.19.0"
},
"funding": {
"type": "github",
"url": "https://github.com/fb55/domutils?sponsor=1"
}
},
"node_modules/sanitize-html/node_modules/entities": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz",
"integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=20.19.0"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/sanitize-html/node_modules/htmlparser2": {
"version": "12.0.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-12.0.0.tgz",
"integrity": "sha512-Tz7u1i95/g2x2jz81+x0FBVhBhY5aRTvD3tXXdFaljuNdzDLJ8UGNRrTcj2cgQvAg3iW/h77Fz15nLW0L0CrZw==",
"funding": [
"https://github.com/fb55/htmlparser2?sponsor=1",
{
"type": "github",
"url": "https://github.com/sponsors/fb55"
}
],
"license": "MIT",
"dependencies": {
"domelementtype": "^3.0.0",
"domhandler": "^6.0.0",
"domutils": "^4.0.2",
"entities": "^8.0.0"
},
"engines": {
"node": ">=20.19.0"
}
},
"node_modules/selderee": {
+2 -2
View File
@@ -4,7 +4,7 @@
"description": "Backend for PicPeak event photo sharing platform",
"main": "server.js",
"engines": {
"node": "^20.19.0 || >=22"
"node": ">=22.12.0"
},
"scripts": {
"start": "node server.js",
@@ -62,7 +62,7 @@
"postcss": "8.5.23",
"qrcode": "^1.5.4",
"react-i18next": "^15.6.0",
"sanitize-html": "2.17.5",
"sanitize-html": "2.17.7",
"sharp": "0.35.3",
"sqlite3": "^5.1.6",
"swagger-jsdoc": "^6.2.8",
+14 -7
View File
@@ -14,8 +14,8 @@ IFS=$'\n\t'
readonly SCRIPT_VERSION="2.1.0"
readonly APP_NAME="PicPeak"
readonly REPO_URL="https://github.com/PicPeak/picpeak.git"
readonly NODE_VERSION="20"
readonly NODE_MIN_VERSION="20.19.0" # backend engines: ^20.19.0 || >=22 (sharp 0.35, html-to-text 10)
readonly NODE_VERSION="22"
readonly NODE_MIN_VERSION="22.12.0" # backend engines: >=22.12.0 (sanitize-html 2.17.7)
readonly MIN_RAM_DOCKER=2048
readonly MIN_RAM_NATIVE=1024
readonly MIN_DISK_GB=2
@@ -822,6 +822,13 @@ EOF
# Native Installation
################################################################################
# True when a Node.js version satisfies the backend's engines range (>=22.12.0).
node_version_supported() {
local ver="$1"
[[ "$ver" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || return 1
[[ "$(printf '%s\n' "$NODE_MIN_VERSION" "$ver" | sort -V | head -1)" == "$NODE_MIN_VERSION" ]]
}
install_nodejs() {
# --update dispatches here before main() runs detect_os, so detect on demand
if [[ -z "$PACKAGE_MANAGER" ]]; then
@@ -830,8 +837,8 @@ install_nodejs() {
local node_ver
node_ver=$(command_exists node && node -v | cut -d'v' -f2 || echo "0")
# backend engines range is ^20.19.0 || >=22 (Node 21 is excluded by the glob/minimatch family)
if [[ "$(printf '%s\n' "$NODE_MIN_VERSION" "$node_ver" | sort -V | head -1)" == "$NODE_MIN_VERSION" && "${node_ver%%.*}" != "21" ]]; then
# Match sanitize-html's declared Node minimum, including strict npm installs.
if node_version_supported "$node_ver"; then
log_success "Node.js $(node -v) is already installed"
return
fi
@@ -849,10 +856,10 @@ install_nodejs() {
;;
esac
# Package managers won't downgrade a newer Node (e.g. 21), so re-verify before continuing
# Re-verify in case the package manager did not replace an unsupported Node.
node_ver=$(command_exists node && node -v | cut -d'v' -f2 || echo "0")
if [[ "$(printf '%s\n' "$NODE_MIN_VERSION" "$node_ver" | sort -V | head -1)" != "$NODE_MIN_VERSION" || "${node_ver%%.*}" == "21" ]]; then
die "Node.js v$node_ver does not satisfy the backend requirement (^$NODE_MIN_VERSION || >=22); remove the current Node.js, install a supported version, then re-run this script"
if ! node_version_supported "$node_ver"; then
die "Node.js v$node_ver does not satisfy the backend requirement (>=$NODE_MIN_VERSION); remove the current Node.js, install a supported version, then re-run this script"
fi
log_success "Node.js installed: $(node -v)"
}