<?xml version='1.0' encoding='UTF-8'?>
<?xml-stylesheet href="/static/style.xsl" type="text/xsl"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">
  <channel>
    <title>Most recent entries from all</title>
    <link>https://db.gcve.eu</link>
    <description>Contains only the most 10 recent entries.</description>
    <docs>http://www.rssboard.org/rss-specification</docs>
    <generator>python-feedgen</generator>
    <language>en</language>
    <lastBuildDate>Thu, 01 Oct 2026 14:53:36 +0000</lastBuildDate>
    <item>
      <title>GHSA-46wh-pxpv-q5gq — express-rate-limit: IPv4-mapped IPv6 addresses bypass per-client rate limiting on servers with dual-stack network</title>
      <link>https://db.gcve.eu/vuln/ghsa-46wh-pxpv-q5gq</link>
      <description>&lt;p&gt;&lt;strong&gt;Affected:&lt;/strong&gt; npm: express-rate-limit&lt;/p&gt;
&lt;p&gt;## Summary&lt;/p&gt;
&lt;p&gt;The default `keyGenerator` in express-rate-limit applies IPv6 subnet masking (`/56` by default) to all addresses that `net.isIPv6()` returns true for. This includes IPv4-mapped IPv6 addresses (`::ffff:x.x.x.x`), which Node.js returns as `request.ip` on dual-stack servers.&lt;/p&gt;
&lt;p&gt;Because the first 80 bits of all IPv4-mapped addresses are zero, a `/56` (or any `/32` to `/80`) subnet mask produces the same network key (`::/56`) for **every** IPv4 client. This collapses all IPv4 traffic into a single rate-limit bucket: one client exhausting the limit causes HTTP 429 for all other IPv4 clients.&lt;/p&gt;
&lt;p&gt;## Details&lt;/p&gt;
&lt;p&gt;### Root Cause&lt;/p&gt;
&lt;p&gt;In `source/ip-key-generator.ts`:&lt;/p&gt;
&lt;p&gt;```typescript
export function ipKeyGenerator(ip: string, ipv6Subnet: number | false = 56) {
  if (ipv6Subnet &amp;amp;&amp;amp; isIPv6(ip)) {
    return `${new Address6(`${ip}/${ipv6Subnet}`).startAddress().correctForm()}/${ipv6Subnet}`
  }
  return ip
}
```&lt;/p&gt;
&lt;p&gt;`net.isIPv6(&amp;#39;::ffff:192.168.1.1&amp;#39;)` returns `true`, so IPv4-mapped addresses enter the subnet masking path. With a `/56` prefix, the start address for any `::ffff:x.x.x.x` is `::`, producing the key `::/56`.&lt;/p&gt;
&lt;p&gt;### Proof of Concept&lt;/p&gt;
&lt;p&gt;```javascript
const { isIPv6 } = require(&amp;#39;net&amp;#39;);
const { Address6 } = require(&amp;#39;ip-address&amp;#39;);&lt;/p&gt;
&lt;p&gt;function ipKeyGenerator(ip, ipv6Subnet = 56) {
  if (ipv6Subnet &amp;amp;&amp;amp; isIPv6(ip)) {
    return `${new Address6(`${ip}/${ipv6Subnet}`).startAddress().correctForm()}/${ipv6Subnet}`;
  }
  return ip;
}&lt;/p&gt;
&lt;p&gt;console.log(ipKeyGenerator(&amp;#39;::ffff:192.168.1.1&amp;#39;, 56)); // ::/56
cons…&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;&lt;strong&gt;Affected:&lt;/strong&gt; npm: express-rate-limit&lt;/p&gt;
&lt;p&gt;## Summary&lt;/p&gt;
&lt;p&gt;The default `keyGenerator` in express-rate-limit applies IPv6 subnet masking (`/56` by default) to all addresses that `net.isIPv6()` returns true for. This includes IPv4-mapped IPv6 addresses (`::ffff:x.x.x.x`), which Node.js returns as `request.ip` on dual-stack servers.&lt;/p&gt;
&lt;p&gt;Because the first 80 bits of all IPv4-mapped addresses are zero, a `/56` (or any `/32` to `/80`) subnet mask produces the same network key (`::/56`) for **every** IPv4 client. This collapses all IPv4 traffic into a single rate-limit bucket: one client exhausting the limit causes HTTP 429 for all other IPv4 clients.&lt;/p&gt;
&lt;p&gt;## Details&lt;/p&gt;
&lt;p&gt;### Root Cause&lt;/p&gt;
&lt;p&gt;In `source/ip-key-generator.ts`:&lt;/p&gt;
&lt;p&gt;```typescript
export function ipKeyGenerator(ip: string, ipv6Subnet: number | false = 56) {
  if (ipv6Subnet &amp;amp;&amp;amp; isIPv6(ip)) {
    return `${new Address6(`${ip}/${ipv6Subnet}`).startAddress().correctForm()}/${ipv6Subnet}`
  }
  return ip
}
```&lt;/p&gt;
&lt;p&gt;`net.isIPv6(&amp;#39;::ffff:192.168.1.1&amp;#39;)` returns `true`, so IPv4-mapped addresses enter the subnet masking path. With a `/56` prefix, the start address for any `::ffff:x.x.x.x` is `::`, producing the key `::/56`.&lt;/p&gt;
&lt;p&gt;### Proof of Concept&lt;/p&gt;
&lt;p&gt;```javascript
const { isIPv6 } = require(&amp;#39;net&amp;#39;);
const { Address6 } = require(&amp;#39;ip-address&amp;#39;);&lt;/p&gt;
&lt;p&gt;function ipKeyGenerator(ip, ipv6Subnet = 56) {
  if (ipv6Subnet &amp;amp;&amp;amp; isIPv6(ip)) {
    return `${new Address6(`${ip}/${ipv6Subnet}`).startAddress().correctForm()}/${ipv6Subnet}`;
  }
  return ip;
}&lt;/p&gt;
&lt;p&gt;console.log(ipKeyGenerator(&amp;#39;::ffff:192.168.1.1&amp;#39;, 56)); // ::/56
cons…&lt;/p&gt;</content:encoded>
      <guid isPermaLink="false">https://db.gcve.eu/vuln/ghsa-46wh-pxpv-q5gq</guid>
    </item>
  </channel>
</rss>
