Your admin panel can only be opened from internal company IP addresses. Login attempts are limited per source. Operation logs record where each action came from with req.ip. If you run Express behind a load balancer or reverse proxy and rely on req.ip for this kind of processing, check the one line where trust proxy is written.
GHSA-jqcg-44mw-7w3h (CVE-2026-90711, severity Critical), added to the GitHub Advisory Database on October 5, 2026 (UTC), is an issue in proxy-addr, the component Express uses to determine req.ip. If trust proxy uses an IPv6 notation with an embedded IPv4 address and a short prefix length, such as ::ffff:10.0.0.0/8, every IPv4 address is treated as a trusted proxy, and req.ip contains any value the user writes in the X-Forwarded-For header. Based on the advisory, the Express changelog, and the editorial team's results from running and comparing 2.0.7 and 2.0.8, we cover what to check and how to update.
Which notations are a problem
The advisory describes the conditions as follows.
When an application configures a trust subnet as an IPv4-mapped IPv6 address with a short prefix, such as
::ffff:10.0.0.0/8(the correct spelling is::ffff:10.0.0.0/104), the subnet compiles with all-zero leading bits and matches every IPv4 address instead of the block it names.
::ffff:10.0.0.0 is a notation that embeds an IPv4 address inside a 128-bit IPv6 address, and the first 96 bits correspond to ::ffff:. The range equivalent to IPv4 10.0.0.0/8 must be written as /104 (96 + 8); writing /8 means "the first 8 bits are 0." Up to proxy-addr 2.0.7, this matched every IPv4 address. The same is said to happen with IPv6 ranges whose leading bit is 0, such as ::/1.
Affected versions are proxy-addr 1.1.0 and later but earlier than 2.0.8. Because Express's req.ip and req.ips return the result of this component, the advisory states: "This defeats IP-based access control, rate limiting, geolocation, and audit logging." Moreover, "The misconfiguration compiles without any error," and nothing is shown at startup.
The editorial team compared 2.0.7 and 2.0.8
On October 10, 2026, we set up two environments with Node.js 22.22.0 on Linux.
- Express 5.2.1 + proxy-addr 2.0.7 (pinned to 2.0.7 with
overridesto reproduce the state of an old lockfile) - Express 5.3.0 + proxy-addr 2.0.8 (fresh install)
After app.set('trust proxy', <設定>), the app simply returns the connecting address, req.ip, and req.ips. We had the server listen on 127.0.0.1 and sent requests from the same 127.0.0.1 with X-Forwarded-For: 198.51.100.7 attached. The connecting 127.0.0.1 does not fall within any of the configured ranges representing 10.0.0.0/8, so if everything works correctly, req.ip should be 127.0.0.1.
express 5.2.1 / proxy-addr 2.0.7 / listen 127.0.0.1 / trust '::ffff:10.0.0.0/8'
XFF 198.51.100.7 -> {"remote":"127.0.0.1","ip":"198.51.100.7","ips":["198.51.100.7"]}
express 5.3.0 / proxy-addr 2.0.8 / listen 127.0.0.1 / trust '::ffff:10.0.0.0/8'
XFF 198.51.100.7 -> {"remote":"127.0.0.1","ip":"127.0.0.1","ips":[]}
With 2.0.7, even though the connection came from outside the range, req.ip became the value written by the sender. When the sender claimed X-Forwarded-For: 10.20.30.40 and an internal address, req.ip was also 10.20.30.40, so an app designed to allow only internal addresses would let outside requests through. With 2.0.8, both stayed 127.0.0.1.

