Common Weakness Enumeration

CWE-407

Allowed-with-Review

Inefficient Algorithmic Complexity

Abstraction: Class · Status: Incomplete

An algorithm in a product has an inefficient worst-case computational complexity that may be detrimental to system performance and can be triggered by an attacker, typically using crafted manipulations that ensure that the worst case is being reached.

212 vulnerabilities reference this CWE, most recent first.

GHSA-RQFJ-9WMV-VPGP

Vulnerability from github – Published: 2025-04-20 00:31 – Updated: 2025-04-20 00:31
VLAI
Details

mystrtod in mjson 1.2.7 requires more than a billion iterations during processing of certain digit strings such as 8891110122900e913013935755114.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2023-30421"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-407"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-04-19T22:15:14Z",
    "severity": "LOW"
  },
  "details": "mystrtod in mjson 1.2.7 requires more than a billion iterations during processing of certain digit strings such as 8891110122900e913013935755114.",
  "id": "GHSA-rqfj-9wmv-vpgp",
  "modified": "2025-04-20T00:31:40Z",
  "published": "2025-04-20T00:31:40Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-30421"
    },
    {
      "type": "WEB",
      "url": "https://github.com/boofish/json_bugs/blob/main/mjson"
    },
    {
      "type": "WEB",
      "url": "https://github.com/cesanta/mjson/releases"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-V245-V573-V5VM

Vulnerability from github – Published: 2026-07-21 19:06 – Updated: 2026-07-21 19:06
VLAI
Summary
linkify-it: Quadratic-complexity DoS via the `mailto:` validator scan-loop on attacker text
Details

Summary

linkify-it's schema-scan loop (.test() / .match(), the documented public API) invokes the mailto: schema validator at every mailto: occurrence in the input text. For each occurrence the validator does text.slice(pos) (an O(n) copy) and runs an email regex whose local-part class src_email_name greedily scans the entire remaining tail (O(n)) before failing. With N mailto: occurrences that is N × O(n) = O(n²). Because linkify-it runs on arbitrary user text (markdown-it feeds it whole documents when linkify:true), an unauthenticated attacker can block the single-threaded event loop for many seconds with a small input. No length bound (unlike an HTTP header).

Root cause — index.mjs + lib/re.mjs

// index.mjs (mailto validator) — runs at every "mailto:" hit
'mailto:': { validate: function (text, pos, self) {
  const tail = text.slice(pos)                                  // O(n) copy per hit
  if (!self.re.mailto) self.re.mailto = new RegExp('^' + self.re.src_email_name + '@' + self.re.src_host_strict, 'i')
  if (self.re.mailto.test(tail)) { ... }                        // scans the whole O(n) tail
  return 0
}}
// lib/re.mjs:91-93 — every char of "mailto:" (incl. ':','-',';') is in this class:
re.src_email_name = '[\\-;:&=\\+\\$,\\.a-zA-Z0-9_][\\-;:&=\\+\\$,\\"\\.a-zA-Z0-9_]*'

The while ((m = re.exec(text)) !== null) { …testSchemaAt… } scan loop calls the validator at each mailto: hit; src_email_name greedily consumes the whole tail (all chars are in its class) then fails for lack of @. http:/https: do NOT blow up — their validator requires the tail to start with //, failing in O(1) per hit.

Proof of Concept (confirmed, linkify-it 5.0.1, Node v24)

const LinkifyIt = require('linkify-it');
const lf = new LinkifyIt();
lf.match('mailto:'.repeat(48000));   // ~336 KB of "mailto:mailto:…" -> seconds of blocked event loop
input (same bytes) 56 KB 112 KB 224 KB 336 KB
mailto: contiguous 97 ms 357 ms 1438 ms 3272 ms
mailto: space-separated 2 ms 3 ms 5 ms 8 ms
http:// contiguous 12 ms 17 ms 33 ms 49 ms

×~4 per 2× input ⇒ O(n²); equal-byte controls stay flat ⇒ algorithmic, not a GC/allocation artifact. Real-world via markdown-it 14.x ({linkify:true}), md.render('mailto:'.repeat(n)): 219 KB ≈ ~5 s. image

Impact

Reachable on arbitrary user text via the documented .test()/.match() API and through markdown-it's linkifier — comment systems, chat, forums, wikis, note apps that render user markdown with linkify enabled. A ~220 KB post hangs the event loop ~5 s; a few hundred KB → tens of seconds. Availability only.

Suggested remediation

Bound the email local-part per RFC 5321 (≤64) so per-hit work is O(1), and avoid the full-tail slice:

// lib/re.mjs — cap the greedy run:
re.src_email_name = '[\\-;:&=\\+\\$,\\.a-zA-Z0-9_][\\-;:&=\\+\\$,\\"\\.a-zA-Z0-9_]{0,63}'
// index.mjs — prefer a sticky regex anchored at `pos` over text.slice(pos).

Affected / disclosure

All versions through 5.0.1 (latest); same code on master. cve-mcp/OSV report no known vulnerability for linkify-it. Distinct from markdown-it's own *-run ReDoS (CVE-2026-2327, different package/path) and the recent markdown-it DoS. Reported privately; happy to test a patch against the PoC.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 5.0.1"
      },
      "package": {
        "ecosystem": "npm",
        "name": "linkify-it"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "5.0.2"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-59887"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-407"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-07-21T19:06:09Z",
    "nvd_published_at": "2026-07-08T17:17:26Z",
    "severity": "HIGH"
  },
  "details": "### Summary\n`linkify-it`\u0027s schema-scan loop (`.test()` / `.match()`, the documented public API) invokes the `mailto:`\nschema validator at **every** `mailto:` occurrence in the input text. For each occurrence the validator does\n`text.slice(pos)` (an O(n) copy) and runs an email regex whose local-part class `src_email_name` greedily\nscans the **entire remaining tail** (O(n)) before failing. With N `mailto:` occurrences that is\n**N \u00d7 O(n) = O(n\u00b2)**. Because linkify-it runs on arbitrary user text (markdown-it feeds it whole documents\nwhen `linkify:true`), an unauthenticated attacker can block the single-threaded event loop for many seconds\nwith a small input. No length bound (unlike an HTTP header).\n\n### Root cause \u2014 `index.mjs` + `lib/re.mjs`\n```js\n// index.mjs (mailto validator) \u2014 runs at every \"mailto:\" hit\n\u0027mailto:\u0027: { validate: function (text, pos, self) {\n  const tail = text.slice(pos)                                  // O(n) copy per hit\n  if (!self.re.mailto) self.re.mailto = new RegExp(\u0027^\u0027 + self.re.src_email_name + \u0027@\u0027 + self.re.src_host_strict, \u0027i\u0027)\n  if (self.re.mailto.test(tail)) { ... }                        // scans the whole O(n) tail\n  return 0\n}}\n// lib/re.mjs:91-93 \u2014 every char of \"mailto:\" (incl. \u0027:\u0027,\u0027-\u0027,\u0027;\u0027) is in this class:\nre.src_email_name = \u0027[\\\\-;:\u0026=\\\\+\\\\$,\\\\.a-zA-Z0-9_][\\\\-;:\u0026=\\\\+\\\\$,\\\\\"\\\\.a-zA-Z0-9_]*\u0027\n```\nThe `while ((m = re.exec(text)) !== null) { \u2026testSchemaAt\u2026 }` scan loop calls the validator at each\n`mailto:` hit; `src_email_name` greedily consumes the whole tail (all chars are in its class) then fails for\nlack of `@`. `http:`/`https:` do NOT blow up \u2014 their validator requires the tail to start with `//`, failing\nin O(1) per hit.\n\n### Proof of Concept (confirmed, linkify-it 5.0.1, Node v24)\n```js\nconst LinkifyIt = require(\u0027linkify-it\u0027);\nconst lf = new LinkifyIt();\nlf.match(\u0027mailto:\u0027.repeat(48000));   // ~336 KB of \"mailto:mailto:\u2026\" -\u003e seconds of blocked event loop\n```\n| input (same bytes) | 56 KB | 112 KB | 224 KB | 336 KB |\n|---|---:|---:|---:|---:|\n| **`mailto:` contiguous** | 97 ms | 357 ms | 1438 ms | 3272 ms |\n| `mailto:` space-separated | 2 ms | 3 ms | 5 ms | 8 ms |\n| `http://` contiguous | 12 ms | 17 ms | 33 ms | 49 ms |\n\n\u00d7~4 per 2\u00d7 input \u21d2 O(n\u00b2); equal-byte controls stay flat \u21d2 algorithmic, not a GC/allocation artifact.\nReal-world via markdown-it 14.x (`{linkify:true}`), `md.render(\u0027mailto:\u0027.repeat(n))`: 219 KB \u2248 ~5 s.\n\u003cimg width=\"737\" height=\"161\" alt=\"image\" src=\"https://github.com/user-attachments/assets/b5d390f3-68d0-4861-9c47-ad8aff0203d5\" /\u003e\n\n### Impact\nReachable on arbitrary user text via the documented `.test()`/`.match()` API and through markdown-it\u0027s\nlinkifier \u2014 comment systems, chat, forums, wikis, note apps that render user markdown with linkify enabled.\nA ~220 KB post hangs the event loop ~5 s; a few hundred KB \u2192 tens of seconds. Availability only.\n\n### Suggested remediation\nBound the email local-part per RFC 5321 (\u226464) so per-hit work is O(1), and avoid the full-tail slice:\n```js\n// lib/re.mjs \u2014 cap the greedy run:\nre.src_email_name = \u0027[\\\\-;:\u0026=\\\\+\\\\$,\\\\.a-zA-Z0-9_][\\\\-;:\u0026=\\\\+\\\\$,\\\\\"\\\\.a-zA-Z0-9_]{0,63}\u0027\n// index.mjs \u2014 prefer a sticky regex anchored at `pos` over text.slice(pos).\n```\n\n### Affected / disclosure\nAll versions through 5.0.1 (latest); same code on `master`. cve-mcp/OSV report no known vulnerability for\nlinkify-it. Distinct from markdown-it\u0027s own `*`-run ReDoS (CVE-2026-2327, different package/path) and the\nrecent markdown-it DoS. Reported privately; happy to test a patch against the PoC.",
  "id": "GHSA-v245-v573-v5vm",
  "modified": "2026-07-21T19:06:09Z",
  "published": "2026-07-21T19:06:09Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/markdown-it/linkify-it/security/advisories/GHSA-v245-v573-v5vm"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-59887"
    },
    {
      "type": "WEB",
      "url": "https://github.com/markdown-it/linkify-it/commit/105e5d77f7d119871d2b2d86ed208568eb3e7ffe"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/markdown-it/linkify-it"
    },
    {
      "type": "WEB",
      "url": "https://github.com/markdown-it/linkify-it/releases/tag/5.0.2"
    }
  ],
  "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": "linkify-it: Quadratic-complexity DoS via the `mailto:` validator scan-loop on attacker text"
}

