Repository navigation
fix(deps): update all dependencies (major) - #255
Merged
Merged
Conversation
Contributor
Author
|
renovate
Bot
force-pushed
the
renovate/major-all-dependencies
branch
7 times, most recently
from
October 6, 2026 20:02
7440b0b to
3419855
Compare
renovate
Bot
force-pushed
the
renovate/major-all-dependencies
branch
from
October 6, 2026 20:36
3419855 to
8e91fae
Compare
Hold back the three majors whose ecosystems have not caught up, and fix the
code the rest of them break.
Held back:
- typescript 7 -> ~6.0.3 (backend): @nestjs/schematics@12 peers >=6.0.0 and
typescript-eslint peers <6.1.0, so 6.0.x is the only version satisfying both.
Frontend stays on 5.9 for the same typescript-eslint bound.
- ioredis 6 -> ^5.3.7: every typeorm release peers ioredis ^5.0.4.
- eslint 10 -> ^9.39.4 (frontend only): eslint-plugin-react has no ESLint 10
release; its latest caps at ^9.7. The backend has no React plugin and runs 10.
- eslint-plugin-react-hooks pinned to ~7.0.1, the version already in use. 7.1
adds rules that flag 11 pre-existing effects, which is not this PR's work.
Raised: vitest ^4 -> ^5, because @vitest/coverage-v8@5 pins peer vitest 5.0.3.
Code changes the upgrades require:
- typeorm 1.0 dropped the string-array `relations` form; use the object form.
- typescript 6 requires an explicit rootDir; set it to the ./src it inferred,
so dist keeps its layout.
- eslint 10 (backend) flags two unused initial assignments and a rethrow with
no `cause`.
- vitest 5 rejects hoisted vi.unmock beside a runtime doMock; use doUnmock.
- vite 8 builds with rolldown: manualChunks takes the function form, and the
minifier is oxc ('esbuild' now needs esbuild installed separately).
Backend: 2016 unit tests, e2e boot against Postgres, lint, nest build all pass.
Frontend: 683 tests, lint, vite build all pass. Lockfiles written with npm 10;
npm ci verified under npm 10 and npm 11.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contributor
Author
Edited/Blocked NotificationRenovate will not automatically rebase this PR, because it does not recognize the last commit author and assumes somebody else may have edited the PR. You can manually request rebase by checking the rebase/retry box above. |
Bump `axios` in the backend and integration tests, update `markdown-it`, and refresh package overrides for several transitive dependencies. This pulls in newer upstream fixes and aligns the lockfiles with the updated backend and test dependency set.
Replace `tenantId: null` with `tenantId: IsNull()` in `FeatureFlagService.getByCodeAndTenant` so global (tenantless) feature flag queries are translated explicitly to SQL `IS NULL`. Update unit tests to assert the new repository call shape.
Refactors several backend and frontend string/parsing paths to avoid regex backtracking and improve determinism (new trim-char utility, safer masking/typography/template parsing, and helper extraction for CSV and header-title logic). It also standardizes runtime usage (`node:` imports, `Number.parseInt`, minor guard/lifecycle cleanups) and updates Sonar test inclusion for `*.spec.tsx`. On the frontend, this adds broad API-layer unit coverage (`bulkNotifications`, `cstar`, `events`, `templates`, `user`) and improves accessibility/keyboard behavior in DataTable and Email Logo menus (button semantics, ARIA states, combobox active descendant handling), with related style and spec updates.
Refactors several UI fragments to use more appropriate HTML semantics: empty/loading messages now render with `output`, and the email header preview in settings is now a `figure` instead of a generic grouped `div`. Tests were updated to assert the new `figure` role, and styling resets default figure margin to preserve layout. It also tightens email header title typing to accept `null` values from persisted tenant settings (`customTitle` and `logoDisplayTitle`).
mgtennant
approved these changes
Oct 9, 2026
mgtennant
left a comment
Collaborator
There was a problem hiding this comment.
tested locally and in dev, found no issues
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
^9.38.0→^10.0.0^9.39.4→^10.0.0^11.0.21→^12.0.0^11.0.6→^12.0.012.1.2^4.0.0→^12.0.0^11.0.6→^12.0.012.1.2^11.0.5→^12.0.0^11.0.6→^12.0.012.1.2^11.0.0→^12.0.0^11.0.3→^12.0.0^11.0.0→^12.0.0^11.0.6→^12.0.012.1.2^11.0.0→^12.0.0^6.0.0→^7.0.0^5.0.0→^6.0.06.1.2^4.0.0→^5.0.05.0.3^4.0.0→^5.0.05.0.3^4.0.0→^5.0.05.0.3v5→v6v6→v7v4→v7v6→v7v1.2.6→v2.1.0^17.0.0→^18.0.018.0.5^17.0.0→^18.0.018.0.5^17.4.2→^18.0.018.0.5^9.38.0→^10.0.010.12.0^9.39.4→^10.0.010.12.0^5.3.7→^6.0.0^4.1.0→^5.0.04.3.0→5.4.1^4.3.2→^5.0.0^28.0.0→^30.0.030.1.2^2.7.3→^3.0.03.0.2(+1)^1.10.1→^2.0.0^9.0.3→^10.0.0v2→v3^0.3.21→^1.0.0^5.7.3→^7.0.0^5.2.2→^7.0.0^1.5.1→^2.0.0^11.1.1→^14.0.0^7.0.0→^8.0.08.3.3(+1)JS-YAML: Quadratic-complexity DoS in merge key handling via repeated aliases
CVE-2026-53550 / GHSA-h67p-54hq-rp68
More information
Details
Summary
A crafted YAML document can trigger algorithmic CPU exhaustion in
js-yamlmerge-key processing (<<) by repeating the same alias many times in a merge sequence.This causes quadratic parse-time behavior relative to input size and can block a Node.js worker/event loop for seconds with a relatively small payload (tens of KB), resulting in denial of service.
Details
The issue is in merge handling inside
lib/loader.js:storeMappingPair(...)iterates every element of a merge sequence when key tag istag:yaml.org,2002:merge.mergeMappings(...).mergeMappings(...)computesObject.keys(source)and performs_hasOwnProperty.call(destination, key)checks for each key.When input is of the form:
a: &a {k0:0, k1:0, ..., kK:0}
b: {<<: [*a, *a, *a, ... repeated M times ...]}
all *a entries refer to the same anchored object. After the first merge, subsequent merges are semantically no-ops, but the parser still reprocesses all keys each time.
Resulting work is O(K * M), while input size is O(K + M), giving quadratic scaling as payload grows.
Relevant code path:
lib/loader.js in storeMappingPair(...) merge branch (keyTag === 'tag:yaml.org,2002:merge')
lib/loader.js mergeMappings(...)
Root cause
File: lib/loader.js
Function: storeMappingPair(state, _result, overridableKeys, keyTag, keyNode,
valueNode, startLine, startLineStart, startPos)
Lines: ~359-366
When the merge value is a sequence (YAML 1.1 <<: [ *a, *a, ... ]), each element
is handed to mergeMappings() without deduplication. mergeMappings() then does
Every alias reference in the sequence resolves (by design) to the SAME object
via state.anchorMap. After the first merge, every subsequent merge of that same
reference is a pure no-op semantically, but still performs:
Total: M * K hasOwnProperty checks + M Object.keys allocations, while the final
object and all observable side effects are identical to a single merge.
YAML semantics for
<<:are idempotent and commutative over duplicate sources,so collapsing duplicates preserves behavior exactly; this isn't a spec trade-off.
PoC
Environment:
js-yaml version: 4.1.1
Node.js: v24.5.0
Platform: arm64 macOS (reproduced consistently)
Reproduction script:
Create many keys in one anchored map (&a).
Merge that same alias repeatedly via <<: [*a, *a, ...].
Measure parse time and compare with control payload using single merge (<<: *a).
Observed repeated runs (same machine):
K=M=1000, input 9,909 bytes: ~33–36 ms
K=M=2000, input 20,909 bytes: ~121–123 ms
K=M=4000, input 42,909 bytes: ~524–537 ms
K=M=6000, input 64,909 bytes: ~1,608–1,829 ms
K=M=8000, input 86,909 bytes: ~3,395–3,565 ms
Control (single merge, similar key counts):
K=2000: ~1–2 ms
K=4000: ~3 ms
K=8000: ~5 ms
Also verified: repeated-merge output equals single-merge output (same key count and same JSON), confirming excess time is redundant computation.
Impact
This is a denial-of-service vulnerability (CPU exhaustion / algorithmic complexity).
Any service parsing untrusted YAML with js-yaml can be impacted, including API backends, CI tools, config processors, and automation services. An attacker can submit crafted YAML to significantly increase CPU time and reduce availability.
Suggested fix:
Dedupe the merge source list by reference before invoking mergeMappings. Any of
the following are minimal and preserve YAML 1.1 merge semantics:
dedupe in storeMappingPair:
Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:LReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
js-yaml: YAML merge-key chains can force quadratic CPU consumption
CVE-2026-59869 / GHSA-52cp-r559-cp3m
More information
Details
Impact
js-yaml can spend quadratic CPU time parsing a document whose size grows only linearly. The issue is triggered by a chain of mappings where each mapping merges the previous one:
For each new mapping, the loader has to enumerate the keys inherited from the previous mapping. With N chained mappings, this results in roughly 1 + 2 + ... + N merged-key visits, i.e., O(N^2) work for O(N) input size.
PoC
From N = 4000 delay become > 1s (doc size < 100K)
Patches
Fix released. The most robust protection is to limit the total number of merged keys per parse call. This should close all past and future edge cases with merge. The default 10K-key limit should be okay in most cases.
Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:HReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
JS-YAML: Quadratic CPU consumption in !!omap resolution (3.x and 4.x) — CVE-2026-59870 fix not backported
GHSA-5p4m-2wfm-xmqj
More information
Details
Quadratic CPU consumption in
!!omapresolution (js-yaml 3.x and 4.x)Summary
resolveYamlOmap()enforces key uniqueness for!!omapsequences with a linearscan (
objectKeys.indexOf(...)) inside the per-element loop, making resolutionO(n²) in the number of entries. A modestly sized YAML document therefore
consumes disproportionate CPU inside
yaml.load(), giving a denial of serviceagainst any consumer that parses untrusted YAML.
!!omapis registered in the default schema(
lib/schema/default.js→require('../type/omap')), so a plainyaml.load(untrustedInput)with no options is affected — no custom schema ornon-default configuration is required.
This is the same weakness as CVE-2026-59870 / GHSA-724g-mxrg-4qvm, which was
fixed in the 5.x line in 5.2.1. That fix was never backported: both currently
maintained legacy lines still carry the original implementation.
Affected versions
objectKeys.indexOf(pairKey)atlib/type/omap.js:29objectKeys.indexOf(pairKey)atlib/type/omap.js:30Set)Both figures are the newest release of each line at the time of writing, so
this is not a "you are on an old version" issue.
Details
lib/type/omap.js(js-yaml 4.3.0):objectKeysgrows by one element per entry, andArray.prototype.indexOfis alinear scan, so resolving an
n-entry!!omapperforms roughly1 + 2 + … + ncomparisons — quadratic inn. The work happens synchronouslyinside
yaml.load(), blocking the event loop for its whole duration.The 5.x line already solves exactly this by tracking seen keys in a
Set(
src/tag/sequence/omap.ts):Proof of concept
Measured (node v20.20.2, default heap, no flags)
js-yaml 4.3.0
js-yaml 3.15.0
Runtime grows by a factor of ~4 for each doubling of
n, which is thesignature of O(n²) (linear growth would be ~2×).
Scaling further: a 2.48 MB document with 150,000 entries blocked
yaml.load()for 10.8 seconds.Impact
Any service that parses attacker-influenced YAML with js-yaml 3.x or 4.x can be
stalled with a small input. Because the loop is synchronous, a single request
blocks the Node.js event loop and stalls every other request in the process —
so the amplification is per-process, not just per-request.
Suggested severity: consistent with CVE-2026-59870 (the same weakness in
5.x), i.e. Availability-only impact, network attack vector, no privileges or
user interaction required.
Suggested fix
Mirror the 5.x fix — replace the linear scan with a
Set:This preserves the existing duplicate-key rejection semantics exactly while
making resolution O(n). A
maxOmapLength-style cap would also work, but theSetmatches what 5.x already ships and requires no new option.References
lib/type/omap.js(3.x, 4.x) — the affected resolverlib/schema/default.js— registers!!omapin the default schemaDiscovery
Found by an automated static-analysis and executed-proof-of-concept scanner run
against js-yaml 4.2.0, then manually verified against 3.15.0 and 4.3.0 by
executing the proof of concept above. All timings in this report were measured
on the current releases of each line, not on the version originally scanned.
Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:HReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
js-yaml: maxTotalMergeKeys does not limit CPU use for empty merge sources
CVE-2026-84375 / GHSA-2883-xcg3-v3hh
More information
Details
Summary
maxTotalMergeKeysdoes not count empty mappings. An attacker can repeatedly merge a large sequence of them and consume significant CPU without reaching the configured limit.Example
For every target, the loader iterates all
Nelements ofarr. This results inO(N * K)work whiletotalMergeKeysremains unchanged.PoC
Observed results:
Impact
An attacker can submit a relatively small YAML document that causes prolonged CPU consumption despite the default
maxTotalMergeKeyslimit.Fix
Count each merge-source mapping as one budget unit, in addition to counting its keys.
Difference with v5
In v3 & v4, merge is enabled by default. So, the severity score is higher.
Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:HReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
js-yaml: maxTotalMergeKeys does not limit CPU use for empty merge sources
GHSA-r3ph-w7gj-g6xm
More information
Details
Summary
maxTotalMergeKeysdoes not count empty mappings. An attacker can repeatedly merge a large sequence of them and consume significant CPU without reaching the configured limit.Example
For every target, the loader iterates all
Nelements ofarr. This results inO(N * K)work whiletotalMergeKeysremains unchanged.PoC
Observed results:
Impact
When merge keys are enabled, an attacker can submit a relatively small YAML document that causes prolonged CPU consumption despite the default
maxTotalMergeKeyslimit.Fix
Count every merge source mapping as one budget unit in addition to counting its keys.
Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:LReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
Nodemailer: Recipient-domain validation bypass via RFC 5322 comment mis-parsing leads to email delivery to an attacker-controlled domain
GHSA-cc9r-2j5m-2m83
More information
Details
Summary
Nodemailer's email-address parser treats an RFC 5322 comment
( ... )inside the domain as a point to concatenate the surrounding text, rather than as folding whitespace (CFWS) that terminates the domain. Consequently a recipient address such asuser@good-corp.com(x)evil.comis parsed and delivered togood-corp.comevil.com(registrable domaincomevil.com, attacker‑controlled), while a conformant RFC 5322 parser terminates the domain at the comment and readsgood-corp.com.An application that decides whether it is allowed to email a recipient by parsing/validating the recipient's domain — with a strict RFC 5322 parser (used without inspecting parse defects) or with a naive prefix/substring allow‑list — and then hands the raw address to Nodemailer for delivery, can be induced to send mail to a domain the attacker controls. This is an Interpretation Conflict (CWE‑436), the same class as CVE‑2025‑13033, reached through the RFC 5322 comment construct (the "Comments" technique in PortSwigger's Splitting the email atom research, which produced a Postfix fix).
Severity is Moderate: exploitation requires the app's domain check to disagree with Nodemailer (see Impact for exactly which parsers do and do not). Verified end‑to‑end against a real RFC 5321 SMTP server (nodemailer 9.0.6 →
aiosmtpd).Details
Root cause is in
lib/addressparser/index.js.Tokenizer.operators):)is immediately followed by a non‑break character (anything other than space / tab / CR / LF /,/;), the tokenizer marks that operator token withnoBreak = true:_handleAddressthen glues the token that follows the comment onto the token that preceded it (dropping the comment):For the input
user@good-corp.com(x)evil.comthe tokens aretext:"user@good-corp.com",op:"(",text:"x",op:")"(flaggednoBreak),text:"evil.com". Step 3 appendsevil.comontouser@good-corp.com, producing the single domaingood-corp.comevil.com. The comment content (x) is discarded into the display‑name field.RFC 5322 defines a comment as CFWS — semantically folding whitespace — and it may not appear inside a
dot-atom. A comment therefore separates tokens and terminates the domain; the conformant reading ofgood-corp.com(x)evil.comis the domaingood-corp.com(with the trailingevil.combeing invalid/ignored). Nodemailer instead concatenates the two atoms across the removed comment, yielding a different, attacker‑registrable domain.Nodemailer uses the parsed address for both the SMTP envelope (
getEnvelope()→RCPT TO) and the emittedTo:/From:headers, so the entire message is routed to the concatenated domain.Related grammar defect (bonus, lower impact): nested comments are legal in RFC 5322, but the tokenizer closes the comment at the first
)(chr === this.operatorExpecting, line ~392), so a valid nested comment such asuser@x.com(a(b)c)is mis‑balanced and mangled tox.comc). That particular output contains a stray)and is rejected by a conformant MTA (501) — a bounce/robustness issue, not a misroute.Suggested fix: treat a comment as folding whitespace that terminates the current token — i.e. do not propagate
noBreakacross a comment‑closing)(restrict thenoBreakoptimization to quoted‑string closes), and support nested comments per RFC 5322. Equivalently, never emit a domain formed by concatenating two atoms that were separated only by a comment.PoC
Environment: Node.js ≥ 18 and the published
nodemailer@9.0.6. No special transport configuration is required; the discrepancy is in address parsing.poc-comment.js:Run:
Actual output (nodemailer 9.0.6):
The application asked to mail
user@good-corp.com(x)evil.com; Nodemailer delivers togood-corp.comevil.com— registrable domaincomevil.com, which an attacker can register.Verified against a real RFC 5321 server (containerized lab included with this report —
docker compose up --build, caseR8_comment_glue, receiver =aiosmtpd):Which parser sees what (the crux of exploitability):
user@good-corp.com(x)evil.comemail.policy.default(strict RFC 5322)good-corp.com(flagsInvalidHeaderDefect)startsWith/includes('@good-corp.com'))good-corp.comaddressparsergood-corp.comevil.comemail.utils.getaddressesgood-corp.comevil.comurl.domainToASCIIgood-corp.com(x)evil.comImpact
@good-corp.com", employee‑only flows, "same‑tenant" routing). Applications that validate with Nodemailer's ownaddressparser,email.utils.getaddresses, orurl.domainToASCIIare not affected, which is why this is rated below the IDN/Punycode issue.Patched in 9.1.0
Fixed in 902b63e.
Not propagating
noBreakacross the closing)on its own breaks valid addresses, because CFWS is legal on either side of the@:user@(x)good-corp.comanduser(x)@good-corp.comboth come out mangled. A comment now joins what it separates only when one side carries the@, so those keep resolving whileuser@good-corp.com(x)evil.comterminates atgood-corp.com.Quoted-string and angle-address joining are unchanged. Nested comments are still not modelled, but the misroute is gone:
user@x.com(a(b)c)now yieldsuser@x.com.Severity
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:L/A:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
Nodemailer: IDN/Punycode domain allow-list bypass leads to email delivery to an attacker-controlled domain
GHSA-wmmp-3585-3rmp
More information
Details
Summary
Nodemailer resolves an international (IDN / non-ASCII) recipient domain to a different Punycode
xn--label than every UTS‑46‑conformant parser (web browsers, the WHATWG URL Standard, Node'surl.domainToASCII, Python'sidna). Its address normalizer (_normalizeAddressinlib/mime-node/index.js) uses the bundled raw RFC‑3492 Punycode codec with no UTS‑46 mapping/normalization, so a domain that a standards‑compliant validator maps to a trusted domain is delivered by Nodemailer to a different, attacker‑registrable domain.An application that applies a domain allow‑list / same‑domain check to a recipient using a normal IDN‑aware parser (or that shows the normalized recipient to a user for confirmation) and then relies on Nodemailer to deliver to that domain can be induced to send email to an unintended external domain. This is the same weakness class as CVE‑2025‑13033 (Interpretation Conflict, CWE‑436) but reached through IDN/Punycode rather than quoted local‑parts, and it is not addressed by the 7.0.7 fix.
Because the mismatch can be triggered with an invisible character (U+00AD SOFT HYPHEN) that UTS‑46 folds away to the exact trusted domain string, no visible look‑alike/homograph is required.
Details
lib/mime-node/index.js→_normalizeAddress(address)(around lines 1307–1346) splits the address at the last@and normalizes the domain like this:punycodehere is the project’s bundled codec (lib/punycode/), which is a pure RFC 3492 (Punycode) implementation. The only normalization applied to the domain is.toLowerCase(). It performs none of the UTS‑46 “IDNA2008 + compatibility processing” steps that browsers and DNS‑facing resolvers apply before Punycode encoding, specifically:U+00ADSOFT HYPHEN,As a result, for any domain containing a UTS‑46‑mapped or ‑ignored character, Nodemailer’s
punycode.toASCII(...)produces a different A‑label thanurl.domainToASCII(...)(Node ≥ 7 / WHATWG),new URL('http://'+domain), browsers, and Python’sidna(uts46=True). Nodemailer then uses its A‑label as:RCPT TO:<local@xn--…>(getEnvelope()→lib/smtp-connection/index.js_setEnvelope), andTo:/From:headers (_convertAddresses).So the domain a standards‑compliant validator computes and the domain Nodemailer actually delivers to disagree, on a syntactically valid, validator‑accepted address. Concrete divergences (verified on 9.0.6):
url.domainToASCII)victim@compa{U+00AD}ny.com(invisible soft hyphen)company.comxn--company-pka.comvictim@company.com(full‑width)company.comxn--mi7cd4afch9d.comuser@exámple.com(NFDa+U+0301)xn--exmple-qta.comxn--example-vge.comThis is the “Punycode / IDN parser discrepancy” technique documented in PortSwigger’s Splitting the email atom research (which produced e.g. Joomla CVE‑2024‑21725 and fixes in the PHP
idna_convertlibrary). The fix for CVE‑2025‑13033 (nodemailer 7.0.7) hardened the quoted‑local‑part path only; this IDN path is independent and still present in 9.0.6 (latest) and, given the long‑standing use of the bundled RFC‑3492 codec, earlier releases.Suggested remediation: perform UTS‑46 processing before/at domain encoding so Nodemailer’s resolution matches browsers, validators, and DNS — e.g. use the runtime’s
url.domainToASCII()(available since Node 7) instead of the rawpunycode.toASCII, and decode with the matching UTS‑46domainToUnicode. At minimum, reject a domain whose value changes under UTS‑46 mapping (i.e.punycode.toASCII(d)≠url.domainToASCII(d)).PoC
Environment: Node.js ≥ 18, the published
nodemailer@9.0.6. No special configuration; the discrepancy is in domain normalization itself.poc-idn.js:Run:
Actual output (Nodemailer 9.0.6):
The application’s domain check approves
company.com, but the message is sent toxn--company-pka.com— a different domain an attacker can register — carrying theTo:header<victim@xn--company-pka.com>as well.A containerized version that proves the same result against a real RFC 5321 SMTP server (
aiosmtpd) is included alongside this report (docker compose up --build, casesR6/IDN); the receiving server acceptsRCPT TO:<victim@xn--company-pka.com>and reports the recipient domain asxn--company-pka.com.Impact
Any application that uses Nodemailer to send mail to a recipient whose domain is subjected to a security or trust decision made with a different (UTS‑46‑conformant) parser, and then trusts Nodemailer to deliver to that domain. This includes:
new URL(),url.domainToASCII, a browser‑side check, or an IDN library;company.comdiffers from the deliveredxn--company-pka.com);Patched in 9.1.0
Domain encoding now applies UTS-46 (259c32d), so
victim@company.comresolves tocompany.com, matchingurl.domainToASCIIand browsers.One caveat on the suggested remediation, hardened in b212ac4:
url.domainToASCIIis a WHATWG host parser, not a pure UTS-46 mapper. It terminates the host at/,\\,?and#and percent-decodes. Used unguarded it introduces a worse version of the same weakness, sinceuser@attacker.example/mail.corp.exampleencodes to the deliverableuser@attacker.examplewhere the bundled Punycode codec left it intact and unroutable. Those characters are now kept away from the mapper.On severity, "attacker-registrable" is doing significant work in the report:
xn--company-pka.comdecodes to a label containing U+00AD andxn--mi7cd4afch9d.comto full-width Latin, neither of which Verisign's IDN tables permit for a .com registration. The misdelivery and the confirmation-UI mismatch stand regardless, which is why this is rated level with the comment issue rather than above it.Severity
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:L/A:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
Nodemailer: resolveContent() on a MailMessage bypasses disableFileAccess/disableUrlAccess when called with the legacy signature
[GHSA-8m3c-c648-2xjj](https://redirect.github.com/ad
Thanks for the PR!
Deployments, as required, will be available below:
Please create PRs in draft mode. Mark as ready to enable:
After merge, new images are deployed in: