{"id":"CVE-2026-53423","aliases":["GHSA-43hj-fxwj-49qw"],"title":"membrane_mp4_plugin has an unauthenticated denial-of-service via BEAM atom table exhaustion","summary":"membrane_mp4_plugin has an unauthenticated denial-of-service via BEAM atom table exhaustion","severity":"medium","cwe":["CWE-770"],"vendor":"membrane_mp4_plugin","product":"membrane_mp4_plugin","ecosystem":"erlang","affected":["membrane_mp4_plugin < 0.36.7"],"patched":["membrane_mp4_plugin 0.36.7"],"published":"2026-08-18","updated":"2026-08-18","source":"GHSA","sourceUrl":"https://github.com/advisories/GHSA-43hj-fxwj-49qw","references":[{"url":"https://github.com/membraneframework/membrane_mp4_plugin/security/advisories/GHSA-43hj-fxwj-49qw"},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-53423"},{"url":"https://github.com/membraneframework/membrane_mp4_plugin/commit/56373d1ddc86968e55fbde795c14eeba24357b57"},{"url":"https://cna.erlef.org/cves/CVE-2026-53423.html"},{"url":"https://osv.dev/vulnerability/EEF-CVE-2026-53423"},{"url":"https://github.com/advisories/GHSA-43hj-fxwj-49qw"}],"tags":["ghsa","erlang"],"epss":0.00127,"epssPercentile":0.02686,"ingestedAt":"2026-08-18T20:22:15.594Z","slug":"CVE-2026-53423","body":"## Overview\n\n### Summary\n\n`membrane_mp4_plugin` interns every 4-byte MP4 box name as a BEAM atom while parsing container headers, with no validation against an allow-list. Any code path that calls `Membrane.MP4.Container.parse/1` (or the bang variant) on attacker-controlled MP4 bytes can be made to exhaust the BEAM atom table, which is uncapped at the source but bounded by the runtime ceiling (around 1,048,576 atoms) and never garbage-collected. Once the ceiling is hit, the entire BEAM node aborts.\n\n### Details\n\nThe MP4 container parser walks the input stream box-by-box. For each box, `Membrane.MP4.Container.Header.parse/1` in `lib/membrane_mp4/container/header.ex` extracts the 4-byte name field and delegates to the private helper `parse_box_name/1`, which trims trailing spaces and passes the bytes through `String.to_atom/1`. Because `String.to_atom/1` creates a new atom unconditionally, every distinct attacker-chosen 4-byte sequence becomes a permanent allocation in the global atom table. Atoms are not subject to garbage collection, so unique names accumulate for the lifetime of the node.\n\nThe fix replaces the unsafe interning with `String.to_existing_atom/1` and treats unknown names as the `:unknown` atom downstream (with related plumbing in `parse_helper.ex`, `serialize_helper.ex`, and the ISOM/CMAF demuxer engines so the new error variant flows through cleanly).\n\n### PoC\n\n1. Generate an MP4-shaped payload of roughly 1.1 million minimal box headers, each 8 bytes long (4-byte size of 8, followed by a unique 4-byte ASCII name produced by enumerating combinations in the printable range).\n2. Concatenate them into a single binary (~8 MB total).\n3. Call `Membrane.MP4.Container.parse!/1` on the binary inside any process running under the target BEAM node.\n4. The node aborts once the atom table ceiling is reached.\n\n### Impact\n\nAn attacker who can get a single crafted MP4 file in front of any system that demuxes user-supplied media with `membrane_mp4_plugin` can crash the entire BEAM node hosting that pipeline, taking down every Erlang/Elixir application sharing the runtime. No authentication, network position, or user interaction is required beyond delivering the file to whatever processing path eventually calls the parser.\n\n### References\n\n* Introduction commit: https://github.com/membraneframework/membrane_mp4_plugin/commit/ae4bf04c393aa1562f3df3d33e20bc5cb8130de2\n* Patch commit: https://github.com/membraneframework/membrane_mp4_plugin/commit/56373d1ddc86968e55fbde795c14eeba24357b57\n\n## Affected packages\n\n- `membrane_mp4_plugin < 0.36.7`\n\n## Remediation\n\nUpgrade to a patched release:\n\n- `membrane_mp4_plugin 0.36.7`","depth":"sunlit","depthScore":28,"depthScoreParts":{"impact":27.5,"likelihood":0,"exploitation":0,"ransomware":0},"changes":[]}