GHSA-V569-HP3G-36WR

Vulnerability from github – Published: 2026-04-02 20:32 – Updated: 2026-05-13 16:18
VLAI
Summary
Rack has quadratic complexity in Rack::Utils.select_best_encoding via wildcard Accept-Encoding header
Details

Summary

Rack::Utils.select_best_encoding processes Accept-Encoding values with quadratic time complexity when the header contains many wildcard (*) entries. Because this method is used by Rack::Deflater to choose a response encoding, an unauthenticated attacker can send a single request with a crafted Accept-Encoding header and cause disproportionate CPU consumption on the compression middleware path.

This results in a denial of service condition for applications using Rack::Deflater.

Details

Rack::Utils.select_best_encoding expands parsed Accept-Encoding values into a list of candidate encodings. When an entry is *, the method computes the set of concrete encodings by subtracting the encodings already present in the request:

if m == "*"
  (available_encodings - accept_encoding.map(&:first)).each do |m2|
    expanded_accept_encoding << [m2, q, preference]
  end
else
  expanded_accept_encoding << [m, q, preference]
end

Because accept_encoding.map(&:first) is evaluated inside the loop, it is recomputed for each wildcard entry. If the request contains N wildcard entries, this produces repeated scans over the full parsed header and causes quadratic behavior.

After expansion, the method also performs additional work over expanded_accept_encoding, including per-entry deletion, which further increases the cost for large inputs.

Rack::Deflater invokes this method for each request when the middleware is enabled:

Utils.select_best_encoding(ENCODINGS, Utils.parse_encodings(accept_encoding))

As a result, a client can trigger this expensive code path simply by sending a large Accept-Encoding header containing many repeated wildcard values.

For example, a request with an approximately 8 KB Accept-Encoding header containing about 1,000 *;q=0.5 entries can cause roughly 170 ms of CPU time in a single request on the Rack::Deflater path, compared to a negligible baseline for a normal header.

This issue is distinct from CVE-2024-26146. That issue concerned regular expression denial of service during Accept header parsing, whereas this issue arises later during encoding selection after the header has already been parsed.

Impact

Any Rack application using Rack::Deflater may be affected.

An unauthenticated attacker can send requests with crafted Accept-Encoding headers to trigger excessive CPU usage in the encoding selection logic. Repeated requests can consume worker time disproportionately and reduce application availability.

The attack does not require invalid HTTP syntax or large payload bodies. A single header-sized request is sufficient to reach the vulnerable code path.

