Node.js-Sicherheitsupdates vom Juni 2026: Container patchen und mit dem Permission Model härten
Node.js hat am 18. Juni 2026 zwölf CVEs gepatcht. So aktualisieren Sie Ihren Container auf 22.23.0/24.17.0/26.3.1 und härten die App minimal ab.
Am 18. Juni 2026 hat das Node.js-Projekt Sicherheitsreleases für alle aktiven Linien veröffentlicht: insgesamt zwölf CVEs, darunter zwei mit Schweregrad HIGH und mehrere, die das Permission Model betreffen. Wenn Sie Node.js im Container betreiben, ist das ein guter Anlass, zwei Dinge auf einmal zu erledigen: die Laufzeit auf die gepatchte Version heben und die App mit dem Permission Model als schlanke Grundhärtung absichern. Dieser Beitrag zeigt beides an einem minimalen, lauffähigen Beispiel.
Was gepatcht wurde
Die gefixten Versionen sind 22.23.0 (LTS), 24.17.0 und 26.3.1. Betroffen sind im Wesentlichen die Linien 22.x, 24.x und 26.x. Zwei Lücken sind mit HIGH bewertet:
- CVE-2026-48933 (HIGH): Ein Integer-Overflow in WebCrypto. Ist die Eingabe an
subtle.encrypt()ein Vielfaches von 2 GiB, kann der Prozess abstürzen (Denial of Service). - CVE-2026-48618 (HIGH): Ein Hostname-Bypass in der TLS-Prüfung durch abweichende Behandlung von Unicode-Punkt-Trennern. Durch eine Normalisierungs-Diskrepanz zwischen Resolver und Verifier lässt sich die Wildcard-Tiefe der Hostname-Prüfung umgehen.
Dazu kommen mehrere MEDIUM-Findings (u. a. HTTP/2-Speicherwachstum, SNI-Matching-Probleme, Leck von Proxy-Zugangsdaten in Fehlermeldungen) sowie drei Bypässe des Permission Models mit Schweregrad LOW, etwa CVE-2026-48617 über process.report.writeReport() und CVE-2026-48935 über FileHandle.utimes(). Die vollständige Liste steht in der offiziellen Ankündigung. Die wichtigste Erkenntnis: Patchen ist Pflicht, und das Permission Model ist eine sinnvolle, aber keine allein tragende Schutzschicht.
Schritt 1: Version im Container prüfen
Zuerst stellen Sie fest, was tatsächlich läuft. Nicht der Image-Tag zählt, sondern die Laufzeit im Container:
docker run --rm node:24-alpine node --version
Liefert das eine Version unterhalb von 24.17.0 (bzw. 22.23.0 in der 22er-Linie oder 26.3.1 in der 26er-Linie), ist der Container verwundbar. Für ein bereits laufendes Deployment:
docker compose exec app node --version
Schritt 2: Auf die gepatchte Version aktualisieren
Der einfachste Weg ist ein präziser Image-Tag. Statt eines beweglichen node:24 pinnen Sie die konkrete Patch-Version und bauen das Image neu:
# Multi-Stage: schlankes, gepatchtes Runtime-Image
FROM node:24.17.0-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
FROM node:24.17.0-alpine
WORKDIR /app
# Nicht als root laufen: das Alpine-Image bringt den User node mit
COPY --from=build --chown=node:node /app /app
USER node
EXPOSE 3000
CMD ["node", "server.js"]
Danach neu bauen und die Version erneut prüfen:
docker compose build --pull app
docker compose up -d app
docker compose exec app node --version # -> v24.17.0
Der --pull-Schalter erzwingt, dass Docker das Basis-Image frisch vom Registry zieht, statt eine veraltete lokale Ebene zu verwenden. Ein exakter Tag wie 24.17.0-alpine ist reproduzierbar; ein loser 24-Tag bekommt das Update zwar irgendwann, aber Sie wissen nicht, wann.
Schritt 3: Die App mit dem Permission Model härten
Das Permission Model ist seit der aktuellen LTS-Linie stabil (nicht mehr experimentell). Mit dem Schalter --permission startet Node.js im Sperrmodus: Zugriff auf das Dateisystem, das Starten von Kindprozessen, Worker-Threads und native Addons sind zunächst verboten. Sie geben nur frei, was die App wirklich braucht.
Ein minimaler Server, der Dateien aus einem Datenverzeichnis liest, sieht so aus:
// server.js
import { createServer } from 'node:http';
import { readFile } from 'node:fs/promises';
createServer(async (req, res) => {
try {
const data = await readFile('/app/data/index.html');
res.writeHead(200, { 'content-type': 'text/html' });
res.end(data);
} catch {
res.writeHead(500);
res.end('error');
}
}).listen(3000);
Gestartet wird er mit aktivem Permission Model und genau einer Freigabe: Lesezugriff auf /app/data:
node --permission --allow-fs-read=/app/data server.js
Versucht die App nun, außerhalb von /app/data zu lesen oder irgendwo zu schreiben, wirft Node.js einen ERR_ACCESS_DENIED – der Schreibzugriff ist ja nicht freigegeben. Braucht die App zusätzlich Schreibrechte oder Kindprozesse, ergänzen Sie gezielt weitere Flags:
node --permission \
--allow-fs-read=/app/data \
--allow-fs-write=/app/data/uploads \
--allow-child-process \
server.js
Weitere Schalter derselben Familie sind --allow-worker (Worker-Threads) und --allow-addons (native Addons). Im Dockerfile wandert das in den CMD:
CMD ["node", "--permission", "--allow-fs-read=/app", "--allow-fs-write=/app/data", "server.js"]
Der Ablauf im Überblick:
+-------------------------+
| node --permission ... |
+------------+------------+
|
v
+-------------------------+
| alles gesperrt |
| (fs, child_process, |
| worker, addons) |
+------------+------------+
|
nur explizite Freigaben
|
v
+-------------------------------------+
| --allow-fs-read=/app/data |
| --allow-fs-write=/app/data/uploads |
+-------------------------------------+
Drei typische Stolperfallen
1. Das Permission Model deckt keine Netzwerk-Restriktion auf der LTS-Linie ab. In den Linien 22.x und 24.x gibt es keine Freigabe, die ausgehende oder eingehende Netzwerkverbindungen einschränkt – die App darf weiterhin uneingeschränkt Sockets öffnen. Eine Netzwerk-Freigabe (--allow-net) existiert erst ab Node.js 25 und damit in der 26er-Linie. Verlassen Sie sich für Netzwerkgrenzen also weiterhin auf Container-Netze, Firewalls oder einen Reverse Proxy, nicht auf das Permission Model.
2. Pfad-Granularität bei --allow-fs-*. Die Freigaben gelten pro Pfad. --allow-fs-read=/app/data erlaubt genau diesen Baum; ein Zugriff auf /app/config schlägt fehl. Ein Verzeichnis wird dabei implizit als Baum behandelt (das Modell hängt intern ein Wildcard an). Zu weite Freigaben wie --allow-fs-read=* heben den Schutz praktisch auf – vergeben Sie so eng wie möglich und listen Sie bei Bedarf mehrere Pfade einzeln auf.
3. Transitive Abhängigkeiten laufen im selben Sicherheitskontext. Das Permission Model unterscheidet nicht zwischen Ihrem Code und dem einer Bibliothek aus node_modules. Ein Paket, das plötzlich einen Kindprozess startet, scheitert genauso an fehlendem --allow-child-process wie Ihr eigener Code – das ist erwünscht, kann aber überraschen. Prüfen Sie nach dem Aktivieren, welche Freigaben Ihre Dependencies real benötigen, statt vorsorglich alles zu öffnen.
Wie es weitergeht
Damit ist der Container aktuell und die App grundgehärtet. Für den Einstieg genügt das; wer tiefer gehen möchte, findet die Details in der offiziellen Ankündigung der Juni-2026-Releases, in der Permissions-Dokumentation sowie in der Node.js-Security-Übersicht. Sinnvolle nächste Schritte sind das Pinnen von Basis-Images per Digest und ein regelmäßiger Blick auf den Node.js-Security-Blog, damit das nächste Update nicht wieder ein Zufallsfund wird.
Hinweis: Die Beiträge dieses Blogs werden unter Einsatz von KI erstellt und vor der Veröffentlichung redaktionell geprüft. Die redaktionelle Verantwortung trägt Emre Yurtbay (siehe Impressum).