Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions deps/undici/src/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,6 @@ typings/
# next.js build output
.next

# lock files
package-lock.json
yarn.lock
pnpm-lock.yaml

# IDE files
.idea
.vscode
Expand All @@ -81,9 +76,6 @@ fuzz-results-*.json
undici-fetch.js
/test/imports/undici-import.js

# .npmrc has platform specific value for windows
.npmrc

.tap

# File generated by /test/request-timeout.js
Expand Down
1 change: 1 addition & 0 deletions deps/undici/src/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
min-release-age=1
163 changes: 161 additions & 2 deletions deps/undici/src/SECURITY.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,161 @@
If you believe you have found a security issue in the software in this
repository, please consult https://github.com/nodejs/node/blob/HEAD/SECURITY.md.
# Security

## Reporting a vulnerability in undici

Report security bugs in undici via
[GitHub Security Advisories](https://github.com/nodejs/undici/security/advisories/new)
or [HackerOne](https://hackerone.com/nodejs).

Your report will normally be acknowledged within 5 days, and you will receive
a more detailed response within 10 days indicating the next steps in handling
your submission. These timelines may extend when our triage volunteers are
away, particularly at the end of the year.

After the initial reply to your report, the security team will endeavor to keep
you informed of the progress being made towards a fix and full announcement,
and may ask for additional information or guidance surrounding the reported
issue.

## Disclosure policy

* The security report is received and assigned a primary handler. The problem
is validated against all supported versions of undici. Once confirmed, a list
of all affected versions is determined. Code is audited to find any potential
similar problems. Fixes are prepared for all supported releases. These fixes
are not committed to the public repository but rather held locally pending
the announcement.

* Because undici is bundled into Node.js, security releases are often
coordinated with the Node.js project to avoid leaving Node.js users
vulnerable. As a result, fixed versions of undici are published to npm
before the corresponding CVE is disclosed, since the CVE will only be
published after the coordinated Node.js release. This delay is typically
a few days but can take up to a week.

## The undici threat model

Undici is an HTTP client library for Node.js. Its threat model is derived from
and aligned with the [Node.js threat model](https://github.com/nodejs/node/blob/HEAD/SECURITY.md#the-nodejs-threat-model).

### What constitutes a vulnerability

Being able to cause the following through control of the elements that undici
does not trust is considered a vulnerability:

* Disclosure or loss of integrity or confidentiality of data protected through
the correct use of undici APIs.
* The unavailability of the runtime, including the unbounded degradation of its
performance.

#### Denial of Service (DoS) vulnerabilities

For a behavior to be considered a DoS vulnerability, the proof of concept must
meet the following criteria:

* The API is being correctly used.
* The API is public and documented.
* The behavior is significant enough to cause a denial of service quickly
or in a context not controlled by the application developer (for example,
HTTP parsing).
* The behavior is directly exploitable by an untrusted source without requiring
application mistakes.
* The behavior cannot be reasonably mitigated through standard operational
practices (like process recycling).
* The attack demonstrates
[asymmetric resource consumption](https://cwe.mitre.org/data/definitions/405.html),
where the attacker expends significantly fewer resources than what is required
by the client to process the attack.

**Undici does NOT trust**:

* Data received from the remote end of HTTP connections (both inbound responses
and server-sent data) that is parsed or transformed by undici before being
passed to the application. This includes:
* HTTP response headers and status lines.
* HTTP response bodies when processed by undici (e.g., chunked transfer
decoding, content-encoding).
* WebSocket frames received from a server.
* Server-Sent Events (EventSource) data received from a server.
* TLS certificate validation performed by undici on behalf of the application.

**Undici trusts**:

* The application code that uses its APIs, including all configuration,
options, and callbacks provided by the application.
* The operating system and its network stack.
* The Node.js runtime undici is running on.
* Dependencies installed by the application.
* The DNS resolution results provided by the operating system or configured
resolvers.

In other words, if untrusted data passing through undici to the application
can trigger actions other than those documented for the APIs, there is likely
a security vulnerability. Examples of unwanted actions are polluting globals,
causing an unrecoverable crash, or any other unexpected side effects that can
lead to a loss of confidentiality, integrity, or availability.

### Examples of vulnerabilities

#### Improper Certificate Validation (CWE-295)

* Undici provides TLS connections to HTTPS endpoints. If certificates can be
crafted that result in incorrect validation by undici, that is considered
a vulnerability.

#### Inconsistent Interpretation of HTTP Responses (CWE-444)

* Undici parses HTTP responses received from servers. Bugs in parsing response
headers or transfer encoding which can result in response smuggling or
desynchronization are considered vulnerabilities.

#### HTTP Request Smuggling (CWE-444)

* Bugs that allow crafting requests that are interpreted differently by undici
and an upstream server, leading to request smuggling, are considered
vulnerabilities.

#### CRLF Injection in Request Headers (CWE-93)

* If untrusted input passed to undici APIs (such as header values or URLs)
can inject additional headers or corrupt the HTTP request stream, that is
considered a vulnerability.

### Examples of non-vulnerabilities

#### Malicious Third-Party Modules (CWE-1357)

* Application code and its dependencies are trusted by undici. Any scenario
that requires a malicious third-party module cannot result in a vulnerability
in undici.

#### Prototype Pollution Attacks (CWE-1321)

* Undici trusts the inputs provided to it by application code. It is up to the
application to sanitize appropriately. Any scenario that requires control
over user input passed directly by the application is not considered a
vulnerability in undici.

#### Uncontrolled Resource Consumption on Outbound Connections (CWE-400)

* If undici is asked to connect to a remote site and the response payload is
large enough to impact performance or cause the runtime to run out of
resources, that is not considered a vulnerability. Applications are
responsible for setting appropriate limits on response sizes.

#### Application Misconfiguration

* Issues arising from incorrect or insecure use of undici APIs (such as
disabling TLS verification, ignoring errors, or passing unsanitized user
input to request options) are the application's responsibility, not
vulnerabilities in undici.

## Receiving security updates

Security notifications will be distributed via
[GitHub Security Advisories](https://github.com/nodejs/undici/security/advisories).

## Comments on this policy

If you have suggestions on how this process could be improved, please open an
issue on the [nodejs/undici](https://github.com/nodejs/undici/issues)
repository or file a pull request.
22 changes: 11 additions & 11 deletions deps/undici/src/deps/llhttp/include/llhttp.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

#define LLHTTP_VERSION_MAJOR 9
#define LLHTTP_VERSION_MINOR 3
#define LLHTTP_VERSION_PATCH 0
#define LLHTTP_VERSION_PATCH 1

#ifndef INCLUDE_LLHTTP_ITSELF_H_
#define INCLUDE_LLHTTP_ITSELF_H_
Expand Down Expand Up @@ -58,10 +58,8 @@ enum llhttp_errno {
HPE_OK = 0,
HPE_INTERNAL = 1,
HPE_STRICT = 2,
HPE_CR_EXPECTED = 25,
HPE_LF_EXPECTED = 3,
HPE_UNEXPECTED_CONTENT_LENGTH = 4,
HPE_UNEXPECTED_SPACE = 30,
HPE_CLOSED_CONNECTION = 5,
HPE_INVALID_METHOD = 6,
HPE_INVALID_URL = 7,
Expand All @@ -82,15 +80,17 @@ enum llhttp_errno {
HPE_PAUSED_UPGRADE = 22,
HPE_PAUSED_H2_UPGRADE = 23,
HPE_USER = 24,
HPE_CR_EXPECTED = 25,
HPE_CB_URL_COMPLETE = 26,
HPE_CB_STATUS_COMPLETE = 27,
HPE_CB_METHOD_COMPLETE = 32,
HPE_CB_VERSION_COMPLETE = 33,
HPE_CB_HEADER_FIELD_COMPLETE = 28,
HPE_CB_HEADER_VALUE_COMPLETE = 29,
HPE_UNEXPECTED_SPACE = 30,
HPE_CB_RESET = 31,
HPE_CB_METHOD_COMPLETE = 32,
HPE_CB_VERSION_COMPLETE = 33,
HPE_CB_CHUNK_EXTENSION_NAME_COMPLETE = 34,
HPE_CB_CHUNK_EXTENSION_VALUE_COMPLETE = 35,
HPE_CB_RESET = 31,
HPE_CB_PROTOCOL_COMPLETE = 38
};
typedef enum llhttp_errno llhttp_errno_t;
Expand Down Expand Up @@ -294,10 +294,8 @@ typedef enum llhttp_status llhttp_status_t;
XX(0, OK, OK) \
XX(1, INTERNAL, INTERNAL) \
XX(2, STRICT, STRICT) \
XX(25, CR_EXPECTED, CR_EXPECTED) \
XX(3, LF_EXPECTED, LF_EXPECTED) \
XX(4, UNEXPECTED_CONTENT_LENGTH, UNEXPECTED_CONTENT_LENGTH) \
XX(30, UNEXPECTED_SPACE, UNEXPECTED_SPACE) \
XX(5, CLOSED_CONNECTION, CLOSED_CONNECTION) \
XX(6, INVALID_METHOD, INVALID_METHOD) \
XX(7, INVALID_URL, INVALID_URL) \
Expand All @@ -318,15 +316,17 @@ typedef enum llhttp_status llhttp_status_t;
XX(22, PAUSED_UPGRADE, PAUSED_UPGRADE) \
XX(23, PAUSED_H2_UPGRADE, PAUSED_H2_UPGRADE) \
XX(24, USER, USER) \
XX(25, CR_EXPECTED, CR_EXPECTED) \
XX(26, CB_URL_COMPLETE, CB_URL_COMPLETE) \
XX(27, CB_STATUS_COMPLETE, CB_STATUS_COMPLETE) \
XX(32, CB_METHOD_COMPLETE, CB_METHOD_COMPLETE) \
XX(33, CB_VERSION_COMPLETE, CB_VERSION_COMPLETE) \
XX(28, CB_HEADER_FIELD_COMPLETE, CB_HEADER_FIELD_COMPLETE) \
XX(29, CB_HEADER_VALUE_COMPLETE, CB_HEADER_VALUE_COMPLETE) \
XX(30, UNEXPECTED_SPACE, UNEXPECTED_SPACE) \
XX(31, CB_RESET, CB_RESET) \
XX(32, CB_METHOD_COMPLETE, CB_METHOD_COMPLETE) \
XX(33, CB_VERSION_COMPLETE, CB_VERSION_COMPLETE) \
XX(34, CB_CHUNK_EXTENSION_NAME_COMPLETE, CB_CHUNK_EXTENSION_NAME_COMPLETE) \
XX(35, CB_CHUNK_EXTENSION_VALUE_COMPLETE, CB_CHUNK_EXTENSION_VALUE_COMPLETE) \
XX(31, CB_RESET, CB_RESET) \
XX(38, CB_PROTOCOL_COMPLETE, CB_PROTOCOL_COMPLETE) \


Expand Down
22 changes: 13 additions & 9 deletions deps/undici/src/deps/llhttp/src/llhttp.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#endif /* _MSC_VER */
#endif /* __SSE4_2__ */

#ifdef __ARM_NEON__
#if defined(__ARM_NEON__) || defined(__ARM_NEON)
#include <arm_neon.h>
#endif /* __ARM_NEON__ */

Expand Down Expand Up @@ -1542,7 +1542,7 @@ static llparse_state_t llhttp__internal__run(
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
Expand Down Expand Up @@ -2625,7 +2625,7 @@ static llparse_state_t llhttp__internal__run(
goto s_n_llhttp__internal__n_header_value_otherwise;
}
#endif /* __SSE4_2__ */
#ifdef __ARM_NEON__
#if defined(__ARM_NEON__) || defined(__ARM_NEON)
while (endp - p >= 16) {
uint8x16_t input;
uint8x16_t single;
Expand All @@ -2639,19 +2639,23 @@ static llparse_state_t llhttp__internal__run(
/* Find first character that does not match `ranges` */
single = vceqq_u8(input, vdupq_n_u8(0x9));
mask = single;
single = vandq_u16(
single = vandq_u8(
vcgeq_u8(input, vdupq_n_u8(' ')),
vcleq_u8(input, vdupq_n_u8('~'))
);
mask = vorrq_u16(mask, single);
single = vandq_u16(
mask = vorrq_u8(mask, single);
single = vandq_u8(
vcgeq_u8(input, vdupq_n_u8(0x80)),
vcleq_u8(input, vdupq_n_u8(0xff))
);
mask = vorrq_u16(mask, single);
narrow = vshrn_n_u16(mask, 4);
mask = vorrq_u8(mask, single);
narrow = vshrn_n_u16(vreinterpretq_u16_u8(mask), 4);
match_mask = ~vget_lane_u64(vreinterpret_u64_u8(narrow), 0);
match_len = __builtin_ctzll(match_mask) >> 2;
if (match_mask == 0) {
match_len = 16;
} else {
match_len = __builtin_ctzll(match_mask) >> 2;
}
if (match_len != 16) {
p += match_len;
goto s_n_llhttp__internal__n_header_value_otherwise;
Expand Down
4 changes: 2 additions & 2 deletions deps/undici/src/docs/docs/api/Dispatcher.md
Original file line number Diff line number Diff line change
Expand Up @@ -1354,10 +1354,10 @@ Emitted when dispatcher is no longer busy.

## Parameter: `UndiciHeaders`

* `Record<string, string | string[] | undefined> | string[] | Iterable<[string, string | string[] | undefined]> | null`
* `Record<string, number | string | string[] | undefined> | string[] | Iterable<[string, string | string[] | undefined]> | null`

Header arguments such as `options.headers` in [`Client.dispatch`](/docs/docs/api/Client.md#clientdispatchoptions-handlers) can be specified in three forms:
* As an object specified by the `Record<string, string | string[] | undefined>` (`IncomingHttpHeaders`) type.
* As an object specified by the `Record<string, number | string | string[] | undefined>` (`OutgoingHttpHeaders`) type.
* As an array of strings. An array representation of a header list must have an even length, or an `InvalidArgumentError` will be thrown.
* As an iterable that can encompass `Headers`, `Map`, or a custom iterator returning key-value pairs.
Keys are lowercase and values are not modified.
Expand Down
2 changes: 1 addition & 1 deletion deps/undici/src/lib/api/api-connect.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class ConnectHandler extends AsyncResource {
// Indicates is an HTTP2Session
if (responseHeaders != null) {
responseHeaders = this.responseHeaders === 'raw'
? (Array.isArray(rawHeaders) ? util.parseRawHeaders(rawHeaders) : [])
? util.parseRawHeaders(rawHeaders)
: headers
}

Expand Down
4 changes: 2 additions & 2 deletions deps/undici/src/lib/api/api-pipeline.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ class PipelineHandler extends AsyncResource {
if (this.onInfo) {
const rawHeaders = controller?.rawHeaders
const responseHeaders = this.responseHeaders === 'raw'
? (Array.isArray(rawHeaders) ? util.parseRawHeaders(rawHeaders) : [])
? util.parseRawHeaders(rawHeaders)
: headers
this.onInfo({ statusCode, headers: responseHeaders })
}
Expand All @@ -181,7 +181,7 @@ class PipelineHandler extends AsyncResource {
this.handler = null
const rawHeaders = controller?.rawHeaders
const responseHeaders = this.responseHeaders === 'raw'
? (Array.isArray(rawHeaders) ? util.parseRawHeaders(rawHeaders) : [])
? util.parseRawHeaders(rawHeaders)
: headers
body = this.runInAsyncScope(handler, null, {
statusCode,
Expand Down
4 changes: 2 additions & 2 deletions deps/undici/src/lib/api/api-request.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class RequestHandler extends AsyncResource {
throw new InvalidArgumentError('invalid callback')
}

if (highWaterMark && (typeof highWaterMark !== 'number' || highWaterMark < 0)) {
if (highWaterMark != null && (!Number.isFinite(highWaterMark) || highWaterMark < 0)) {
throw new InvalidArgumentError('invalid highWaterMark')
}

Expand Down Expand Up @@ -92,7 +92,7 @@ class RequestHandler extends AsyncResource {

const rawHeaders = controller?.rawHeaders
const responseHeaderData = responseHeaders === 'raw'
? (Array.isArray(rawHeaders) ? util.parseRawHeaders(rawHeaders) : [])
? util.parseRawHeaders(rawHeaders)
: headers

if (statusCode < 200) {
Expand Down
2 changes: 1 addition & 1 deletion deps/undici/src/lib/api/api-stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class StreamHandler extends AsyncResource {

const rawHeaders = controller?.rawHeaders
const responseHeaderData = responseHeaders === 'raw'
? (Array.isArray(rawHeaders) ? util.parseRawHeaders(rawHeaders) : [])
? util.parseRawHeaders(rawHeaders)
: headers

if (statusCode < 200) {
Expand Down
Loading
Loading