Mitigation

  • Update to a patched version of Rack in which encoding selection does not repeatedly rescan the parsed header for wildcard entries.
  • Avoid enabling Rack::Deflater on untrusted traffic.
  • Apply request filtering or header size / format restrictions at the reverse proxy or application boundary to limit abusive Accept-Encoding values.
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "RubyGems",
        "name": "rack"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "2.2.23"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "RubyGems",
        "name": "rack"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "3.0.0.beta1"
            },
            {
              "fixed": "3.1.21"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "RubyGems",
        "name": "rack"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "3.2.0"
            },
            {
              "fixed": "3.2.6"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-34230"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-400",
      "CWE-407"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-04-02T20:32:19Z",
    "nvd_published_at": "2026-04-02T17:16:23Z",
    "severity": "HIGH"
  },
  "details": "## Summary\n\n`Rack::Utils.select_best_encoding` processes `Accept-Encoding` values with quadratic time complexity when the header contains many wildcard (`*`) entries. Because this method is used by `Rack::Deflater` to choose a response encoding, an unauthenticated attacker can send a single request with a crafted `Accept-Encoding` header and cause disproportionate CPU consumption on the compression middleware path.\n\nThis results in a denial of service condition for applications using `Rack::Deflater`.\n\n## Details\n\n`Rack::Utils.select_best_encoding` expands parsed `Accept-Encoding` values into a list of candidate encodings. When an entry is `*`, the method computes the set of concrete encodings by subtracting the encodings already present in the request:\n\n```ruby\nif m == \"*\"\n  (available_encodings - accept_encoding.map(\u0026:first)).each do |m2|\n    expanded_accept_encoding \u003c\u003c [m2, q, preference]\n  end\nelse\n  expanded_accept_encoding \u003c\u003c [m, q, preference]\nend\n```\n\nBecause `accept_encoding.map(\u0026:first)` is evaluated inside the loop, it is recomputed for each wildcard entry. If the request contains `N` wildcard entries, this produces repeated scans over the full parsed header and causes quadratic behavior.\n\nAfter expansion, the method also performs additional work over `expanded_accept_encoding`, including per-entry deletion, which further increases the cost for large inputs.\n\n`Rack::Deflater` invokes this method for each request when the middleware is enabled:\n\n```ruby\nUtils.select_best_encoding(ENCODINGS, Utils.parse_encodings(accept_encoding))\n```\n\nAs a result, a client can trigger this expensive code path simply by sending a large `Accept-Encoding` header containing many repeated wildcard values.\n\nFor example, a request with an approximately 8 KB `Accept-Encoding` header containing about 1,000 `*;q=0.5` entries can cause roughly 170 ms of CPU time in a single request on the `Rack::Deflater` path, compared to a negligible baseline for a normal header.\n\nThis issue is distinct from CVE-2024-26146. That issue concerned regular expression denial of service during `Accept` header parsing, whereas this issue arises later during encoding selection after the header has already been parsed.\n\n## Impact\n\nAny Rack application using `Rack::Deflater` may be affected.\n\nAn unauthenticated attacker can send requests with crafted `Accept-Encoding` headers to trigger excessive CPU usage in the encoding selection logic. Repeated requests can consume worker time disproportionately and reduce application availability.\n\nThe attack does not require invalid HTTP syntax or large payload bodies. A single header-sized request is sufficient to reach the vulnerable code path.\n\n## Mitigation\n\n* Update to a patched version of Rack in which encoding selection does not repeatedly rescan the parsed header for wildcard entries.\n* Avoid enabling `Rack::Deflater` on untrusted traffic.\n* Apply request filtering or header size / format restrictions at the reverse proxy or application boundary to limit abusive `Accept-Encoding` values.",
  "id": "GHSA-v569-hp3g-36wr",
  "modified": "2026-05-13T16:18:11Z",
  "published": "2026-04-02T20:32:19Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/rack/rack/security/advisories/GHSA-v569-hp3g-36wr"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-34230"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/rack/rack"
    },
    {
      "type": "WEB",
      "url": "https://github.com/rubysec/ruby-advisory-db/blob/master/gems/rack/CVE-2026-34230.yml"
    }
  ],
  "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": "Rack has quadratic complexity in Rack::Utils.select_best_encoding via wildcard Accept-Encoding header"
}

GHSA-V6X5-CG8R-VV6X

Vulnerability from github – Published: 2026-04-02 20:30 – Updated: 2026-05-13 16:18
VLAI
Summary
Rack's multipart header parsing allows Denial of Service via escape-heavy quoted parameters
Details

Summary

Rack::Multipart::Parser#handle_mime_head parses quoted multipart parameters such as Content-Disposition: form-data; name="..." using repeated String#index searches combined with String#slice! prefix deletion. For escape-heavy quoted values, this causes super-linear processing.

An unauthenticated attacker can send a crafted multipart/form-data request containing many parts with long backslash-escaped parameter values to trigger excessive CPU usage during multipart parsing.

This results in a denial of service condition in Rack applications that accept multipart form data.

Details

Rack::Multipart::Parser#handle_mime_head parses quoted parameter values by repeatedly:

  1. Searching for the next quote or backslash,
  2. Copying the preceding substring into a new buffer, and
  3. Removing the processed prefix from the original string with slice!.

An attacker can exploit this by sending a multipart request with many parts whose name parameters contain long escape-heavy values such as:

name="a\\a\\a\\a\\a\\..."

Under default Rack limits, a request can contain up to 4095 parts. If many of those parts use long quoted values with dense escape characters, the parser performs disproportionately expensive CPU work while remaining within normal request size and part-count limits.

Impact

Any Rack application that accepts multipart/form-data requests may be affected, including file upload endpoints and standard HTML form handlers.

An unauthenticated attacker can send crafted multipart requests that consume excessive CPU time during request parsing. Repeated requests can tie up application workers, reduce throughput, and degrade or deny service availability.

Mitigation

  • Update to a patched version of Rack that parses quoted multipart parameters without repeated rescanning and destructive prefix deletion.
  • Apply request throttling or rate limiting to multipart upload endpoints.
  • Where operationally feasible, restrict or isolate multipart parsing on untrusted high-volume endpoints.
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "RubyGems",
        "name": "rack"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "3.0.0.beta1"
            },
            {
              "fixed": "3.1.21"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "RubyGems",
        "name": "rack"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "3.2.0"
            },
            {
              "fixed": "3.2.6"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-34827"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-400",
      "CWE-407",
      "CWE-770"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-04-02T20:30:12Z",
    "nvd_published_at": "2026-04-02T18:16:33Z",
    "severity": "HIGH"
  },
  "details": "## Summary\n\n`Rack::Multipart::Parser#handle_mime_head` parses quoted multipart parameters such as `Content-Disposition: form-data; name=\"...\"` using repeated `String#index` searches combined with `String#slice!` prefix deletion. For escape-heavy quoted values, this causes super-linear processing.\n\nAn unauthenticated attacker can send a crafted `multipart/form-data` request containing many parts with long backslash-escaped parameter values to trigger excessive CPU usage during multipart parsing.\n\nThis results in a denial of service condition in Rack applications that accept multipart form data.\n\n## Details\n\n`Rack::Multipart::Parser#handle_mime_head` parses quoted parameter values by repeatedly:\n\n1. Searching for the next quote or backslash,\n2. Copying the preceding substring into a new buffer, and\n3. Removing the processed prefix from the original string with `slice!`.\n\nAn attacker can exploit this by sending a multipart request with many parts whose `name` parameters contain long escape-heavy values such as:\n\n```text\nname=\"a\\\\a\\\\a\\\\a\\\\a\\\\...\"\n```\n\nUnder default Rack limits, a request can contain up to 4095 parts. If many of those parts use long quoted values with dense escape characters, the parser performs disproportionately expensive CPU work while remaining within normal request size and part-count limits.\n\n## Impact\n\nAny Rack application that accepts `multipart/form-data` requests may be affected, including file upload endpoints and standard HTML form handlers.\n\nAn unauthenticated attacker can send crafted multipart requests that consume excessive CPU time during request parsing. Repeated requests can tie up application workers, reduce throughput, and degrade or deny service availability.\n\n## Mitigation\n\n* Update to a patched version of Rack that parses quoted multipart parameters without repeated rescanning and destructive prefix deletion.\n* Apply request throttling or rate limiting to multipart upload endpoints.\n* Where operationally feasible, restrict or isolate multipart parsing on untrusted high-volume endpoints.",
  "id": "GHSA-v6x5-cg8r-vv6x",
  "modified": "2026-05-13T16:18:33Z",
  "published": "2026-04-02T20:30:12Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/rack/rack/security/advisories/GHSA-v6x5-cg8r-vv6x"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-34827"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/rack/rack"
    },
    {
      "type": "WEB",
      "url": "https://github.com/rubysec/ruby-advisory-db/blob/master/gems/rack/CVE-2026-34827.yml"
    }
  ],
  "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": "Rack\u0027s multipart header parsing allows Denial of Service via escape-heavy quoted parameters"
}

