{"id":"EEF-CVE-2026-104634","summary":"beam_mcp: JSON boolean and null tool arguments reach dispatch as strings","details":"## Summary\n\nIncorrect Type Conversion or Cast vulnerability in `BeamMCP.Server` in ScriptKittyOS beam_mcp allows an MCP client's JSON `true`, `false` and `null` tool arguments to reach the host's dispatch function as the strings \"true\", \"false\" and \"nil\". After `BeamMCP.Schema.validate/2` accepted a value as a boolean, `normalize_arguments/2` passed every argument through `to_json_value/1`, whose atom clause converts `true`, `false` and `nil` to strings. A string is truthy in Elixir, so a host that tests a boolean argument, for example `if args.dry_run`, takes the opposite branch for `false`, and a guard such as `confirm: false` reads as set.\n\nThe client controls the argument and could send `true` directly, so the practical impact is limited to hosts whose behaviour on `false` differs from their behaviour on `true`, and to any policy layer in front of the server that permits `false` but refuses `true`. The same normalisation applies to `prompts/get` arguments, which exist from 0.5.0.\n\nThis issue affects beam_mcp: from 0.1.0 before 0.10.1.\n\n## Details\n\n**1. Validation.** `BeamMCP.Schema.check_type/3` accepts a JSON `false` for a `boolean` property because the decoded value is the atom `false`.\n\n**2. Normalisation.** `BeamMCP.Server.normalize_arguments/2` in `lib/beam_mcp/server.ex` maps each declared key to an atom and passes each value through `to_json_value/1`. That function was written to encode host results for the wire, and its clause `when is_atom(value)` converts the value with `Atom.to_string/1`. `true`, `false` and `nil` are atoms, so they become the strings \"true\", \"false\" and \"nil\", at any depth of the argument map.\n\n**3. Dispatch.** The host receives `%{dry_run: \"false\"}`. Any string is truthy in Elixir, so `if args.dry_run` takes the true branch. A host result carrying booleans was stringified the same way on the way out. The fix in 0.10.1 adds a clause that passes booleans and `nil` through unchanged.\n\n## Proof of concept\n\n1. Declare a tool whose `input_schema` has `\"dry_run\": {\"type\": \"boolean\"}`.\n2. Send `tools/call` with `\"arguments\": {\"dry_run\": false}`.\n3. On beam_mcp 0.10.0 the dispatch function receives `%{dry_run: \"false\"}` and `if args.dry_run` evaluates the true branch. On 0.10.1 it receives `%{dry_run: false}`.\n\n## Impact\n\nA host that branches on a boolean argument takes the opposite branch for `false`, so a safety guard such as `confirm: false` or `dry_run: false` is read as set. The client already controls the argument, so the gain over sending `true` is limited to hosts and intermediaries that treat the two values differently.\n\n## Workarounds\n\nIn the host's dispatch function, compare boolean arguments against both forms, for example `args.flag in [true, \"true\"]` and `args.flag in [false, \"false\"]`, and treat the string \"nil\" as `null` where the schema admits null.","aliases":["CVE-2026-104634","GHSA-wv7p-j6qh-3hj4"],"modified":"2026-10-08T13:56:03.266254685Z","published":"2026-10-08T13:41:05.745Z","database_specific":{"cpe_ids":["cpe:2.3:a:scriptkittyos:beam_mcp:*:*:*:*:*:*:*:*"],"cwe_ids":["CWE-704"],"capec_ids":["CAPEC-153"]},"references":[{"type":"ADVISORY","url":"https://github.com/ScriptKittyOS/beam_mcp/security/advisories/GHSA-wv7p-j6qh-3hj4"},{"type":"WEB","url":"https://cna.erlef.org/cves/CVE-2026-104634.html"},{"type":"WEB","url":"https://github.com/ScriptKittyOS/beam_mcp/commit/083838eb8e17fe5f6fcaf761bdbe203110288b0b"},{"type":"FIX","url":"https://github.com/ScriptKittyOS/beam_mcp/commit/289dbdbad641943b29a3b8d1eb36506cc8cec10a"},{"type":"PACKAGE","url":"https://hex.pm/packages/beam_mcp"}],"affected":[{"package":{"name":"beam_mcp","ecosystem":"Hex","purl":"pkg:hex/beam_mcp"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.1.0"},{"fixed":"0.10.1"}]}],"versions":["0.1.0","0.10.0","0.2.0","0.3.0","0.3.1","0.4.0","0.5.0","0.6.0","0.7.0","0.8.0","0.9.0"],"database_specific":{"source":"https://cna.erlef.org/osv/EEF-CVE-2026-104634.json"}},{"ranges":[{"type":"GIT","repo":"https://github.com/ScriptKittyOS/beam_mcp","events":[{"introduced":"083838eb8e17fe5f6fcaf761bdbe203110288b0b"},{"fixed":"289dbdbad641943b29a3b8d1eb36506cc8cec10a"}]}],"versions":["v0.10.0","v0.9.0","v0.8.0","v0.7.0","v0.6.0","v0.5.0","v0.4.0","v0.3.1","v0.3.0","v0.2.0","v0.1.0"],"database_specific":{"source":"https://cna.erlef.org/osv/EEF-CVE-2026-104634.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V4","score":"CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N"}],"credits":[{"name":"Ayla Croft / Script Kitty OS","type":"FINDER"},{"name":"Ayla Croft / Script Kitty OS","type":"REPORTER"},{"name":"Ayla Croft / Script Kitty OS","type":"REMEDIATION_DEVELOPER"},{"name":"Jonatan Männchen / EEF","type":"COORDINATOR"}]}