{"id":"CVE-2026-116579","aliases":["EUVD-2026-110320","GHSA-pjh6-c8mg-3x7m","UBUNTU-CVE-2026-116579"],"status":"published","title":"Autobahn Python: permessage-brotli inflates a whole frame before maxMessagePayloadSize is checked (incomplete fix of GHSA-hxp9-w8x3-p566)","description":"Autobahn Python is a WebSocket and WAMP implementation for Python that supports Twisted and asyncio. From 26.7.1 until 26.10.1, PerMessageBrotli.decompress_message_data in compress_brotli.py calls the Brotli decompressor without an output limit and checks maxMessagePayloadSize only after a complete frame has been inflated. An unauthenticated WebSocket client can send a small, highly compressed frame that allocates hundreds of MiB before rejection, causing memory-exhaustion denial of service on servers that enable the opt-in permessage-brotli feature through the compress extra. Deflate and bzip2 already enforce the remaining output budget and are outside this residual vulnerability. This issue is fixed in version 26.10.1.","severity":{"version":"3.1","score":5.9,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"medium","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-12","score":0.00425,"percentile":0.37261,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-409","CWE-770"],"published":"2026-10-26T20:29:22Z","modified":"2026-10-29T02:30:39Z","fixes":[{"ecosystem":"PyPI","package":"autobahn","fixed_in":["26.10.1"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"PyPI","package":"autobahn","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"26.7.1"},{"fixed":"26.10.1"}]}]},{"source":"osv","ecosystem":"PyPI","package":"autobahn","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"26.7.1"},{"fixed":"26.10.1"}]}],"versions":["26.7.1"]},{"source":"osv","ecosystem":"Ubuntu:16.04:LTS","package":"python-autobahn","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["0.10.3+dfsg1-2","0.10.3+dfsg1-3","0.10.3+dfsg1-5"]},{"source":"osv","ecosystem":"Ubuntu:18.04:LTS","package":"python-autobahn","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["0.14.1+dfsg1-2ubuntu1","17.10.1+dfsg1-2"]},{"source":"osv","ecosystem":"Ubuntu:20.04:LTS","package":"python-autobahn","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["17.10.1+dfsg1-5","17.10.1+dfsg1-6"]},{"source":"osv","ecosystem":"Ubuntu:22.04:LTS","package":"python-autobahn","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["17.10.1+dfsg1-7","21.11.1+dfsg1-2","21.11.1+dfsg1-2build1"]},{"source":"osv","ecosystem":"Ubuntu:24.04:LTS","package":"python-autobahn","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["22.7.1+dfsg1-3","22.7.1+dfsg1-4"]},{"source":"osv","ecosystem":"Ubuntu:26.10","package":"python-autobahn","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["24.4.2+dfsg1-5"]},{"source":"osv","ecosystem":"Ubuntu:26.04:LTS","package":"python-autobahn","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["23.1.2+dfsg1-2","24.4.2+dfsg1-4","24.4.2+dfsg1-5"]}],"products":[{"vendor":"crossbario","product":"autobahn-python"}],"references":[{"url":"https://github.com/crossbario/autobahn-python/security/advisories/GHSA-pjh6-c8mg-3x7m","tags":["x_refsource_CONFIRM","advisory","web","report"]},{"url":"https://github.com/crossbario/autobahn-python/pull/1987","tags":["x_refsource_MISC","fix","web","report"]},{"url":"https://github.com/crossbario/autobahn-python/commit/a41442bbee4f6126a8ce1bb892840124c24d16f1","tags":["x_refsource_MISC","fix","web","report"]},{"url":"https://github.com/crossbario/autobahn-python/releases/tag/v26_10_1","tags":["x_refsource_MISC","web","report"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-116579","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-pjh6-c8mg-3x7m"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/116xxx/CVE-2026-116579.json","tags":["advisory"]},{"url":"https://github.com/crossbario/autobahn-python","tags":["package"]},{"url":"https://ubuntu.com/security/CVE-2026-116579","tags":["report"]},{"url":"https://www.cve.org/CVERecord?id=CVE-2026-116579","tags":["report"]}],"sources":{"cve":[{"id":"CVE-2026-116579","title":"Autobahn Python: permessage-brotli inflates a whole frame before maxMessagePayloadSize is checked (incomplete fix of GHSA-hxp9-w8x3-p566)","description":"Autobahn Python is a WebSocket and WAMP implementation for Python that supports Twisted and asyncio. From 26.7.1 until 26.10.1, PerMessageBrotli.decompress_message_data in compress_brotli.py calls the Brotli decompressor without an output limit and checks maxMessagePayloadSize only after a complete frame has been inflated. An unauthenticated WebSocket client can send a small, highly compressed frame that allocates hundreds of MiB before rejection, causing memory-exhaustion denial of service on servers that enable the opt-in permessage-brotli feature through the compress extra. Deflate and bzip2 already enforce the remaining output budget and are outside this residual vulnerability. This issue is fixed in version 26.10.1.","status":"published","published":"2026-10-26T20:29:22.906Z","modified":"2026-10-27T14:18:18.772Z","cvss":[{"version":"3.1","score":5.9,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"medium","assessor":"cna"}],"cwes":["CWE-409","CWE-770"],"updated_at":"2026-11-02T14:20:03.827373Z"}],"euvd":[{"id":"EUVD-2026-110320","description":"Autobahn Python is a WebSocket and WAMP implementation for Python that supports Twisted and asyncio. From 26.7.1 until 26.10.1, PerMessageBrotli.decompress_message_data in compress_brotli.py calls the Brotli decompressor without an output limit and checks maxMessagePayloadSize only after a complete frame has been inflated. An unauthenticated WebSocket client can send a small, highly compressed frame that allocates hundreds of MiB before rejection, causing memory-exhaustion denial of service on servers that enable the opt-in permessage-brotli feature through the compress extra. Deflate and bzip2 already enforce the remaining output budget and are outside this residual vulnerability. This issue is fixed in version 26.10.1.","status":"published","published":"2026-10-26T20:29:22Z","modified":"2026-10-27T14:18:18Z","cvss":[{"version":"3.1","score":5.9,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"medium"}],"updated_at":"2026-11-02T16:59:23.601588Z"}],"ghsa":[{"id":"GHSA-pjh6-c8mg-3x7m","title":"Autobahn Python: permessage-brotli inflates a whole frame before maxMessagePayloadSize is checked (incomplete fix of GHSA-hxp9-w8x3-p566)","description":"### Summary\n\npermessage-brotli inflates each frame fully before checking maxMessagePayloadSize, so one 421-byte frame makes the server allocate about 545 MiB even with a 1 MiB message limit (brotli expands about 1,000,000:1). Any unauthenticated client can exhaust server memory this way on servers that enable permessage-brotli. This bypasses the GHSA-hxp9-w8x3-p566 fix.\n\n### Details\n\nIn 26.7.1 the receive path passes the remaining `maxMessagePayloadSize` budget to `decompress_message_data(..., max_output_len=...)`. deflate and bzip2 stop at that budget. `PerMessageBrotli.decompress_message_data` (`compress_brotli.py`) instead calls `self._decompressor.process(data)` with no limit and compares the length afterwards, so the whole frame is inflated first.\n\nThe code comment and changelog say this is still \"bounded on the wire by `maxFramePayloadSize`\", but brotli reaches about 1,000,000:1 (841 bytes inflate to 1 GiB), so that bound means little. A 421-byte frame against a 1 MiB budget peaks at 545 MiB before the 1009 rejection.\n\nAn autobahn asyncio server on 127.0.0.1 accepting permessage-brotli, with `maxFramePayloadSize=64 KiB` and `maxMessagePayloadSize=1 MiB`, received one small brotli frame from an autobahn client and peaked at 545 MiB (baseline 28 MiB). A few concurrent connections can exhaust memory.\n\nbrotli ≥ 1.2.0 has `Decompressor.process(data, output_buffer_limit=N)`, so the backend can stop at `max_output_len` like deflate and bzip2 (and the extra's floor can be raised to `brotli\u003e=1.2.0`).\n\nTested on autobahn 26.7.1 (latest) with brotli 1.2.0; `compress_brotli.py` on master is unchanged. This affects servers that enable permessage-brotli (opt-in, needs the `compress` extra).\n\n### Proof of concept\n\nHow to run the PoC\n```\npython3 -m venv venv \u0026\u0026 . venv/bin/activate\npip install autobahn==26.7.1 brotli==1.2.0\npython3 poc_autobahn.py\n```\n\n```python\n# PoC: autobahn 26.7.1 permessage-brotli inflates a whole frame before maxMessagePayloadSize is checked.\nimport brotli, resource\nfrom autobahn.websocket.compress import PerMessageBrotli\n\nc = brotli.Compressor()  # build a 256 MiB-of-zeros frame without holding the plaintext\nframe = b\"\".join(c.process(b\"\\0\" * (1 \u003c\u003c 20)) for _ in range(256)) + c.finish()\npmce = PerMessageBrotli(is_server=True, server_no_context_takeover=False, client_no_context_takeover=False)\npmce.start_decompress_message()\nprint(len(frame), \"bytes on the wire; peak RSS before:\", resource.getrusage(resource.RUSAGE_SELF).ru_maxrss \u003e\u003e 10, \"MiB\")\ntry:\n    pmce.decompress_message_data(frame, max_output_len=1 \u003c\u003c 20)  # remaining budget: 1 MiB\nexcept Exception as e:\n    print(type(e).__name__, \"| peak RSS after:\", resource.getrusage(resource.RUSAGE_SELF).ru_maxrss \u003e\u003e 10, \"MiB\")\n```\n\nOutput:\n```\n421 bytes on the wire; peak RSS before: 36 MiB\nPayloadExceededError | peak RSS after: 545 MiB\n```\n\n### Impact\n\nAn unauthenticated WebSocket client can make a server that enabled permessage-brotli allocate hundreds of MB or more per tiny frame, regardless of the configured `maxMessagePayloadSize`. That is the memory-exhaustion DoS GHSA-hxp9-w8x3-p566 was meant to prevent.\n\nCredit goes to Adrian Korwel.","status":"published","published":"2026-10-28T21:10:17Z","modified":"2026-10-28T21:10:18Z","cvss":[{"version":"3.1","score":5.9,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"medium"}],"cwes":["CWE-409","CWE-770"],"updated_at":"2026-11-02T14:41:39.926569Z"}],"nvd":[{"id":"CVE-2026-116579","description":"Autobahn Python is a WebSocket and WAMP implementation for Python that supports Twisted and asyncio. From 26.7.1 until 26.10.1, PerMessageBrotli.decompress_message_data in compress_brotli.py calls the Brotli decompressor without an output limit and checks maxMessagePayloadSize only after a complete frame has been inflated. An unauthenticated WebSocket client can send a small, highly compressed frame that allocates hundreds of MiB before rejection, causing memory-exhaustion denial of service on servers that enable the opt-in permessage-brotli feature through the compress extra. Deflate and bzip2 already enforce the remaining output budget and are outside this residual vulnerability. This issue is fixed in version 26.10.1.","status":"published","published":"2026-10-26T21:18:15.117Z","modified":"2026-10-27T16:03:45.247Z","cvss":[{"version":"3.1","score":5.9,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"medium","assessor":"secondary"}],"cwes":["CWE-409","CWE-770"],"updated_at":"2026-11-02T14:13:03.746397Z"}],"osv":[{"id":"CVE-2026-116579","title":"Autobahn Python: permessage-brotli inflates a whole frame before maxMessagePayloadSize is checked (incomplete fix of GHSA-hxp9-w8x3-p566)","description":"Autobahn Python is a WebSocket and WAMP implementation for Python that supports Twisted and asyncio. From 26.7.1 until 26.10.1, PerMessageBrotli.decompress_message_data in compress_brotli.py calls the Brotli decompressor without an output limit and checks maxMessagePayloadSize only after a complete frame has been inflated. An unauthenticated WebSocket client can send a small, highly compressed frame that allocates hundreds of MiB before rejection, causing memory-exhaustion denial of service on servers that enable the opt-in permessage-brotli feature through the compress extra. Deflate and bzip2 already enforce the remaining output budget and are outside this residual vulnerability. This issue is fixed in version 26.10.1.","status":"published","published":"2026-10-26T20:29:22.906Z","modified":"2026-10-29T02:30:39.264027023Z","cvss":[{"version":"3.1","score":5.9,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"medium"}],"cwes":["CWE-409","CWE-770"],"updated_at":"2026-11-02T15:44:56.675758Z"},{"id":"GHSA-pjh6-c8mg-3x7m","title":"Autobahn Python: permessage-brotli inflates a whole frame before maxMessagePayloadSize is checked (incomplete fix of GHSA-hxp9-w8x3-p566)","description":"### Summary\n\npermessage-brotli inflates each frame fully before checking maxMessagePayloadSize, so one 421-byte frame makes the server allocate about 545 MiB even with a 1 MiB message limit (brotli expands about 1,000,000:1). Any unauthenticated client can exhaust server memory this way on servers that enable permessage-brotli. This bypasses the GHSA-hxp9-w8x3-p566 fix.\n\n### Details\n\nIn 26.7.1 the receive path passes the remaining `maxMessagePayloadSize` budget to `decompress_message_data(..., max_output_len=...)`. deflate and bzip2 stop at that budget. `PerMessageBrotli.decompress_message_data` (`compress_brotli.py`) instead calls `self._decompressor.process(data)` with no limit and compares the length afterwards, so the whole frame is inflated first.\n\nThe code comment and changelog say this is still \"bounded on the wire by `maxFramePayloadSize`\", but brotli reaches about 1,000,000:1 (841 bytes inflate to 1 GiB), so that bound means little. A 421-byte frame against a 1 MiB budget peaks at 545 MiB before the 1009 rejection.\n\nAn autobahn asyncio server on 127.0.0.1 accepting permessage-brotli, with `maxFramePayloadSize=64 KiB` and `maxMessagePayloadSize=1 MiB`, received one small brotli frame from an autobahn client and peaked at 545 MiB (baseline 28 MiB). A few concurrent connections can exhaust memory.\n\nbrotli ≥ 1.2.0 has `Decompressor.process(data, output_buffer_limit=N)`, so the backend can stop at `max_output_len` like deflate and bzip2 (and the extra's floor can be raised to `brotli\u003e=1.2.0`).\n\nTested on autobahn 26.7.1 (latest) with brotli 1.2.0; `compress_brotli.py` on master is unchanged. This affects servers that enable permessage-brotli (opt-in, needs the `compress` extra).\n\n### Proof of concept\n\nHow to run the PoC\n```\npython3 -m venv venv \u0026\u0026 . venv/bin/activate\npip install autobahn==26.7.1 brotli==1.2.0\npython3 poc_autobahn.py\n```\n\n```python\n# PoC: autobahn 26.7.1 permessage-brotli inflates a whole frame before maxMessagePayloadSize is checked.\nimport brotli, resource\nfrom autobahn.websocket.compress import PerMessageBrotli\n\nc = brotli.Compressor()  # build a 256 MiB-of-zeros frame without holding the plaintext\nframe = b\"\".join(c.process(b\"\\0\" * (1 \u003c\u003c 20)) for _ in range(256)) + c.finish()\npmce = PerMessageBrotli(is_server=True, server_no_context_takeover=False, client_no_context_takeover=False)\npmce.start_decompress_message()\nprint(len(frame), \"bytes on the wire; peak RSS before:\", resource.getrusage(resource.RUSAGE_SELF).ru_maxrss \u003e\u003e 10, \"MiB\")\ntry:\n    pmce.decompress_message_data(frame, max_output_len=1 \u003c\u003c 20)  # remaining budget: 1 MiB\nexcept Exception as e:\n    print(type(e).__name__, \"| peak RSS after:\", resource.getrusage(resource.RUSAGE_SELF).ru_maxrss \u003e\u003e 10, \"MiB\")\n```\n\nOutput:\n```\n421 bytes on the wire; peak RSS before: 36 MiB\nPayloadExceededError | peak RSS after: 545 MiB\n```\n\n### Impact\n\nAn unauthenticated WebSocket client can make a server that enabled permessage-brotli allocate hundreds of MB or more per tiny frame, regardless of the configured `maxMessagePayloadSize`. That is the memory-exhaustion DoS GHSA-hxp9-w8x3-p566 was meant to prevent.\n\nCredit goes to Adrian Korwel.","status":"published","published":"2026-10-28T21:10:17Z","modified":"2026-10-28T21:30:06.702115297Z","cvss":[{"version":"3.1","score":5.9,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"medium"}],"cwes":["CWE-409","CWE-770"],"updated_at":"2026-11-02T15:46:53.244788Z"},{"id":"UBUNTU-CVE-2026-116579","description":"Autobahn Python is a WebSocket and WAMP implementation for Python that supports Twisted and asyncio. From 26.7.1 until 26.10.1, PerMessageBrotli.decompress_message_data in compress_brotli.py calls the Brotli decompressor without an output limit and checks maxMessagePayloadSize only after a complete frame has been inflated. An unauthenticated WebSocket client can send a small, highly compressed frame that allocates hundreds of MiB before rejection, causing memory-exhaustion denial of service on servers that enable the opt-in permessage-brotli feature through the compress extra. Deflate and bzip2 already enforce the remaining output budget and are outside this residual vulnerability. This issue is fixed in version 26.10.1.","status":"published","published":"2026-10-26T21:18:00Z","modified":"2026-10-28T20:15:58.318257939Z","cvss":[{"version":"3.1","score":5.9,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"medium"}],"updated_at":"2026-11-02T16:56:00.081948Z"}]}}