GHSA-VRCR-9HJ9-JCG6

Vulnerability from github – Published: 2025-12-02 18:30 – Updated: 2026-06-05 14:34
VLAI
Summary
Django is vulnerable to DoS via XML serializer text extraction
Details

An issue was discovered in 5.2 before 5.2.9, 5.1 before 5.1.15, and 4.2 before 4.2.27. Algorithmic complexity in django.core.serializers.xml_serializer.getInnerText() allows a remote attacker to cause a potential denial-of-service attack triggering CPU and memory exhaustion via specially crafted XML input processed by the XML Deserializer. Earlier, unsupported Django series (such as 5.0.x, 4.1.x, and 3.2.x) were not evaluated and may also be affected. Django would like to thank Seokchan Yoon for reporting this issue.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "Django"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "5.2a1"
            },
            {
              "fixed": "5.2.9"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "Django"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "5.1a1"
            },
            {
              "fixed": "5.1.15"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "Django"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "4.2a1"
            },
            {
              "fixed": "4.2.27"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2025-64460"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-407"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2025-12-03T16:59:02Z",
    "nvd_published_at": "2025-12-02T16:15:56Z",
    "severity": "MODERATE"
  },
  "details": "An issue was discovered in 5.2 before 5.2.9, 5.1 before 5.1.15, and 4.2 before 4.2.27.\nAlgorithmic complexity in `django.core.serializers.xml_serializer.getInnerText()` allows a remote attacker to cause a potential denial-of-service attack triggering CPU and memory exhaustion via specially crafted XML input processed by the XML `Deserializer`.\nEarlier, unsupported Django series (such as 5.0.x, 4.1.x, and 3.2.x) were not evaluated and may also be affected.\nDjango would like to thank Seokchan Yoon for reporting this issue.",
  "id": "GHSA-vrcr-9hj9-jcg6",
  "modified": "2026-06-05T14:34:31Z",
  "published": "2025-12-02T18:30:35Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-64460"
    },
    {
      "type": "WEB",
      "url": "https://github.com/django/django/commit/0db9ea4669312f1f4973e09f4bca06ab9c1ec74b"
    },
    {
      "type": "WEB",
      "url": "https://github.com/django/django/commit/1dbd07a608e495a0c229edaaf84d58d8976313b5"
    },
    {
      "type": "WEB",
      "url": "https://github.com/django/django/commit/4d2b8803bebcdefd2b76e9e8fc528d5fddea93f0"
    },
    {
      "type": "WEB",
      "url": "https://github.com/django/django/commit/99e7d22f55497278d0bcb2e15e72ef532e62a31d"
    },
    {
      "type": "WEB",
      "url": "https://docs.djangoproject.com/en/dev/releases/security"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/django/django"
    },
    {
      "type": "WEB",
      "url": "https://github.com/pypa/advisory-database/tree/main/vulns/django/PYSEC-2025-109.yaml"
    },
    {
      "type": "WEB",
      "url": "https://groups.google.com/g/django-announce"
    },
    {
      "type": "WEB",
      "url": "https://www.djangoproject.com/weblog/2025/dec/02/security-releases"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Django is vulnerable to DoS via XML serializer text extraction"
}

GHSA-W4GW-W5JQ-G9JH

Vulnerability from github – Published: 2026-02-12 22:06 – Updated: 2026-02-12 22:06
VLAI
Summary
golang.org/x/net/html has a Quadratic Parsing Complexity issue
Details

The html.Parse function in golang.org/x/net/html has quadratic parsing complexity when processing certain inputs, which can lead to Denial of Service (DoS) if an attacker provides specially crafted HTML content.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "golang.org/x/net/html"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.45.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2025-47911"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-407"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-02-12T22:06:13Z",
    "nvd_published_at": "2026-02-05T18:16:09Z",
    "severity": "MODERATE"
  },
  "details": "The html.Parse function in golang.org/x/net/html has quadratic parsing complexity when processing certain inputs, which can lead to Denial of Service (DoS) if an attacker provides specially crafted HTML content.",
  "id": "GHSA-w4gw-w5jq-g9jh",
  "modified": "2026-02-12T22:06:13Z",
  "published": "2026-02-12T22:06:13Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-47911"
    },
    {
      "type": "WEB",
      "url": "https://github.com/golang/vulndb/issues/4440"
    },
    {
      "type": "WEB",
      "url": "https://go.dev/cl/709876"
    },
    {
      "type": "PACKAGE",
      "url": "https://go.googlesource.com/net"
    },
    {
      "type": "WEB",
      "url": "https://groups.google.com/g/golang-announce/c/jnQcOYpiR2c"
    },
    {
      "type": "WEB",
      "url": "https://pkg.go.dev/vuln/GO-2026-4440"
    }
  ],
  "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:L",
      "type": "CVSS_V3"
    }
  ],
  "summary": "golang.org/x/net/html has a Quadratic Parsing Complexity issue"
}

GHSA-WF6M-89Q7-H9JH

Vulnerability from github – Published: 2023-07-26 21:30 – Updated: 2024-04-04 06:22
VLAI
Details

Trustwave ModSecurity 3.x before 3.0.10 has Inefficient Algorithmic Complexity.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2023-38285"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-407"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2023-07-26T21:15:10Z",
    "severity": "HIGH"
  },
  "details": "Trustwave ModSecurity 3.x before 3.0.10 has Inefficient Algorithmic Complexity.",
  "id": "GHSA-wf6m-89q7-h9jh",
  "modified": "2024-04-04T06:22:21Z",
  "published": "2023-07-26T21:30:20Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-38285"
    },
    {
      "type": "WEB",
      "url": "https://www.trustwave.com/en-us/resources/blogs/spiderlabs-blog/modsecurity-v3-dos-vulnerability-in-four-transformations-cve-2023-38285"
    },
    {
      "type": "WEB",
      "url": "https://www.trustwave.com/en-us/resources/security-resources/software-updates/end-of-sale-and-trustwave-support-for-modsecurity-web-application-firewall"
    }
  ],
  "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-WP3C-266W-4QFQ

Vulnerability from github – Published: 2026-06-26 22:21 – Updated: 2026-06-26 22:21
VLAI
Summary
js-toml vulnerable to CPU exhaustion via O(n^2) BigInt construction on radix-prefixed integer literals
Details

Summary

js-toml versions up to and including 1.1.0 parse hexadecimal / octal / binary integer literals via a hand-written parseBigInt loop that multiplies a BigInt accumulator by the radix once per input digit. Each iteration performs a BigInt * BigInt operation on an accumulator that grows linearly with the number of digits already consumed, so the whole loop is O(n²) in the literal length. The lexer regex places no upper bound on the literal length, so a single TOML document containing one ~500 kB hex literal pins one CPU core for ~40 seconds on a modern laptop (Apple M-series, Node v22). Memory amplification is bounded but CPU amplification is severe and grows quadratically: doubling the literal length quadruples the work.

