Skip to content

dgram: reject null bytes in address before queueing - #67064

Open
philipsorensen wants to merge 1 commit into
nodejs:mainfrom
philipsorensen:dgram-nul-host-before-enqueue
Open

philipsorensen wants to merge 1 commit into
nodejs:mainfrom
philipsorensen:dgram-nul-host-before-enqueue

Conversation

@philipsorensen

Copy link
Copy Markdown

Since 7dafafa24247 (CVE-2026-48930), dns.lookup() throws synchronously for a hostname that contains a null byte.

On a dgram socket that isn't bound yet, send() and connect() only check the address with validateString(). They then bind implicitly and queue the operation. The queued lookup runs inside the socket's 'listening' emit, so the throw happens there. It bypasses the caller's try/catch, the callback and the 'error' listener, and the process exits. Anything else queued on the socket is lost. On a bound socket the same call throws synchronously and can be caught.

const dgram = require('node:dgram');
const s = dgram.createSocket('udp4');
s.on('error', (e) => console.log('error event', e.code)); // not called
try {
  s.send('x', 9999, '127.0.0.1\0x', (e) => console.log('cb', e)); // not called
} catch (e) {
  console.log('caught', e.code); // not called
}
// Uncaught TypeError [ERR_INVALID_ARG_VALUE], exit code 1

This reproduces on v22.23.x, v24.21.0+, v26.12.1 and main. Before the CVE fix, the packet went to the truncated host instead.

This PR uses validateStringWithoutNullBytes() for the address in send() and connect(), before anything is bound or queued (connect, send). The error is now the same synchronous ERR_INVALID_ARG_VALUE whether or not the socket is bound, which matches what dns and net throw for this input.

The new test covers send() and connect() on an unbound socket, and checks that the socket still works afterwards. It fails without the change.

Not included, and I'm happy to follow up separately if wanted:

  • bind(port, 'a\0b') throws, but leaves the socket in the binding state.
  • http.Agent has a similar deferred throw when a queued request (because maxTotalSockets is reached) has a host with a null byte.

On a socket that is not bound yet, `send()` and `connect()` queue the
operation until the implicit bind completes. Since `dns.lookup()`
started rejecting hostnames with null bytes, the queued lookup throws
from inside the 'listening' event. The error then bypasses the
caller's try/catch, the callback and the 'error' listener, and the
process exits.

Validate the address for null bytes before anything is queued, so the
error is thrown synchronously whether or not the socket is bound.

Refs: nodejs@7dafafa24247
Signed-off-by: Philip Sørensen <git@ppsa.dk>
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/net

@nodejs-github-bot nodejs-github-bot added dgram Issues and PRs related to UDP and the dgram module. needs-ci PRs that need a full CI run. labels Oct 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Welcome to Node.js, and thank you for your first contribution!

Before review, please take a moment to read:

Please make sure every commit is signed off. For a first pull request, GitHub Actions require collaborator approval and Jenkins CI must be started by a collaborator or triager, so an initial wait is normal.

@codecov

codecov Bot commented Oct 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.65%. Comparing base (98dbf60) to head (ef3ef4e).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main   #67064   +/-   ##
=======================================
  Coverage   90.65%   90.65%           
=======================================
  Files         797      797           
  Lines      278268   278321   +53     
  Branches    53517    53524    +7     
=======================================
+ Hits       252261   252311   +50     
+ Misses      16386    16377    -9     
- Partials     9621     9633   +12     
Files with missing lines Coverage Δ
lib/dgram.js 97.19% <100.00%> (+<0.01%) ⬆️

... and 23 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dgram Issues and PRs related to UDP and the dgram module. needs-ci PRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants