diff --git a/apps/backend/Dockerfile.worker b/apps/backend/Dockerfile.worker index e053bb6..1818926 100644 --- a/apps/backend/Dockerfile.worker +++ b/apps/backend/Dockerfile.worker @@ -239,20 +239,24 @@ RUN curl -fsSL https://deb.nodesource.com/setup_${NODE_MAJOR}.x | bash - \ && apt-get install -y --no-install-recommends nodejs \ && rm -rf /var/lib/apt/lists/* \ && npm install -g "npm@${NPM_VERSION}" \ - # CVE-2026-14257 (HIGH, brace-expansion ReDoS): npm 11.18.0 bundles - # brace-expansion 5.0.7 under its OWN node_modules. npm is a BUILD-time tool - # (it installed cdxgen above); the celery worker never invokes it at runtime, - # so this is not runtime-reachable — but 5.0.8 is a drop-in patch, so we - # REPLACE the vulnerable copy rather than blanket-ignore the CVE ID (an - # ignore would also mask brace-expansion findings elsewhere). Verbatim - # npm-pack swap, same pattern as the cdxgen tar override below. - && npm pack brace-expansion@5.0.8 --pack-destination /tmp \ + # brace-expansion ReDoS/OOM chain under npm's OWN node_modules. npm ships + # 5.0.7 (CVE-2026-14257); 5.0.8 fixed that but is itself vulnerable to + # CVE-2026-69152, whose fix landed in 5.0.9. npm is a BUILD-time tool here + # (it installed cdxgen above) and the celery worker never invokes it at + # runtime, so neither is runtime-reachable — we still REPLACE rather than + # blanket-ignore, because an ignore would mask the same CVE ids on copies + # that ARE reachable (cdxgen's tree, overridden below). + # + # Pinning a fixed version is not a one-time act: this line said 5.0.8 until + # 5.0.8 became the vulnerable one. Re-check it whenever the image scan + # flags brace-expansion again. + && npm pack brace-expansion@5.0.9 --pack-destination /tmp \ && rm -rf /usr/lib/node_modules/npm/node_modules/brace-expansion \ && mkdir -p /usr/lib/node_modules/npm/node_modules/brace-expansion \ - && tar -xzf /tmp/brace-expansion-5.0.8.tgz --strip-components=1 \ + && tar -xzf /tmp/brace-expansion-5.0.9.tgz --strip-components=1 \ -C /usr/lib/node_modules/npm/node_modules/brace-expansion \ - && rm -f /tmp/brace-expansion-5.0.8.tgz \ - && node -e "const p=require('/usr/lib/node_modules/npm/node_modules/brace-expansion/package.json');if(p.version!=='5.0.8'){throw new Error('brace-expansion override failed: '+p.version)}" \ + && rm -f /tmp/brace-expansion-5.0.9.tgz \ + && node -e "const p=require('/usr/lib/node_modules/npm/node_modules/brace-expansion/package.json');if(p.version!=='5.0.9'){throw new Error('brace-expansion override failed: '+p.version)}" \ && node --version \ && npm --version @@ -328,6 +332,41 @@ RUN npm install -g --omit=dev --omit=optional "@cyclonedx/cdxgen@${CDXGEN_VERSIO -C /usr/lib/node_modules/@cyclonedx/cdxgen/node_modules/tar \ && rm -f /tmp/tar-7.5.19.tgz \ && node -e "const p=require('/usr/lib/node_modules/@cyclonedx/cdxgen/node_modules/tar/package.json');if(p.version!=='7.5.19'){throw new Error('tar override failed: '+p.version)}" \ + # Force brace-expansion >= 5.0.9 and ip-address >= 10.3.1 (CVE-2026-69152 + # HIGH, CVE-2026-69192). Neither is suppressible as unreached: cdxgen puts + # values it read from the SCANNED repository into glob patterns, and the + # brace-expansion flaw is an uncatchable OOM, so an upstream try/catch + # would not contain it either. + # + # Unlike the tar swap above these are TRANSITIVE, and they land in more + # than one tree: cdxgen's own node_modules AND npm's. The sweep therefore + # walks all of /usr/lib/node_modules, rewrites every copy, and verifies + # each — a surviving stale copy fails the build rather than shipping + # quietly. Both bumps are patch-level on the same major, so no dependency + # range moves and no re-resolution runs. + # + # Scoping this to cdxgen's subtree was the first attempt and it swept + # nothing: cdxgen's own copies are already current, and both findings sit + # under npm's tree instead. A sweep that finds nothing looks identical to + # a sweep that fixed everything, which is why the verification below runs + # per directory rather than once at the end. + # + # Drop this when the cdxgen pin moves to a release carrying the fixes. + && for spec in "brace-expansion@5.0.9" "ip-address@10.3.1"; do \ + name="${spec%@*}"; ver="${spec##*@}"; \ + npm pack "$spec" --pack-destination /tmp; \ + for dir in $(find /usr/lib/node_modules -type d -name "$name" -prune -print); do \ + rm -rf "$dir"; \ + mkdir -p "$dir"; \ + tar -xzf "/tmp/${name}-${ver}.tgz" --strip-components=1 -C "$dir"; \ + got=$(node -p "require('${dir}/package.json').version"); \ + if [ "$got" != "$ver" ]; then \ + echo "override failed: ${dir} is ${got}, want ${ver}" >&2; \ + exit 1; \ + fi; \ + done; \ + rm -f "/tmp/${name}-${ver}.tgz"; \ + done \ && cdxgen --version # ---- Trivy 0.72.0 (Apache-2.0). -------------------------------------------- diff --git a/apps/backend/requirements.txt b/apps/backend/requirements.txt index 7a4fdd6..2d8ec4d 100644 --- a/apps/backend/requirements.txt +++ b/apps/backend/requirements.txt @@ -62,7 +62,9 @@ pyasn1==0.6.4 # future jose bump from silently moving the Fernet surface out from under us. # 2026-06-16 bump 48.0.0 → 48.0.1: fixes GHSA-537c-gmf6-5ccf (HIGH — vulnerable # OpenSSL statically included in the cryptography wheels). -cryptography==48.0.1 +# 2026-08-04 bump 48.0.1 → 50.0.0: CVE-2026-69247 (HIGH) and CVE-2026-69249. +# 50.0.0 is the floor for the first; 49.0.0 would only clear the second. +cryptography==50.0.0 slowapi==0.1.9 email-validator==2.2.0 # Phase 6 PR #18 — async SMTP for the notifications module. aiosmtplib is the