A caller that invokes load() on attacker-controlled TOML (configuration upload endpoints, CI/CD systems ingesting third-party *.toml, IDE plugins, build tools) is exposed to a single-request CPU exhaustion DoS.

CWE-1333 (Inefficient Regular Expression Complexity → here, inefficient parser complexity), CWE-400 (Uncontrolled Resource Consumption), CWE-407 (Inefficient Algorithmic Complexity).

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H = 7.5 (HIGH) when the parser is invoked on attacker-controllable input; LOW when the calling application restricts TOML input size to small documents (< 1 kB).

Affected

  • Package: js-toml (npm)
  • Versions: >= 0.0.0, <= 1.1.0 (all released versions up to and including the current 1.1.0)
  • Affected entry point: load() exported from the package root

Vulnerable code

src/load/tokens/NonDecimalInteger.ts lines 54-84 at SHA-pinned 2470ebf2e9009096aa4cbd1a15e574c54cc36b1a:

const parseBigInt = (string: string, radix: number): bigint => {
  let result = BigInt(0);
  for (let i = 0; i < string.length; i++) {
    const char = string[i];
    const digit = parseInt(char, radix);
    result = result * BigInt(radix) + BigInt(digit);
  }

  return result;
};

and the interpreter that dispatches to it at lines 72-84:

registerTokenInterpreter(NonDecimalInteger, (raw: string) => {
  const intString = raw.replace(/_/g, '');
  const digits = intString.slice(2);
  const radix = getRadix(raw);

  const int = parseInt(digits, radix);

  if (Number.isSafeInteger(int)) {
    return int;
  }

  return parseBigInt(digits, radix);
});

Two compounding problems:

  1. Algorithmic: the loop performs result * BigInt(radix) + BigInt(digit) once per input digit. After i iterations result has O(i) limbs, so the multiply costs O(i). Summed over n digits the total cost is O(n²).

  2. No length guard: the lexer regex at src/load/tokens/NonDecimalInteger.ts#L14-L46 is 0x<hexDigit>(<hexDigit>|_<hexDigit>)* (likewise for 0o / 0b). The literal length is bounded only by the input document size. There is no maxNumberLength / maxLiteralLength option, no chevrotain-level cutoff, and no validation at the interpreter callsite.

By contrast, the DecimalInteger token interpreter at src/load/tokens/DecimalInteger.ts#L12-L19 uses the V8 native BigInt(intString) constructor, which is O(n) and runs in single-digit milliseconds for inputs that take 40 seconds via the hand-written radix loop.

Impact

A single attacker-supplied TOML document containing one ~500 kB radix-prefixed integer literal pins one CPU core for ~40 seconds on a modern laptop. Doubling the literal length quadruples the work. With 8 MB of input the parse would block the event loop for many minutes of CPU. In a typical Node.js single-thread process this blocks all concurrent request handling for the duration. The defect is exploitable on any code path that calls load() (the only documented entry point) on attacker-controlled or third-party TOML.

Reachability

The vulnerable path is the default code path for load(). No options or configuration are required to trigger it. Any caller that exposes load() to attacker-controlled or third-party TOML input reaches it on the first hex / octal / binary literal whose value exceeds Number.MAX_SAFE_INTEGER (i.e. more than 13 hex digits, 18 octal digits, or 53 binary digits).

Realistic exposure surfaces:

  • Web service that accepts a user-supplied TOML configuration (settings import, theme upload, deployment manifest).
  • CI / CD or build tool that runs js-toml on TOML in third-party repositories or pull requests.
  • IDE / language-server plugin that re-parses a TOML buffer on every keystroke.
  • Multi-tenant SaaS that lets one tenant submit TOML processed by a shared worker.

PoC (End-to-end reproduction)

Environment

  • Node.js v22.x (tested on v22.0.0 and Node v26.0.0)
  • macOS arm64 / Linux x86_64 (CPU exhaustion is hardware-independent; absolute timings will scale by CPU clock)

Install

mkdir js-toml-cve && cd js-toml-cve
npm init -y
npm install js-toml@1.1.0 @iarna/toml

poc_full_e2e.mjs

import { load } from 'js-toml';
import iarna from '@iarna/toml';

function timeIt(label, fn) {
  const t0 = process.hrtime.bigint();
  let result, err;
  try { result = fn(); } catch (e) { err = e; }
  const t1 = process.hrtime.bigint();
  const ms = (Number(t1 - t0) / 1e6).toFixed(1);
  if (err) console.log(`${label}: ERROR ${err.message} after ${ms}ms`);
  else     console.log(`${label}: ${ms}ms${result ? ' ' + result : ''}`);
}

console.log('--- Sanity baseline (small inputs) ---');
timeIt('decimal int 1', () => { load('x = 1'); return ''; });
timeIt('hex 0x10',      () => { load('x = 0x10'); return ''; });
timeIt('hex 0xffff',    () => { load('x = 0xffff'); return ''; });

console.log('\n--- Amplification curve: js-toml.load() with 0x<N hex digits> ---');
for (const n of [10_000, 20_000, 50_000, 100_000, 200_000, 500_000]) {
  const hexDigits = 'f'.repeat(n);
  const tomlText  = `x = 0x${hexDigits}`;
  timeIt(`hex ${n.toLocaleString()} digits (${tomlText.length} bytes input)`,
    () => {
      const r = load(tomlText);
      return `bits=${r.x.toString(2).length}`;
    });
}

console.log('\n--- Negative control: same input via @iarna/toml ---');
for (const n of [10_000, 50_000, 100_000, 200_000]) {
  const hexDigits = 'f'.repeat(n);
  const tomlText  = `x = 0x${hexDigits}`;
  timeIt(`@iarna/toml hex ${n.toLocaleString()} digits`,
    () => {
      const r = iarna.parse(tomlText);
      return `type=${typeof r.x}`;
    });
}

console.log('\n--- Octal / binary share the same code path ---');
for (const n of [50_000, 100_000]) {
  const octDigits = '7'.repeat(n);
  const binDigits = '1'.repeat(n);
  timeIt(`oct 0o${n.toLocaleString()} digits`,
    () => { const r = load(`x = 0o${octDigits}`); return `bits=${r.x.toString(2).length}`; });
  timeIt(`bin 0b${n.toLocaleString()} digits`,
    () => { const r = load(`x = 0b${binDigits}`); return `bits=${r.x.toString(2).length}`; });
}

Captured run output (unpatched js-toml@1.1.0, Node v26.0.0, Apple M-series)

# js-toml version: 1.1.0

--- Sanity baseline (small inputs) ---
decimal int 1: 1.3ms
hex 0x10: 0.4ms
hex 0xffff: 0.1ms

--- Amplification curve: js-toml.load() with 0x<N hex digits> ---
hex 10,000 digits (10006 bytes input): 15.0ms bits=40000
hex 20,000 digits (20006 bytes input): 29.8ms bits=80000
hex 50,000 digits (50006 bytes input): 214.7ms bits=200000
hex 100,000 digits (100006 bytes input): 693.0ms bits=400000
hex 200,000 digits (200006 bytes input): 3239.6ms bits=800000
hex 500,000 digits (500006 bytes input): 40388.3ms bits=2000000