The IPv4 notation 10.0.0.0/8, the correct prefix length ::ffff:10.0.0.0/104, and the name-based uniquelocal all stayed 127.0.0.1 even with 2.0.7. As a control, with ::ffff:127.0.0.0/104, which correctly trusts the connecting address, both versions returned the X-Forwarded-For value. In 2.0.8, correctly written notations continue to work as before.
Test conditions and limitations
This environment could not listen on IPv6 (EAFNOSUPPORT), so for the case where the server listens on :: and the connecting address appears as ::ffff:127.0.0.1, we checked by calling proxy-addr directly. The results were the same: only with ::ffff:10.0.0.0/8 did 2.0.7 return 198.51.100.7. We have not tested an actual setup behind a load balancer.
Check whether your app is affected
Your app is affected if the proxy-addr in your runtime environment is 2.0.7 or earlier and trust proxy contains a range that starts with ::ffff: and has a prefix length of less than 96 (or a range such as ::/1).
The proxy-addr version is determined by the lockfile. In the editorial team's environment, a fresh install pulled in 2.0.8 with both Express 5.2.1 and 4.22.3. You cannot judge from the Express version alone, so check the version that is actually installed. In the environment pinned to 2.0.7, npm audit showed "proxy-addr 1.1.0 - 2.0.7 / Severity: critical."
npm ls proxy-addr
npm audit
grep -rnE "trust proxy|proxy-addr|proxyaddr" --include=*.js --include=*.ts --include=*.mjs --include=*.cjs .
grep -rn "::ffff:" .env* config/ deploy/ 2>/dev/null
The setting may be written directly in code, or read from environment variables or configuration files. If ::ffff: is followed by an IPv4 address and a short prefix length, as in ::ffff:172.16.0.0/12, consider it likely that you are affected. Note that Fastify uses a different component (@fastify/proxy-addr) and is not covered by this advisory. We have not checked its behavior with the same notation.
There are two fixes; do both
Rewrite the setting in IPv4 notation
The advisory's workaround is: "Write IPv4 trust subnets in plain IPv4 notation (for example 10.0.0.0/8)." If you keep using IPv6 notation, add 96 to the prefix length, as in ::ffff:10.0.0.0/104.
// 直す前(2.0.7 以下では、すべての IPv4 の接続元を信頼してしまう)
app.set('trust proxy', '::ffff:10.0.0.0/8');
// 直した後
app.set('trust proxy', '10.0.0.0/8');
If you only update the component, you get the opposite symptom. When we called proxy-addr directly and tested with 10.1.1.1, treating the connecting address as a legitimate proxy, 2.0.8 returned 10.1.1.1 while the setting was still ::ffff:10.0.0.0/8, and the user's address could not be obtained. After changing it to 10.0.0.0/8, it returned the X-Forwarded-For value.
Upgrade proxy-addr to 2.0.8
For the Express 5 line, 5.3.0, released on October 9, raises the requirement to ^2.0.8 (changelog: "Upgrade proxy-addr to ^2.0.8, which fixes CVE-2026-90711"). The latest Express 4 release, 4.22.3 (September 14), still requires ~2.0.7, but that range includes 2.0.8. In the editorial team's environment, running npm install with a lockfile that recorded 2.0.7 left it at 2.0.7, and npm update proxy-addr upgraded it to 2.0.8. npm ci installs exactly what the lockfile says, so unless you commit the updated lockfile, production stays on the old version.
npm update proxy-addr compression body-parser
npm ls proxy-addr compression body-parser
At the same time, if you use compression, upgrade to 1.8.2 or later. GHSA-vc2v-76pw-4v95 (CVE-2026-87776, severity High), registered on the same day, October 5, is an issue where cutting the connection while a compressed response is being sent leaves zlib memory unreleased, and repeating this can exhaust memory; the workaround is "None." compression is not a dependency of Express itself, so check it separately. In body-parser, an issue where passing an invalid value to limit silently disables the size limit (CVE-2026-12590) is fixed in 2.3.0, and in the 1.x line it is fixed in 1.20.6.
Responses that change in 5.3.0, and checks after updating
5.3.0 also includes changes that alter the content of responses.
- Quotes disappear from
Content-Disposition. Inres.attachment(),res.download(), andres.sendFile(), file names that are valid HTTP tokens are no longer enclosed in quotes. In the editorial team's environment as well,res.attachment('report.csv')changed fromfilename="report.csv"in 5.2.1 tofilename=report.csvin 5.3.0. The changelog says the meaning is the same under RFC 6266, but notes that tests comparing the header string verbatim need their expected values updated - An invalid
limitin body-parser now stops the app at startup. In 2.3.0,express.json({ limit: 'abc' })threwTypeError: option limit "abc" is invalid(no error in 2.2.1). If you read the value from an environment variable, check the production value first res.send()now adds charset while keeping the existing parameters ofContent-Type
After shipping the update to production, the editorial team recommends checking the following three points.
- For connections through the proxy, whether
req.ipis the user's address (whether your logs are filled only with the load balancer's address) - If there is a path that reaches the app directly, whether
req.ipbecomes the actual connecting address when you send a fakeX-Forwarded-Forthrough it - How far back to review the permissions, restrictions, and operation logs based on
req.ipfor the period when you ran with the problematic setting
We also cover how allow rules that trust header values become loopholes in Is the ClaudeBot in your logs real? How allow rules that trust the User-Agent become loopholes. The process of checking npm component versions is covered in The sharp AVIF vulnerability: check that Astro and Next.js use 0.35.4 or later, and preparing for attacks that cross dependencies is covered in A roundup of 2026 supply chain attacks.
Scope of verification
On October 10, 2026, we directly retrieved and checked the JSON for GHSA-jqcg-44mw-7w3h and GHSA-vc2v-76pw-4v95 in github/advisory-database, History.md and the package.json of each tag in expressjs/express (commit cf6722b for v5.3.0, commit 899b524 for v4.22.3), fix commit 780911d in jshttp/proxy-addr, HISTORY.md in expressjs/body-parser, and the publication dates and dependencies on registry.npmjs.org (document research). We also ran Express 5.2.1 (pinned to proxy-addr 2.0.7) and 5.3.0 with Node.js 22.22.0 on Linux, and checked the behavior of
req.ip,Content-Disposition, and body-parser'slimit, as well as the results ofnpm ls,npm audit, andnpm update(hands-on testing). We have not checked listening on IPv6, setups behind a load balancer, reproduction of the compression and body-parser issues themselves, or behavior in Fastify.
For updating dependencies of business systems running behind a load balancer, or reviewing IP address-based restrictions, please contact us through our consultation on development, AI, and automation.
References
- GitHub Advisory Database — GHSA-jqcg-44mw-7w3h(proxy-addr vulnerable to IP spoofing via IPv4-mapped IPv6 trust subnet)
- GitHub Advisory Database — GHSA-vc2v-76pw-4v95(compression vulnerable to Denial of Service via memory leak on premature response close)
- expressjs/express — History.md(5.3.0)
- expressjs/express — commit cf6722b(5.3.0)
- jshttp/proxy-addr — commit 780911d(fix: reject IPv4 trust via mapped IPv6 subnets with a short prefix)
- expressjs/body-parser — HISTORY.md (fix in 1.20.6)
- npm registry — express (publication dates and dependencies)
- GitHub Advisory Database — GHSA-v422-hmwv-36x6 (issue where an invalid value for body-parser's limit disables the limit)









