CVE-2026-86696 (GCVE-0-2026-86696)
Vulnerability from cvelistv5
Published
2026-10-22 06:59
Modified
2026-10-30 18:05
Severity ?
VLAI Severity ?
EPSS score ?
CWE
- CWE-770 - Allocation of Resources Without Limits or Throttling
Summary
Allocation of Resources Without Limits or Throttling vulnerability in esaml in dropbox esaml allows an unauthenticated attacker to exhaust the Erlang VM atom table and crash the node via unsigned LogoutResponse messages.
esaml:status_code_map/1 in src/esaml.erl maps any StatusCode value it does not recognize to an atom with list_to_atom/1 on the last colon-separated segment of the URN. esaml_sp:validate_logout_response/2 verifies a signature only when the message carries one, so an unsigned LogoutResponse posted to the single-logout endpoint reaches esaml:decode_logout_response/1 and mints one permanent atom per distinct status value. Atoms are never reclaimed and the VM caps the atom table at about one million entries, so an attacker who posts that many distinct values aborts the node.
This issue affects esaml: from 0.1.0 onward.
References
| URL | Tags | |
|---|---|---|
|
|
||
Impacted products
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-86696",
"options": [
{
"Exploitation": "poc"
},
{
"Automatable": "no"
},
{
"Technical Impact": "partial"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-10-30T18:05:24.637835Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-10-30T18:05:53.388Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"references": [
{
"tags": [
"exploit"
],
"url": "https://cna.erlef.org/cves/CVE-2026-86696.html"
},
{
"tags": [
"exploit"
],
"url": "https://osv.dev/vulnerability/EEF-CVE-2026-86696"
}
],
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"collectionURL": "https://github.com",
"cpes": [
"cpe:2.3:a:handnot2:esaml:*:*:*:*:*:*:*:*"
],
"defaultStatus": "unaffected",
"modules": [
"esaml",
"esaml_sp",
"esaml_cowboy"
],
"packageName": "handnot2/esaml",
"packageURL": "pkg:github/handnot2/esaml",
"product": "esaml",
"programFiles": [
"src/esaml.erl",
"src/esaml_sp.erl",
"src/esaml_cowboy.erl"
],
"programRoutines": [
{
"name": "esaml:status_code_map/1"
},
{
"name": "esaml:decode_logout_response/1"
},
{
"name": "esaml_sp:validate_logout_response/2"
},
{
"name": "esaml_cowboy:validate_logout/2"
}
],
"repo": "https://github.com/handnot2/esaml",
"vendor": "handnot2",
"versions": [
{
"lessThan": "*",
"status": "affected",
"version": "be692b56245071899757afa7ef47e43593d3de96",
"versionType": "git"
}
]
},
{
"collectionURL": "https://github.com",
"cpes": [
"cpe:2.3:a:arekinath:esaml:*:*:*:*:*:*:*:*"
],
"defaultStatus": "unaffected",
"modules": [
"esaml",
"esaml_sp",
"esaml_cowboy"
],
"packageName": "arekinath/esaml",
"packageURL": "pkg:github/arekinath/esaml",
"product": "esaml",
"programFiles": [
"src/esaml.erl",
"src/esaml_sp.erl",
"src/esaml_cowboy.erl"
],
"programRoutines": [
{
"name": "esaml:status_code_map/1"
},
{
"name": "esaml:decode_logout_response/1"
},
{
"name": "esaml_sp:validate_logout_response/2"
},
{
"name": "esaml_cowboy:validate_logout/2"
}
],
"repo": "https://github.com/arekinath/esaml",
"vendor": "arekinath",
"versions": [
{
"lessThan": "*",
"status": "affected",
"version": "be692b56245071899757afa7ef47e43593d3de96",
"versionType": "git"
}
]
},
{
"collectionURL": "https://repo.hex.pm",
"cpes": [
"cpe:2.3:a:dropbox:esaml:*:*:*:*:*:*:*:*"
],
"defaultStatus": "unaffected",
"modules": [
"esaml",
"esaml_sp",
"esaml_cowboy"
],
"packageName": "esaml",
"packageURL": "pkg:hex/esaml",
"product": "esaml",
"programFiles": [
"src/esaml.erl",
"src/esaml_sp.erl",
"src/esaml_cowboy.erl"
],
"programRoutines": [
{
"name": "esaml:status_code_map/1"
},
{
"name": "esaml:decode_logout_response/1"
},
{
"name": "esaml_sp:validate_logout_response/2"
},
{
"name": "esaml_cowboy:validate_logout/2"
}
],
"repo": "https://github.com/dropbox/esaml",
"vendor": "dropbox",
"versions": [
{
"lessThan": "*",
"status": "affected",
"version": "0.1.0",
"versionType": "semver"
}
]
},
{
"collectionURL": "https://github.com",
"cpes": [
"cpe:2.3:a:dropbox:esaml:*:*:*:*:*:*:*:*"
],
"defaultStatus": "unaffected",
"modules": [
"esaml",
"esaml_sp",
"esaml_cowboy"
],
"packageName": "dropbox/esaml",
"packageURL": "pkg:github/dropbox/esaml",
"product": "esaml",
"programFiles": [
"src/esaml.erl",
"src/esaml_sp.erl",
"src/esaml_cowboy.erl"
],
"programRoutines": [
{
"name": "esaml:status_code_map/1"
},
{
"name": "esaml:decode_logout_response/1"
},
{
"name": "esaml_sp:validate_logout_response/2"
},
{
"name": "esaml_cowboy:validate_logout/2"
}
],
"repo": "https://github.com/dropbox/esaml",
"vendor": "dropbox",
"versions": [
{
"lessThan": "*",
"status": "affected",
"version": "be692b56245071899757afa7ef47e43593d3de96",
"versionType": "git"
}
]
}
],
"configurations": [
{
"lang": "en",
"supportingMedia": [
{
"base64": false,
"type": "text/html",
"value": "\u003cp\u003eReachable only where the service provider exposes a single-logout endpoint that hands incoming \u003ccode\u003eLogoutResponse\u003c/code\u003e messages to \u003ccode\u003eesaml_sp:validate_logout_response/2\u003c/code\u003e, directly or through \u003ccode\u003eesaml_cowboy:validate_logout/2\u003c/code\u003e. The consume (ACS) path verifies signatures before decoding and does not reach the status code mapping.\u003c/p\u003e"
},
{
"base64": false,
"type": "text/markdown",
"value": "Reachable only where the service provider exposes a single-logout endpoint that hands incoming `LogoutResponse` messages to `esaml_sp:validate_logout_response/2`, directly or through `esaml_cowboy:validate_logout/2`. The consume (ACS) path verifies signatures before decoding and does not reach the status code mapping."
}
],
"value": "Reachable only where the service provider exposes a single-logout endpoint that hands incoming LogoutResponse messages to esaml_sp:validate_logout_response/2, directly or through esaml_cowboy:validate_logout/2. The consume (ACS) path verifies signatures before decoding and does not reach the status code mapping."
}
],
"cpeApplicability": [
{
"nodes": [
{
"cpeMatch": [
{
"criteria": "cpe:2.3:a:handnot2:esaml:*:*:*:*:*:*:*:*",
"versionStartIncluding": "2.0.0",
"vulnerable": true
},
{
"criteria": "cpe:2.3:a:dropbox:esaml:*:*:*:*:*:*:*:*",
"versionStartIncluding": "0.1.0",
"vulnerable": true
}
],
"negate": false,
"operator": "OR"
}
],
"operator": "AND"
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Quinn Wilton"
},
{
"lang": "en",
"type": "reporter",
"value": "Quinn Wilton"
},
{
"lang": "en",
"type": "coordinator",
"value": "Jonatan M\u00e4nnchen / EEF"
}
],
"dateAssigned": "2026-10-08T14:39:37.000Z",
"descriptions": [
{
"lang": "en",
"supportingMedia": [
{
"base64": false,
"type": "text/html",
"value": "\u003cp\u003eAllocation of Resources Without Limits or Throttling vulnerability in \u003ccode\u003eesaml\u003c/code\u003e in dropbox esaml allows an unauthenticated attacker to exhaust the Erlang VM atom table and crash the node via unsigned \u003ccode\u003eLogoutResponse\u003c/code\u003e messages.\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eesaml:status_code_map/1\u003c/code\u003e in \u003ccode\u003esrc/esaml.erl\u003c/code\u003e maps any \u003ccode\u003eStatusCode\u003c/code\u003e value it does not recognize to an atom with \u003ccode\u003elist_to_atom/1\u003c/code\u003e on the last colon-separated segment of the URN. \u003ccode\u003eesaml_sp:validate_logout_response/2\u003c/code\u003e verifies a signature only when the message carries one, so an unsigned \u003ccode\u003eLogoutResponse\u003c/code\u003e posted to the single-logout endpoint reaches \u003ccode\u003eesaml:decode_logout_response/1\u003c/code\u003e and mints one permanent atom per distinct status value. Atoms are never reclaimed and the VM caps the atom table at about one million entries, so an attacker who posts that many distinct values aborts the node.\u003c/p\u003e\n\u003cp\u003eThis issue affects esaml: from 0.1.0 onward.\u003c/p\u003e"
},
{
"base64": false,
"type": "text/markdown",
"value": "Allocation of Resources Without Limits or Throttling vulnerability in `esaml` in dropbox esaml allows an unauthenticated attacker to exhaust the Erlang VM atom table and crash the node via unsigned `LogoutResponse` messages.\n\n`esaml:status_code_map/1` in `src/esaml.erl` maps any `StatusCode` value it does not recognize to an atom with `list_to_atom/1` on the last colon-separated segment of the URN. `esaml_sp:validate_logout_response/2` verifies a signature only when the message carries one, so an unsigned `LogoutResponse` posted to the single-logout endpoint reaches `esaml:decode_logout_response/1` and mints one permanent atom per distinct status value. Atoms are never reclaimed and the VM caps the atom table at about one million entries, so an attacker who posts that many distinct values aborts the node.\n\nThis issue affects esaml: from 0.1.0 onward."
}
],
"value": "Allocation of Resources Without Limits or Throttling vulnerability in esaml in dropbox esaml allows an unauthenticated attacker to exhaust the Erlang VM atom table and crash the node via unsigned LogoutResponse messages.\n\nesaml:status_code_map/1 in src/esaml.erl maps any StatusCode value it does not recognize to an atom with list_to_atom/1 on the last colon-separated segment of the URN. esaml_sp:validate_logout_response/2 verifies a signature only when the message carries one, so an unsigned LogoutResponse posted to the single-logout endpoint reaches esaml:decode_logout_response/1 and mints one permanent atom per distinct status value. Atoms are never reclaimed and the VM caps the atom table at about one million entries, so an attacker who posts that many distinct values aborts the node.\n\nThis issue affects esaml: from 0.1.0 onward."
}
],
"impacts": [
{
"capecId": "CAPEC-125",
"descriptions": [
{
"lang": "en",
"supportingMedia": [
{
"base64": false,
"type": "text/html",
"value": "\u003cp\u003eAn unauthenticated attacker posts unsigned \u003ccode\u003eLogoutResponse\u003c/code\u003e messages with distinct status code URNs to a service provider\u0027s single-logout endpoint. Each message permanently consumes one atom table entry, and about one million of them abort the Erlang VM, denying service to every user of the service provider.\u003c/p\u003e"
},
{
"base64": false,
"type": "text/markdown",
"value": "An unauthenticated attacker posts unsigned `LogoutResponse` messages with distinct status code URNs to a service provider\u0027s single-logout endpoint. Each message permanently consumes one atom table entry, and about one million of them abort the Erlang VM, denying service to every user of the service provider."
}
],
"value": "An unauthenticated attacker posts unsigned LogoutResponse messages with distinct status code URNs to a service provider\u0027s single-logout endpoint. Each message permanently consumes one atom table entry, and about one million of them abort the Erlang VM, denying service to every user of the service provider."
}
]
}
],
"metrics": [
{
"cvssV4_0": {
"Automatable": "NOT_DEFINED",
"Recovery": "NOT_DEFINED",
"Safety": "NOT_DEFINED",
"attackComplexity": "LOW",
"attackRequirements": "PRESENT",
"attackVector": "NETWORK",
"baseScore": 8.2,
"baseSeverity": "HIGH",
"privilegesRequired": "NONE",
"providerUrgency": "NOT_DEFINED",
"subAvailabilityImpact": "NONE",
"subConfidentialityImpact": "NONE",
"subIntegrityImpact": "NONE",
"userInteraction": "NONE",
"valueDensity": "NOT_DEFINED",
"vectorString": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N",
"version": "4.0",
"vulnAvailabilityImpact": "HIGH",
"vulnConfidentialityImpact": "NONE",
"vulnIntegrityImpact": "NONE",
"vulnerabilityResponseEffort": "NOT_DEFINED"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "GENERAL"
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-770",
"description": "CWE-770 Allocation of Resources Without Limits or Throttling",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-10-22T06:59:07.680Z",
"orgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
"shortName": "EEF"
},
"references": [
{
"name": "EEF CNA record for CVE-2026-86696",
"tags": [
"related",
"third-party-advisory"
],
"url": "https://cna.erlef.org/cves/CVE-2026-86696.html"
},
{
"name": "OSV record EEF-CVE-2026-86696",
"tags": [
"related"
],
"url": "https://osv.dev/vulnerability/EEF-CVE-2026-86696"
},
{
"name": "Introducing commit be692b5 in handnot2/esaml",
"tags": [
"related"
],
"url": "https://github.com/handnot2/esaml/commit/be692b56245071899757afa7ef47e43593d3de96"
},
{
"name": "Introducing commit be692b5 in arekinath/esaml",
"tags": [
"related"
],
"url": "https://github.com/arekinath/esaml/commit/be692b56245071899757afa7ef47e43593d3de96"
},
{
"name": "Introducing commit be692b5 in dropbox/esaml",
"tags": [
"related",
"broken-link"
],
"url": "https://github.com/dropbox/esaml/commit/be692b56245071899757afa7ef47e43593d3de96"
}
],
"source": {
"discovery": "EXTERNAL"
},
"title": "Unbounded atom creation from unsigned LogoutResponse status codes in esaml allows atom table exhaustion",
"x_proofOfConcept": [
{
"lang": "en",
"supportingMedia": [
{
"base64": false,
"type": "text/html",
"value": "\u003col\u003e\n\u003cli\u003eBuild an unsigned \u003ccode\u003esamlp:LogoutResponse\u003c/code\u003e document with \u003ccode\u003eVersion=\"2.0\"\u003c/code\u003e, any \u003ccode\u003eIssueInstant\u003c/code\u003e, and a \u003ccode\u003esamlp:Status/samlp:StatusCode\u003c/code\u003e whose \u003ccode\u003eValue\u003c/code\u003e is a fresh URN such as \u003ccode\u003eurn:x:\u0026lt;unique token\u0026gt;\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eDeflate and base64-encode it, and post it to the service provider\u0027s single-logout endpoint as the \u003ccode\u003eSAMLResponse\u003c/code\u003e form field with \u003ccode\u003eSAMLEncoding\u003c/code\u003e set to the DEFLATE URI.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eesaml_sp:validate_logout_response/2\u003c/code\u003e skips signature verification because none is present, \u003ccode\u003eesaml:decode_logout_response/1\u003c/code\u003e maps the status through \u003ccode\u003estatus_code_map/1\u003c/code\u003e, and the atom table grows by one entry per distinct token. The endpoint answers with an error, but the atom is never reclaimed. Repeat with fresh tokens until the VM aborts.\u003c/li\u003e\n\u003c/ol\u003e"
},
{
"base64": false,
"type": "text/markdown",
"value": "1. Build an unsigned `samlp:LogoutResponse` document with `Version=\"2.0\"`, any `IssueInstant`, and a `samlp:Status/samlp:StatusCode` whose `Value` is a fresh URN such as `urn:x:\u003cunique token\u003e`.\n2. Deflate and base64-encode it, and post it to the service provider\u0027s single-logout endpoint as the `SAMLResponse` form field with `SAMLEncoding` set to the DEFLATE URI.\n3. `esaml_sp:validate_logout_response/2` skips signature verification because none is present, `esaml:decode_logout_response/1` maps the status through `status_code_map/1`, and the atom table grows by one entry per distinct token. The endpoint answers with an error, but the atom is never reclaimed. Repeat with fresh tokens until the VM aborts."
}
],
"value": "* Build an unsigned samlp:LogoutResponse document with Version=\"2.0\", any IssueInstant, and a samlp:Status/samlp:StatusCode whose Value is a fresh URN such as urn:x:\u003cunique token\u003e.\n* Deflate and base64-encode it, and post it to the service provider\u0027s single-logout endpoint as the SAMLResponse form field with SAMLEncoding set to the DEFLATE URI.\n* esaml_sp:validate_logout_response/2 skips signature verification because none is present, esaml:decode_logout_response/1 maps the status through status_code_map/1, and the atom table grows by one entry per distinct token. The endpoint answers with an error, but the atom is never reclaimed. Repeat with fresh tokens until the VM aborts."
}
],
"x_technicalAnalysis": [
{
"lang": "en",
"supportingMedia": [
{
"base64": false,
"type": "text/html",
"value": "\u003cp\u003e\u003cstrong\u003e1. Input.\u003c/strong\u003e The single-logout endpoint in \u003ccode\u003eesaml_cowboy:validate_logout/2\u003c/code\u003e reads the request body, decodes the \u003ccode\u003eSAMLResponse\u003c/code\u003e form field with \u003ccode\u003eesaml_binding:decode_response/2\u003c/code\u003e, and passes a \u003ccode\u003esamlp:LogoutResponse\u003c/code\u003e document to \u003ccode\u003eesaml_sp:validate_logout_response/2\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e2. No signature required.\u003c/strong\u003e \u003ccode\u003evalidate_logout_response/2\u003c/code\u003e looks for a \u003ccode\u003eds:Signature\u003c/code\u003e element and verifies it only when one is present. An unsigned document passes through unchanged to \u003ccode\u003eesaml:decode_logout_response/1\u003c/code\u003e, which requires only the \u003ccode\u003eVersion\u003c/code\u003e and \u003ccode\u003eIssueInstant\u003c/code\u003e attributes before mapping the \u003ccode\u003eStatusCode\u003c/code\u003e value.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e3. Interning.\u003c/strong\u003e \u003ccode\u003eesaml:status_code_map/1\u003c/code\u003e matches six known SAML status URNs to fixed atoms. Any other value starting with \u003ccode\u003eurn:\u003c/code\u003e falls through to a clause that interns the last colon-separated segment with \u003ccode\u003elist_to_atom/1\u003c/code\u003e. The attacker chooses that segment, so each request with a fresh value mints one permanent atom. The VM aborts when the atom table reaches its limit of about one million entries.\u003c/p\u003e"
},
{
"base64": false,
"type": "text/markdown",
"value": "**1. Input.** The single-logout endpoint in `esaml_cowboy:validate_logout/2` reads the request body, decodes the `SAMLResponse` form field with `esaml_binding:decode_response/2`, and passes a `samlp:LogoutResponse` document to `esaml_sp:validate_logout_response/2`.\n\n**2. No signature required.** `validate_logout_response/2` looks for a `ds:Signature` element and verifies it only when one is present. An unsigned document passes through unchanged to `esaml:decode_logout_response/1`, which requires only the `Version` and `IssueInstant` attributes before mapping the `StatusCode` value.\n\n**3. Interning.** `esaml:status_code_map/1` matches six known SAML status URNs to fixed atoms. Any other value starting with `urn:` falls through to a clause that interns the last colon-separated segment with `list_to_atom/1`. The attacker chooses that segment, so each request with a fresh value mints one permanent atom. The VM aborts when the atom table reaches its limit of about one million entries."
}
],
"value": "1. Input. The single-logout endpoint in esaml_cowboy:validate_logout/2 reads the request body, decodes the SAMLResponse form field with esaml_binding:decode_response/2, and passes a samlp:LogoutResponse document to esaml_sp:validate_logout_response/2.\n\n2. No signature required. validate_logout_response/2 looks for a ds:Signature element and verifies it only when one is present. An unsigned document passes through unchanged to esaml:decode_logout_response/1, which requires only the Version and IssueInstant attributes before mapping the StatusCode value.\n\n3. Interning. esaml:status_code_map/1 matches six known SAML status URNs to fixed atoms. Any other value starting with urn: falls through to a clause that interns the last colon-separated segment with list_to_atom/1. The attacker chooses that segment, so each request with a fresh value mints one permanent atom. The VM aborts when the atom table reaches its limit of about one million entries."
}
]
}
},
"cveMetadata": {
"assignerOrgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
"assignerShortName": "EEF",
"cveId": "CVE-2026-86696",
"datePublished": "2026-10-22T06:59:07.680Z",
"dateReserved": "2026-10-08T13:45:02.138Z",
"dateUpdated": "2026-10-30T18:05:53.388Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2",
"vulnerability-lookup:meta": {
"vulnrichment": {
"containers": "{\"adp\": [{\"title\": \"CISA ADP Vulnrichment\", \"metrics\": [{\"other\": {\"type\": \"ssvc\", \"content\": {\"id\": \"CVE-2026-86696\", \"role\": \"CISA Coordinator\", \"options\": [{\"Exploitation\": \"poc\"}, {\"Automatable\": \"no\"}, {\"Technical Impact\": \"partial\"}], \"version\": \"2.0.3\", \"timestamp\": \"2026-10-30T18:05:24.637835Z\"}}}], \"references\": [{\"url\": \"https://cna.erlef.org/cves/CVE-2026-86696.html\", \"tags\": [\"exploit\"]}, {\"url\": \"https://osv.dev/vulnerability/EEF-CVE-2026-86696\", \"tags\": [\"exploit\"]}], \"providerMetadata\": {\"orgId\": \"134c704f-9b21-4f2e-91b3-4a467353bcc0\", \"shortName\": \"CISA-ADP\", \"dateUpdated\": \"2026-10-30T18:05:44.908Z\"}}], \"cna\": {\"title\": \"Unbounded atom creation from unsigned LogoutResponse status codes in esaml allows atom table exhaustion\", \"source\": {\"discovery\": \"EXTERNAL\"}, \"credits\": [{\"lang\": \"en\", \"type\": \"finder\", \"value\": \"Quinn Wilton\"}, {\"lang\": \"en\", \"type\": \"reporter\", \"value\": \"Quinn Wilton\"}, {\"lang\": \"en\", \"type\": \"coordinator\", \"value\": \"Jonatan M\\u00e4nnchen / EEF\"}], \"impacts\": [{\"capecId\": \"CAPEC-125\", \"descriptions\": [{\"lang\": \"en\", \"value\": \"An unauthenticated attacker posts unsigned LogoutResponse messages with distinct status code URNs to a service provider\u0027s single-logout endpoint. Each message permanently consumes one atom table entry, and about one million of them abort the Erlang VM, denying service to every user of the service provider.\", \"supportingMedia\": [{\"type\": \"text/html\", \"value\": \"\u003cp\u003eAn unauthenticated attacker posts unsigned \u003ccode\u003eLogoutResponse\u003c/code\u003e messages with distinct status code URNs to a service provider\u0027s single-logout endpoint. Each message permanently consumes one atom table entry, and about one million of them abort the Erlang VM, denying service to every user of the service provider.\u003c/p\u003e\", \"base64\": false}, {\"type\": \"text/markdown\", \"value\": \"An unauthenticated attacker posts unsigned `LogoutResponse` messages with distinct status code URNs to a service provider\u0027s single-logout endpoint. Each message permanently consumes one atom table entry, and about one million of them abort the Erlang VM, denying service to every user of the service provider.\", \"base64\": false}]}]}], \"metrics\": [{\"format\": \"CVSS\", \"cvssV4_0\": {\"Safety\": \"NOT_DEFINED\", \"version\": \"4.0\", \"Recovery\": \"NOT_DEFINED\", \"baseScore\": 8.2, \"Automatable\": \"NOT_DEFINED\", \"attackVector\": \"NETWORK\", \"baseSeverity\": \"HIGH\", \"valueDensity\": \"NOT_DEFINED\", \"vectorString\": \"CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N\", \"providerUrgency\": \"NOT_DEFINED\", \"userInteraction\": \"NONE\", \"attackComplexity\": \"LOW\", \"attackRequirements\": \"PRESENT\", \"privilegesRequired\": \"NONE\", \"subIntegrityImpact\": \"NONE\", \"vulnIntegrityImpact\": \"NONE\", \"subAvailabilityImpact\": \"NONE\", \"vulnAvailabilityImpact\": \"HIGH\", \"subConfidentialityImpact\": \"NONE\", \"vulnConfidentialityImpact\": \"NONE\", \"vulnerabilityResponseEffort\": \"NOT_DEFINED\"}, \"scenarios\": [{\"lang\": \"en\", \"value\": \"GENERAL\"}]}], \"affected\": [{\"cpes\": [\"cpe:2.3:a:handnot2:esaml:*:*:*:*:*:*:*:*\"], \"repo\": \"https://github.com/handnot2/esaml\", \"vendor\": \"handnot2\", \"modules\": [\"esaml\", \"esaml_sp\", \"esaml_cowboy\"], \"product\": \"esaml\", \"versions\": [{\"status\": \"affected\", \"version\": \"be692b56245071899757afa7ef47e43593d3de96\", \"lessThan\": \"*\", \"versionType\": \"git\"}], \"packageURL\": \"pkg:github/handnot2/esaml\", \"packageName\": \"handnot2/esaml\", \"programFiles\": [\"src/esaml.erl\", \"src/esaml_sp.erl\", \"src/esaml_cowboy.erl\"], \"collectionURL\": \"https://github.com\", \"defaultStatus\": \"unaffected\", \"programRoutines\": [{\"name\": \"esaml:status_code_map/1\"}, {\"name\": \"esaml:decode_logout_response/1\"}, {\"name\": \"esaml_sp:validate_logout_response/2\"}, {\"name\": \"esaml_cowboy:validate_logout/2\"}]}, {\"cpes\": [\"cpe:2.3:a:arekinath:esaml:*:*:*:*:*:*:*:*\"], \"repo\": \"https://github.com/arekinath/esaml\", \"vendor\": \"arekinath\", \"modules\": [\"esaml\", \"esaml_sp\", \"esaml_cowboy\"], \"product\": \"esaml\", \"versions\": [{\"status\": \"affected\", \"version\": \"be692b56245071899757afa7ef47e43593d3de96\", \"lessThan\": \"*\", \"versionType\": \"git\"}], \"packageURL\": \"pkg:github/arekinath/esaml\", \"packageName\": \"arekinath/esaml\", \"programFiles\": [\"src/esaml.erl\", \"src/esaml_sp.erl\", \"src/esaml_cowboy.erl\"], \"collectionURL\": \"https://github.com\", \"defaultStatus\": \"unaffected\", \"programRoutines\": [{\"name\": \"esaml:status_code_map/1\"}, {\"name\": \"esaml:decode_logout_response/1\"}, {\"name\": \"esaml_sp:validate_logout_response/2\"}, {\"name\": \"esaml_cowboy:validate_logout/2\"}]}, {\"cpes\": [\"cpe:2.3:a:dropbox:esaml:*:*:*:*:*:*:*:*\"], \"repo\": \"https://github.com/dropbox/esaml\", \"vendor\": \"dropbox\", \"modules\": [\"esaml\", \"esaml_sp\", \"esaml_cowboy\"], \"product\": \"esaml\", \"versions\": [{\"status\": \"affected\", \"version\": \"0.1.0\", \"lessThan\": \"*\", \"versionType\": \"semver\"}], \"packageURL\": \"pkg:hex/esaml\", \"packageName\": \"esaml\", \"programFiles\": [\"src/esaml.erl\", \"src/esaml_sp.erl\", \"src/esaml_cowboy.erl\"], \"collectionURL\": \"https://repo.hex.pm\", \"defaultStatus\": \"unaffected\", \"programRoutines\": [{\"name\": \"esaml:status_code_map/1\"}, {\"name\": \"esaml:decode_logout_response/1\"}, {\"name\": \"esaml_sp:validate_logout_response/2\"}, {\"name\": \"esaml_cowboy:validate_logout/2\"}]}, {\"cpes\": [\"cpe:2.3:a:dropbox:esaml:*:*:*:*:*:*:*:*\"], \"repo\": \"https://github.com/dropbox/esaml\", \"vendor\": \"dropbox\", \"modules\": [\"esaml\", \"esaml_sp\", \"esaml_cowboy\"], \"product\": \"esaml\", \"versions\": [{\"status\": \"affected\", \"version\": \"be692b56245071899757afa7ef47e43593d3de96\", \"lessThan\": \"*\", \"versionType\": \"git\"}], \"packageURL\": \"pkg:github/dropbox/esaml\", \"packageName\": \"dropbox/esaml\", \"programFiles\": [\"src/esaml.erl\", \"src/esaml_sp.erl\", \"src/esaml_cowboy.erl\"], \"collectionURL\": \"https://github.com\", \"defaultStatus\": \"unaffected\", \"programRoutines\": [{\"name\": \"esaml:status_code_map/1\"}, {\"name\": \"esaml:decode_logout_response/1\"}, {\"name\": \"esaml_sp:validate_logout_response/2\"}, {\"name\": \"esaml_cowboy:validate_logout/2\"}]}], \"references\": [{\"url\": \"https://cna.erlef.org/cves/CVE-2026-86696.html\", \"name\": \"EEF CNA record for CVE-2026-86696\", \"tags\": [\"related\", \"third-party-advisory\"]}, {\"url\": \"https://osv.dev/vulnerability/EEF-CVE-2026-86696\", \"name\": \"OSV record EEF-CVE-2026-86696\", \"tags\": [\"related\"]}, {\"url\": \"https://github.com/handnot2/esaml/commit/be692b56245071899757afa7ef47e43593d3de96\", \"name\": \"Introducing commit be692b5 in handnot2/esaml\", \"tags\": [\"related\"]}, {\"url\": \"https://github.com/arekinath/esaml/commit/be692b56245071899757afa7ef47e43593d3de96\", \"name\": \"Introducing commit be692b5 in arekinath/esaml\", \"tags\": [\"related\"]}, {\"url\": \"https://github.com/dropbox/esaml/commit/be692b56245071899757afa7ef47e43593d3de96\", \"name\": \"Introducing commit be692b5 in dropbox/esaml\", \"tags\": [\"related\", \"broken-link\"]}], \"dateAssigned\": \"2026-10-08T14:39:37.000Z\", \"descriptions\": [{\"lang\": \"en\", \"value\": \"Allocation of Resources Without Limits or Throttling vulnerability in esaml in dropbox esaml allows an unauthenticated attacker to exhaust the Erlang VM atom table and crash the node via unsigned LogoutResponse messages.\\n\\nesaml:status_code_map/1 in src/esaml.erl maps any StatusCode value it does not recognize to an atom with list_to_atom/1 on the last colon-separated segment of the URN. esaml_sp:validate_logout_response/2 verifies a signature only when the message carries one, so an unsigned LogoutResponse posted to the single-logout endpoint reaches esaml:decode_logout_response/1 and mints one permanent atom per distinct status value. Atoms are never reclaimed and the VM caps the atom table at about one million entries, so an attacker who posts that many distinct values aborts the node.\\n\\nThis issue affects esaml: from 0.1.0 onward.\", \"supportingMedia\": [{\"type\": \"text/html\", \"value\": \"\u003cp\u003eAllocation of Resources Without Limits or Throttling vulnerability in \u003ccode\u003eesaml\u003c/code\u003e in dropbox esaml allows an unauthenticated attacker to exhaust the Erlang VM atom table and crash the node via unsigned \u003ccode\u003eLogoutResponse\u003c/code\u003e messages.\u003c/p\u003e\\n\u003cp\u003e\u003ccode\u003eesaml:status_code_map/1\u003c/code\u003e in \u003ccode\u003esrc/esaml.erl\u003c/code\u003e maps any \u003ccode\u003eStatusCode\u003c/code\u003e value it does not recognize to an atom with \u003ccode\u003elist_to_atom/1\u003c/code\u003e on the last colon-separated segment of the URN. \u003ccode\u003eesaml_sp:validate_logout_response/2\u003c/code\u003e verifies a signature only when the message carries one, so an unsigned \u003ccode\u003eLogoutResponse\u003c/code\u003e posted to the single-logout endpoint reaches \u003ccode\u003eesaml:decode_logout_response/1\u003c/code\u003e and mints one permanent atom per distinct status value. Atoms are never reclaimed and the VM caps the atom table at about one million entries, so an attacker who posts that many distinct values aborts the node.\u003c/p\u003e\\n\u003cp\u003eThis issue affects esaml: from 0.1.0 onward.\u003c/p\u003e\", \"base64\": false}, {\"type\": \"text/markdown\", \"value\": \"Allocation of Resources Without Limits or Throttling vulnerability in `esaml` in dropbox esaml allows an unauthenticated attacker to exhaust the Erlang VM atom table and crash the node via unsigned `LogoutResponse` messages.\\n\\n`esaml:status_code_map/1` in `src/esaml.erl` maps any `StatusCode` value it does not recognize to an atom with `list_to_atom/1` on the last colon-separated segment of the URN. `esaml_sp:validate_logout_response/2` verifies a signature only when the message carries one, so an unsigned `LogoutResponse` posted to the single-logout endpoint reaches `esaml:decode_logout_response/1` and mints one permanent atom per distinct status value. Atoms are never reclaimed and the VM caps the atom table at about one million entries, so an attacker who posts that many distinct values aborts the node.\\n\\nThis issue affects esaml: from 0.1.0 onward.\", \"base64\": false}]}], \"problemTypes\": [{\"descriptions\": [{\"lang\": \"en\", \"type\": \"CWE\", \"cweId\": \"CWE-770\", \"description\": \"CWE-770 Allocation of Resources Without Limits or Throttling\"}]}], \"configurations\": [{\"lang\": \"en\", \"value\": \"Reachable only where the service provider exposes a single-logout endpoint that hands incoming LogoutResponse messages to esaml_sp:validate_logout_response/2, directly or through esaml_cowboy:validate_logout/2. The consume (ACS) path verifies signatures before decoding and does not reach the status code mapping.\", \"supportingMedia\": [{\"type\": \"text/html\", \"value\": \"\u003cp\u003eReachable only where the service provider exposes a single-logout endpoint that hands incoming \u003ccode\u003eLogoutResponse\u003c/code\u003e messages to \u003ccode\u003eesaml_sp:validate_logout_response/2\u003c/code\u003e, directly or through \u003ccode\u003eesaml_cowboy:validate_logout/2\u003c/code\u003e. The consume (ACS) path verifies signatures before decoding and does not reach the status code mapping.\u003c/p\u003e\", \"base64\": false}, {\"type\": \"text/markdown\", \"value\": \"Reachable only where the service provider exposes a single-logout endpoint that hands incoming `LogoutResponse` messages to `esaml_sp:validate_logout_response/2`, directly or through `esaml_cowboy:validate_logout/2`. The consume (ACS) path verifies signatures before decoding and does not reach the status code mapping.\", \"base64\": false}]}], \"cpeApplicability\": [{\"nodes\": [{\"negate\": false, \"cpeMatch\": [{\"criteria\": \"cpe:2.3:a:handnot2:esaml:*:*:*:*:*:*:*:*\", \"vulnerable\": true, \"versionStartIncluding\": \"2.0.0\"}, {\"criteria\": \"cpe:2.3:a:dropbox:esaml:*:*:*:*:*:*:*:*\", \"vulnerable\": true, \"versionStartIncluding\": \"0.1.0\"}], \"operator\": \"OR\"}], \"operator\": \"AND\"}], \"providerMetadata\": {\"orgId\": \"6b3ad84c-e1a6-4bf7-a703-f496b71e49db\", \"shortName\": \"EEF\", \"dateUpdated\": \"2026-10-22T06:59:07.680Z\"}, \"x_proofOfConcept\": [{\"lang\": \"en\", \"value\": \"* Build an unsigned samlp:LogoutResponse document with Version=\\\"2.0\\\", any IssueInstant, and a samlp:Status/samlp:StatusCode whose Value is a fresh URN such as urn:x:\u003cunique token\u003e.\\n* Deflate and base64-encode it, and post it to the service provider\u0027s single-logout endpoint as the SAMLResponse form field with SAMLEncoding set to the DEFLATE URI.\\n* esaml_sp:validate_logout_response/2 skips signature verification because none is present, esaml:decode_logout_response/1 maps the status through status_code_map/1, and the atom table grows by one entry per distinct token. The endpoint answers with an error, but the atom is never reclaimed. Repeat with fresh tokens until the VM aborts.\", \"supportingMedia\": [{\"type\": \"text/html\", \"value\": \"\u003col\u003e\\n\u003cli\u003eBuild an unsigned \u003ccode\u003esamlp:LogoutResponse\u003c/code\u003e document with \u003ccode\u003eVersion=\\\"2.0\\\"\u003c/code\u003e, any \u003ccode\u003eIssueInstant\u003c/code\u003e, and a \u003ccode\u003esamlp:Status/samlp:StatusCode\u003c/code\u003e whose \u003ccode\u003eValue\u003c/code\u003e is a fresh URN such as \u003ccode\u003eurn:x:\u0026lt;unique token\u0026gt;\u003c/code\u003e.\u003c/li\u003e\\n\u003cli\u003eDeflate and base64-encode it, and post it to the service provider\u0027s single-logout endpoint as the \u003ccode\u003eSAMLResponse\u003c/code\u003e form field with \u003ccode\u003eSAMLEncoding\u003c/code\u003e set to the DEFLATE URI.\u003c/li\u003e\\n\u003cli\u003e\u003ccode\u003eesaml_sp:validate_logout_response/2\u003c/code\u003e skips signature verification because none is present, \u003ccode\u003eesaml:decode_logout_response/1\u003c/code\u003e maps the status through \u003ccode\u003estatus_code_map/1\u003c/code\u003e, and the atom table grows by one entry per distinct token. The endpoint answers with an error, but the atom is never reclaimed. Repeat with fresh tokens until the VM aborts.\u003c/li\u003e\\n\u003c/ol\u003e\", \"base64\": false}, {\"type\": \"text/markdown\", \"value\": \"1. Build an unsigned `samlp:LogoutResponse` document with `Version=\\\"2.0\\\"`, any `IssueInstant`, and a `samlp:Status/samlp:StatusCode` whose `Value` is a fresh URN such as `urn:x:\u003cunique token\u003e`.\\n2. Deflate and base64-encode it, and post it to the service provider\u0027s single-logout endpoint as the `SAMLResponse` form field with `SAMLEncoding` set to the DEFLATE URI.\\n3. `esaml_sp:validate_logout_response/2` skips signature verification because none is present, `esaml:decode_logout_response/1` maps the status through `status_code_map/1`, and the atom table grows by one entry per distinct token. The endpoint answers with an error, but the atom is never reclaimed. Repeat with fresh tokens until the VM aborts.\", \"base64\": false}]}], \"x_technicalAnalysis\": [{\"lang\": \"en\", \"value\": \"1. Input. The single-logout endpoint in esaml_cowboy:validate_logout/2 reads the request body, decodes the SAMLResponse form field with esaml_binding:decode_response/2, and passes a samlp:LogoutResponse document to esaml_sp:validate_logout_response/2.\\n\\n2. No signature required. validate_logout_response/2 looks for a ds:Signature element and verifies it only when one is present. An unsigned document passes through unchanged to esaml:decode_logout_response/1, which requires only the Version and IssueInstant attributes before mapping the StatusCode value.\\n\\n3. Interning. esaml:status_code_map/1 matches six known SAML status URNs to fixed atoms. Any other value starting with urn: falls through to a clause that interns the last colon-separated segment with list_to_atom/1. The attacker chooses that segment, so each request with a fresh value mints one permanent atom. The VM aborts when the atom table reaches its limit of about one million entries.\", \"supportingMedia\": [{\"type\": \"text/html\", \"value\": \"\u003cp\u003e\u003cstrong\u003e1. Input.\u003c/strong\u003e The single-logout endpoint in \u003ccode\u003eesaml_cowboy:validate_logout/2\u003c/code\u003e reads the request body, decodes the \u003ccode\u003eSAMLResponse\u003c/code\u003e form field with \u003ccode\u003eesaml_binding:decode_response/2\u003c/code\u003e, and passes a \u003ccode\u003esamlp:LogoutResponse\u003c/code\u003e document to \u003ccode\u003eesaml_sp:validate_logout_response/2\u003c/code\u003e.\u003c/p\u003e\\n\u003cp\u003e\u003cstrong\u003e2. No signature required.\u003c/strong\u003e \u003ccode\u003evalidate_logout_response/2\u003c/code\u003e looks for a \u003ccode\u003eds:Signature\u003c/code\u003e element and verifies it only when one is present. An unsigned document passes through unchanged to \u003ccode\u003eesaml:decode_logout_response/1\u003c/code\u003e, which requires only the \u003ccode\u003eVersion\u003c/code\u003e and \u003ccode\u003eIssueInstant\u003c/code\u003e attributes before mapping the \u003ccode\u003eStatusCode\u003c/code\u003e value.\u003c/p\u003e\\n\u003cp\u003e\u003cstrong\u003e3. Interning.\u003c/strong\u003e \u003ccode\u003eesaml:status_code_map/1\u003c/code\u003e matches six known SAML status URNs to fixed atoms. Any other value starting with \u003ccode\u003eurn:\u003c/code\u003e falls through to a clause that interns the last colon-separated segment with \u003ccode\u003elist_to_atom/1\u003c/code\u003e. The attacker chooses that segment, so each request with a fresh value mints one permanent atom. The VM aborts when the atom table reaches its limit of about one million entries.\u003c/p\u003e\", \"base64\": false}, {\"type\": \"text/markdown\", \"value\": \"**1. Input.** The single-logout endpoint in `esaml_cowboy:validate_logout/2` reads the request body, decodes the `SAMLResponse` form field with `esaml_binding:decode_response/2`, and passes a `samlp:LogoutResponse` document to `esaml_sp:validate_logout_response/2`.\\n\\n**2. No signature required.** `validate_logout_response/2` looks for a `ds:Signature` element and verifies it only when one is present. An unsigned document passes through unchanged to `esaml:decode_logout_response/1`, which requires only the `Version` and `IssueInstant` attributes before mapping the `StatusCode` value.\\n\\n**3. Interning.** `esaml:status_code_map/1` matches six known SAML status URNs to fixed atoms. Any other value starting with `urn:` falls through to a clause that interns the last colon-separated segment with `list_to_atom/1`. The attacker chooses that segment, so each request with a fresh value mints one permanent atom. The VM aborts when the atom table reaches its limit of about one million entries.\", \"base64\": false}]}]}}",
"cveMetadata": "{\"cveId\": \"CVE-2026-86696\", \"state\": \"PUBLISHED\", \"dateUpdated\": \"2026-10-30T18:05:53.388Z\", \"dateReserved\": \"2026-10-08T13:45:02.138Z\", \"assignerOrgId\": \"6b3ad84c-e1a6-4bf7-a703-f496b71e49db\", \"datePublished\": \"2026-10-22T06:59:07.680Z\", \"assignerShortName\": \"EEF\"}",
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
}
}
Loading…
Loading…
Sightings
| Author | Source | Type | Date |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or seen somewhere by the user.
- Confirmed: The vulnerability is confirmed from an analyst perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: This vulnerability was exploited and seen by the user reporting the sighting.
- Patched: This vulnerability was successfully patched by the user reporting the sighting.
- Not exploited: This vulnerability was not exploited or seen by the user reporting the sighting.
- Not confirmed: The user expresses doubt about the veracity of the vulnerability.
- Not patched: This vulnerability was not successfully patched by the user reporting the sighting.
Loading…
Loading…