--- Negative control: same input via @iarna/toml ---
@iarna/toml hex 10,000 digits: 2.3ms type=bigint
@iarna/toml hex 50,000 digits: 3.2ms type=bigint
@iarna/toml hex 100,000 digits: 5.4ms type=bigint
@iarna/toml hex 200,000 digits: 10.2ms type=bigint

--- Octal / binary share the same code path ---
oct 0o50,000 digits: 187.6ms bits=150000
bin 0b50,000 digits: 49.5ms bits=50000
oct 0o100,000 digits: 633.2ms bits=300000
bin 0b100,000 digits: 196.8ms bits=100000

Confirmation points:

  • Quadratic curve: 10k → 20k digits is ~2x time (15ms → 30ms); 100k → 200k is ~4.7x time (693ms → 3239ms); 200k → 500k (2.5x) is ~12x time (3.2s → 40s). Matches the predicted O(n²).
  • Single ~500 kB document blocks the event loop for ~40 s of CPU time.
  • Octal and binary literals trigger the same path through parseBigInt(digits, 8) and parseBigInt(digits, 2).
  • The negative control (@iarna/toml, which calls the V8 native BigInt(value) constructor) parses the same inputs in 2-10 ms. The defect is in js-toml's hand-written radix conversion, not in V8 BigInt semantics or in the input size itself.

Patched-build verification

After applying the fix (replace parseBigInt(digits, radix) with BigInt('0' + raw[1] + digits) and add a maxLiteralLength guard at the interpreter callsite), the same PoC produces:

--- Amplification curve: js-toml.load() with 0x<N hex digits> ---
hex 10,000 digits: 0.2ms bits=40000
hex 20,000 digits: 0.3ms bits=80000
hex 50,000 digits: 0.7ms bits=200000
hex 100,000 digits: 1.5ms bits=400000
hex 200,000 digits: 2.8ms bits=800000
hex 500,000 digits: 7.1ms bits=2000000

(Linear scaling, sub-10 ms even on inputs five orders of magnitude larger than any realistic literal.) With a 1000-digit cap applied at the interpreter callsite, literals beyond the cap raise SyntaxParseError instead of being parsed at all, matching the maxNumberLength convention used by jackson-core StreamReadConstraints and gson NumberLimits.

Suggested fix

Two changes, both in src/load/tokens/NonDecimalInteger.ts:

  1. Replace the hand-written parseBigInt loop with the V8 native BigInt(prefixedString) constructor. BigInt natively accepts the 0x / 0o / 0b prefix and parses in O(n):

```ts registerTokenInterpreter(NonDecimalInteger, (raw: string) => { const intString = raw.replace(/_/g, ''); const digits = intString.slice(2); const radix = getRadix(raw);

 // Optional but recommended: cap the literal length to avoid degenerate inputs
 const MAX_RADIX_LITERAL_LENGTH = 1000;
 if (digits.length > MAX_RADIX_LITERAL_LENGTH) {
   throw new SyntaxParseError(
     `Radix-prefixed integer literal exceeds ${MAX_RADIX_LITERAL_LENGTH} digits`
   );
 }

 const int = parseInt(digits, radix);
 if (Number.isSafeInteger(int)) {
   return int;
 }

 // BigInt accepts '0x'/'0o'/'0b' prefix natively
 return BigInt(intString);

}); ```

  1. Delete the parseBigInt helper. The native constructor handles all three radices.

Either change alone fixes the worst-case wall-clock. The combination matches the constraint posture of jackson-core (StreamReadConstraints.validateIntegerLength) and gson (NumberLimits.checkNumberStringLength).

Fix PR link

https://github.com/sunnyadn/js-toml/commit/1abcb31dc7b1fa88e4c848a8d108891cfbb96fa2

Credit

Reported by tonghuaroot.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 1.1.0"
      },
      "package": {
        "ecosystem": "npm",
        "name": "js-toml"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.1.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-49293"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-1333",
      "CWE-400",
      "CWE-407"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-26T22:21:43Z",
    "nvd_published_at": "2026-06-19T19:16:36Z",
    "severity": "HIGH"
  },
  "details": "## Summary\n\n`js-toml` versions up to and including **1.1.0** parse hexadecimal / octal / binary integer literals via a hand-written `parseBigInt` loop that multiplies a `BigInt` accumulator by the radix once per input digit. Each iteration performs a `BigInt * BigInt` operation on an accumulator that grows linearly with the number of digits already consumed, so the whole loop is **O(n\u00b2)** in the literal length. The lexer regex places **no upper bound on the literal length**, so a single TOML document containing one ~500 kB hex literal pins one CPU core for **~40 seconds** on a modern laptop (Apple M-series, Node v22). Memory amplification is bounded but CPU amplification is severe and grows quadratically: doubling the literal length quadruples the work.\n\nA caller that invokes `load()` on attacker-controlled TOML (configuration upload endpoints, CI/CD systems ingesting third-party `*.toml`, IDE plugins, build tools) is exposed to a single-request CPU exhaustion DoS.\n\nCWE-1333 (Inefficient Regular Expression Complexity \u2192 here, inefficient parser complexity), CWE-400 (Uncontrolled Resource Consumption), CWE-407 (Inefficient Algorithmic Complexity).\n\nCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H = **7.5 (HIGH)** when the parser is invoked on attacker-controllable input; LOW when the calling application restricts TOML input size to small documents (\u003c 1 kB).\n\n## Affected\n\n- Package: `js-toml` (npm)\n- Versions: `\u003e= 0.0.0, \u003c= 1.1.0` (all released versions up to and including the current `1.1.0`)\n- Affected entry point: `load()` exported from the package root\n\n## Vulnerable code\n\n`src/load/tokens/NonDecimalInteger.ts` lines 54-84 at SHA-pinned [`2470ebf2e9009096aa4cbd1a15e574c54cc36b1a`](https://github.com/sunnyadn/js-toml/blob/2470ebf2e9009096aa4cbd1a15e574c54cc36b1a/src/load/tokens/NonDecimalInteger.ts#L54-L84):\n\n```ts\nconst parseBigInt = (string: string, radix: number): bigint =\u003e {\n  let result = BigInt(0);\n  for (let i = 0; i \u003c string.length; i++) {\n    const char = string[i];\n    const digit = parseInt(char, radix);\n    result = result * BigInt(radix) + BigInt(digit);\n  }\n\n  return result;\n};\n```\n\nand the interpreter that dispatches to it at lines 72-84:\n\n```ts\nregisterTokenInterpreter(NonDecimalInteger, (raw: string) =\u003e {\n  const intString = raw.replace(/_/g, \u0027\u0027);\n  const digits = intString.slice(2);\n  const radix = getRadix(raw);\n\n  const int = parseInt(digits, radix);\n\n  if (Number.isSafeInteger(int)) {\n    return int;\n  }\n\n  return parseBigInt(digits, radix);\n});\n```\n\nTwo compounding problems:\n\n1. **Algorithmic**: the loop performs `result * BigInt(radix) + BigInt(digit)` once per input digit. After `i` iterations `result` has `O(i)` limbs, so the multiply costs `O(i)`. Summed over `n` digits the total cost is `O(n\u00b2)`.\n\n2. **No length guard**: the lexer regex at [`src/load/tokens/NonDecimalInteger.ts#L14-L46`](https://github.com/sunnyadn/js-toml/blob/2470ebf2e9009096aa4cbd1a15e574c54cc36b1a/src/load/tokens/NonDecimalInteger.ts#L14-L46) is `0x\u003chexDigit\u003e(\u003chexDigit\u003e|_\u003chexDigit\u003e)*` (likewise for `0o` / `0b`). The literal length is bounded only by the input document size. There is no `maxNumberLength` / `maxLiteralLength` option, no `chevrotain`-level cutoff, and no validation at the interpreter callsite.\n\nBy contrast, the `DecimalInteger` token interpreter at [`src/load/tokens/DecimalInteger.ts#L12-L19`](https://github.com/sunnyadn/js-toml/blob/2470ebf2e9009096aa4cbd1a15e574c54cc36b1a/src/load/tokens/DecimalInteger.ts#L12-L19) uses the V8 native `BigInt(intString)` constructor, which is `O(n)` and runs in single-digit milliseconds for inputs that take 40 seconds via the hand-written radix loop.\n\n## Impact\n\nA single attacker-supplied TOML document containing one ~500 kB radix-prefixed integer literal pins one CPU core for ~40 seconds on a modern laptop. Doubling the literal length quadruples the work. With `8 MB` of input the parse would block the event loop for many minutes of CPU. In a typical Node.js single-thread process this blocks all concurrent request handling for the duration. The defect is exploitable on any code path that calls `load()` (the only documented entry point) on attacker-controlled or third-party TOML.\n\n## Reachability\n\nThe vulnerable path is the default code path for `load()`. No options or configuration are required to trigger it. Any caller that exposes `load()` to attacker-controlled or third-party TOML input reaches it on the first hex / octal / binary literal whose value exceeds `Number.MAX_SAFE_INTEGER` (i.e. more than 13 hex digits, 18 octal digits, or 53 binary digits).\n\nRealistic exposure surfaces:\n\n- Web service that accepts a user-supplied TOML configuration (settings import, theme upload, deployment manifest).\n- CI / CD or build tool that runs `js-toml` on TOML in third-party repositories or pull requests.\n- IDE / language-server plugin that re-parses a TOML buffer on every keystroke.\n- Multi-tenant SaaS that lets one tenant submit TOML processed by a shared worker.\n\n## PoC (End-to-end reproduction)\n\n### Environment\n\n- Node.js `v22.x` (tested on `v22.0.0` and Node `v26.0.0`)\n- macOS arm64 / Linux x86_64 (CPU exhaustion is hardware-independent; absolute timings will scale by CPU clock)\n\n### Install\n\n```bash\nmkdir js-toml-cve \u0026\u0026 cd js-toml-cve\nnpm init -y\nnpm install js-toml@1.1.0 @iarna/toml\n```\n\n### `poc_full_e2e.mjs`\n\n```js\nimport { load } from \u0027js-toml\u0027;\nimport iarna from \u0027@iarna/toml\u0027;\n\nfunction timeIt(label, fn) {\n  const t0 = process.hrtime.bigint();\n  let result, err;\n  try { result = fn(); } catch (e) { err = e; }\n  const t1 = process.hrtime.bigint();\n  const ms = (Number(t1 - t0) / 1e6).toFixed(1);\n  if (err) console.log(`${label}: ERROR ${err.message} after ${ms}ms`);\n  else     console.log(`${label}: ${ms}ms${result ? \u0027 \u0027 + result : \u0027\u0027}`);\n}\n\nconsole.log(\u0027--- Sanity baseline (small inputs) ---\u0027);\ntimeIt(\u0027decimal int 1\u0027, () =\u003e { load(\u0027x = 1\u0027); return \u0027\u0027; });\ntimeIt(\u0027hex 0x10\u0027,      () =\u003e { load(\u0027x = 0x10\u0027); return \u0027\u0027; });\ntimeIt(\u0027hex 0xffff\u0027,    () =\u003e { load(\u0027x = 0xffff\u0027); return \u0027\u0027; });\n\nconsole.log(\u0027\\n--- Amplification curve: js-toml.load() with 0x\u003cN hex digits\u003e ---\u0027);\nfor (const n of [10_000, 20_000, 50_000, 100_000, 200_000, 500_000]) {\n  const hexDigits = \u0027f\u0027.repeat(n);\n  const tomlText  = `x = 0x${hexDigits}`;\n  timeIt(`hex ${n.toLocaleString()} digits (${tomlText.length} bytes input)`,\n    () =\u003e {\n      const r = load(tomlText);\n      return `bits=${r.x.toString(2).length}`;\n    });\n}\n\nconsole.log(\u0027\\n--- Negative control: same input via @iarna/toml ---\u0027);\nfor (const n of [10_000, 50_000, 100_000, 200_000]) {\n  const hexDigits = \u0027f\u0027.repeat(n);\n  const tomlText  = `x = 0x${hexDigits}`;\n  timeIt(`@iarna/toml hex ${n.toLocaleString()} digits`,\n    () =\u003e {\n      const r = iarna.parse(tomlText);\n      return `type=${typeof r.x}`;\n    });\n}\n\nconsole.log(\u0027\\n--- Octal / binary share the same code path ---\u0027);\nfor (const n of [50_000, 100_000]) {\n  const octDigits = \u00277\u0027.repeat(n);\n  const binDigits = \u00271\u0027.repeat(n);\n  timeIt(`oct 0o${n.toLocaleString()} digits`,\n    () =\u003e { const r = load(`x = 0o${octDigits}`); return `bits=${r.x.toString(2).length}`; });\n  timeIt(`bin 0b${n.toLocaleString()} digits`,\n    () =\u003e { const r = load(`x = 0b${binDigits}`); return `bits=${r.x.toString(2).length}`; });\n}\n```\n\n### Captured run output (unpatched `js-toml@1.1.0`, Node v26.0.0, Apple M-series)\n\n```\n# js-toml version: 1.1.0\n\n--- Sanity baseline (small inputs) ---\ndecimal int 1: 1.3ms\nhex 0x10: 0.4ms\nhex 0xffff: 0.1ms\n\n--- Amplification curve: js-toml.load() with 0x\u003cN hex digits\u003e ---\nhex 10,000 digits (10006 bytes input): 15.0ms bits=40000\nhex 20,000 digits (20006 bytes input): 29.8ms bits=80000\nhex 50,000 digits (50006 bytes input): 214.7ms bits=200000\nhex 100,000 digits (100006 bytes input): 693.0ms bits=400000\nhex 200,000 digits (200006 bytes input): 3239.6ms bits=800000\nhex 500,000 digits (500006 bytes input): 40388.3ms bits=2000000\n\n--- Negative control: same input via @iarna/toml ---\n@iarna/toml hex 10,000 digits: 2.3ms type=bigint\n@iarna/toml hex 50,000 digits: 3.2ms type=bigint\n@iarna/toml hex 100,000 digits: 5.4ms type=bigint\n@iarna/toml hex 200,000 digits: 10.2ms type=bigint\n\n--- Octal / binary share the same code path ---\noct 0o50,000 digits: 187.6ms bits=150000\nbin 0b50,000 digits: 49.5ms bits=50000\noct 0o100,000 digits: 633.2ms bits=300000\nbin 0b100,000 digits: 196.8ms bits=100000\n```\n\nConfirmation points:\n\n- Quadratic curve: 10k \u2192 20k digits is ~2x time (15ms \u2192 30ms); 100k \u2192 200k is ~4.7x time (693ms \u2192 3239ms); 200k \u2192 500k (2.5x) is ~12x time (3.2s \u2192 40s). Matches the predicted `O(n\u00b2)`.\n- Single ~500 kB document blocks the event loop for ~40 s of CPU time.\n- Octal and binary literals trigger the same path through `parseBigInt(digits, 8)` and `parseBigInt(digits, 2)`.\n- The negative control (`@iarna/toml`, which calls the V8 native `BigInt(value)` constructor) parses the same inputs in 2-10 ms. The defect is in `js-toml`\u0027s hand-written radix conversion, not in V8 `BigInt` semantics or in the input size itself.\n\n### Patched-build verification\n\nAfter applying the fix (replace `parseBigInt(digits, radix)` with `BigInt(\u00270\u0027 + raw[1] + digits)` and add a `maxLiteralLength` guard at the interpreter callsite), the same PoC produces:\n\n```\n--- Amplification curve: js-toml.load() with 0x\u003cN hex digits\u003e ---\nhex 10,000 digits: 0.2ms bits=40000\nhex 20,000 digits: 0.3ms bits=80000\nhex 50,000 digits: 0.7ms bits=200000\nhex 100,000 digits: 1.5ms bits=400000\nhex 200,000 digits: 2.8ms bits=800000\nhex 500,000 digits: 7.1ms bits=2000000\n```\n\n(Linear scaling, sub-10 ms even on inputs five orders of magnitude larger than any realistic literal.) With a 1000-digit cap applied at the interpreter callsite, literals beyond the cap raise `SyntaxParseError` instead of being parsed at all, matching the `maxNumberLength` convention used by `jackson-core` `StreamReadConstraints` and `gson` `NumberLimits`.\n\n## Suggested fix\n\nTwo changes, both in [`src/load/tokens/NonDecimalInteger.ts`](https://github.com/sunnyadn/js-toml/blob/2470ebf2e9009096aa4cbd1a15e574c54cc36b1a/src/load/tokens/NonDecimalInteger.ts):\n\n1. Replace the hand-written `parseBigInt` loop with the V8 native `BigInt(prefixedString)` constructor. `BigInt` natively accepts the `0x` / `0o` / `0b` prefix and parses in `O(n)`:\n\n   ```ts\n   registerTokenInterpreter(NonDecimalInteger, (raw: string) =\u003e {\n     const intString = raw.replace(/_/g, \u0027\u0027);\n     const digits = intString.slice(2);\n     const radix = getRadix(raw);\n\n     // Optional but recommended: cap the literal length to avoid degenerate inputs\n     const MAX_RADIX_LITERAL_LENGTH = 1000;\n     if (digits.length \u003e MAX_RADIX_LITERAL_LENGTH) {\n       throw new SyntaxParseError(\n         `Radix-prefixed integer literal exceeds ${MAX_RADIX_LITERAL_LENGTH} digits`\n       );\n     }\n\n     const int = parseInt(digits, radix);\n     if (Number.isSafeInteger(int)) {\n       return int;\n     }\n\n     // BigInt accepts \u00270x\u0027/\u00270o\u0027/\u00270b\u0027 prefix natively\n     return BigInt(intString);\n   });\n   ```\n\n2. Delete the `parseBigInt` helper. The native constructor handles all three radices.\n\nEither change alone fixes the worst-case wall-clock. The combination matches the constraint posture of `jackson-core` (`StreamReadConstraints.validateIntegerLength`) and `gson` (`NumberLimits.checkNumberStringLength`).\n\n## Fix PR link\n\nhttps://github.com/sunnyadn/js-toml/commit/1abcb31dc7b1fa88e4c848a8d108891cfbb96fa2\n\n## Credit\n\nReported by `tonghuaroot`.",
  "id": "GHSA-wp3c-266w-4qfq",
  "modified": "2026-06-26T22:21:43Z",
  "published": "2026-06-26T22:21:43Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/sunnyadn/js-toml/security/advisories/GHSA-wp3c-266w-4qfq"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-49293"
    },
    {
      "type": "WEB",
      "url": "https://github.com/sunnyadn/js-toml/commit/1abcb31dc7b1fa88e4c848a8d108891cfbb96fa2"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/sunnyadn/js-toml"
    },
    {
      "type": "WEB",
      "url": "https://github.com/sunnyadn/js-toml/releases/tag/v1.1.1"
    }
  ],
  "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-toml vulnerable to CPU exhaustion via O(n^2) BigInt construction on radix-prefixed integer literals"
}

GHSA-WRHR-37C7-3326

Vulnerability from github – Published: 2026-04-15 18:31 – Updated: 2026-04-16 15:31
VLAI
Details

Nordic Semiconductor IronSide SE for nRF54H20 before 23.0.2+17 has an Algorithmic complexity issue.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2025-67841"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-407"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-04-15T16:16:33Z",
    "severity": "HIGH"
  },
  "details": "Nordic Semiconductor IronSide SE for nRF54H20 before 23.0.2+17 has an Algorithmic complexity issue.",
  "id": "GHSA-wrhr-37c7-3326",
  "modified": "2026-04-16T15:31:32Z",
  "published": "2026-04-15T18:31:56Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-67841"
    },
    {
      "type": "WEB",
      "url": "https://docs.nordicsemi.com/bundle/SA/resource/SA-2025-447-v1.1.pdf"
    },
    {
      "type": "WEB",
      "url": "https://nordicsemi.no"
    }
  ],
  "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-X2GC-X3Q3-8FP4

Vulnerability from github – Published: 2022-05-24 16:55 – Updated: 2024-04-04 01:53
VLAI
Details

An issue was discovered in Total.js CMS 12.0.0. A low privilege user can perform a simple transformation of a cookie to obtain the random values inside it. If an attacker can discover a session cookie owned by an admin, then it is possible to brute force it with O(n)=2n instead of O(n)=n^x complexity, and steal the admin password.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2019-15955"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-327",
      "CWE-407"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2019-09-05T19:16:00Z",
    "severity": "MODERATE"
  },
  "details": "An issue was discovered in Total.js CMS 12.0.0. A low privilege user can perform a simple transformation of a cookie to obtain the random values inside it. If an attacker can discover a session cookie owned by an admin, then it is possible to brute force it with O(n)=2n instead of O(n)=n^x complexity, and steal the admin password.",
  "id": "GHSA-x2gc-x3q3-8fp4",
  "modified": "2024-04-04T01:53:20Z",
  "published": "2022-05-24T16:55:31Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2019-15955"
    },
    {
      "type": "WEB",
      "url": "https://github.com/beerpwn/CVE/blob/master/Totaljs_disclosure_report/report_final.pdf"
    },
    {
      "type": "WEB",
      "url": "https://seclists.org/fulldisclosure/2019/Sep/3"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N",
      "type": "CVSS_V3"
    }
  ]
}

No mitigation information available for this CWE.

No CAPEC attack patterns related to this CWE.