{"id":"GHSA-7w38-ggh5-v542","summary":"Elo Ruby backend has Remote Code Execution via unescaped `#{...}` interpolation in emitted string literals and subtype-constraint labels","details":"### Summary\n\nElo's Ruby backend emits attacker-controlled text into Ruby double-quoted strings without escaping the `#` character. Because `#` begins Ruby's interpolation sequences — `#{expr}`, `#@ivar`, `#@@cvar`, `#$gvar` — and any expression wrapped in `#{...}` may use backticks for shell execution, an Elo program that contains a crafted string literal or a labelled subtype constraint compiles to Ruby that evaluates attacker-chosen Ruby, and through backticks runs attacker-chosen shell commands, at runtime.\n\nThe same Elo source compiled to JavaScript, Python, or SQL is benign, so the bug also breaks the cross-target portability guarantee the rest of the compiler honours.\n\n### Vulnerable sinks\n\nTwo sinks exist in `src/compilers/ruby.ts` at commit `749af7b`:\n\n1. **String-literal emitter — lines 180–184.**\n   The emitter escapes backslash, double quote, and control characters, but not `#`. Any `#{...}` sequence in an Elo string literal flows straight into the emitted Ruby source.\n\n2. **Labelled subtype-constraint branch — lines 405–412.**\n   The error message passed to `p_fail(p, \"...\")` is wrapped in a Ruby double-quoted string with no escape pass at all. Because the parser at `src/parser.ts:1339–1348` accepts single-quoted Elo strings as constraint labels, a label such as `'#{` `` `id` `` `}'` flows unchanged into the emitted Ruby.\n\n### Attack surfaces\n\nAll three surfaces share the same root cause (the missing `#` escape in the Ruby double-quoted-string emission path) and are addressed by the same patch:\n\n| # | Entry point | Threat model |\n|---|---|---|\n| 1 | `/try` playground on elo-lang.org (Ruby target) | 0-click server-side RCE against elo-lang.org infrastructure from a shared PoC URL |\n| 2 | `bin/eloc -t ruby -x` on a CI or DevOps host | RCE on any host that passes Elo strings through the CLI |\n| 3 | Library API — `defaultFormats.elo.parse()` with a Ruby emission step | Ruby RCE for any downstream integrator using Elo as a rule engine, configuration DSL, or form builder DSL (the primary documented use cases) |\n\n### Proof of Concept\n\n**String-literal sink:**\n\n```\n# poc.elo\n'RES=#{`id 2\u003e&1`}'\n```\n\n```\n$ eloc -t ruby -x poc.elo\n# emitted Ruby contains:  \"RES=#{`id 2\u003e&1`}\"\n# running it returns the output of id(1).\n```\n\nReplacing `` `id 2\u003e&1` `` with `` `touch /tmp/pwned` `` produces a trivially observable filesystem side effect.\n\n**Subtype-constraint label sink:**\n\n```\n# poc-subtype.elo\nlet X = Int(i | '#{`touch /tmp/pwned2`}': i \u003e 0) in X(-1)\n```\n\nThe predicate fails for `-1`, causing `p_fail(p, \"#{...}\")` to interpolate and execute the backtick command at the Ruby layer.\n\nBoth flows are automated in the reproduction script submitted with the original report and were verified against Ruby 3.x.\n\n### Root cause\n\nThe Ruby-emitter's double-quoted-string escape routine omitted `#` from its character set, and one emission path (the subtype-constraint label branch) performed no escape pass at all.","aliases":["CVE-2026-44266"],"modified":"2026-11-03T18:02:25.930696566Z","published":"2026-11-03T17:51:30Z","database_specific":{"github_reviewed":true,"github_reviewed_at":"2026-11-03T17:51:30Z","nvd_published_at":null,"cwe_ids":["CWE-116","CWE-1336","CWE-94"],"severity":"CRITICAL"},"references":[{"type":"WEB","url":"https://github.com/enspirit/elo/security/advisories/GHSA-7w38-ggh5-v542"},{"type":"WEB","url":"https://github.com/enspirit/elo/commit/51b869963fbe445c18328714a7ccfbd76b21ba38"},{"type":"WEB","url":"https://github.com/enspirit/elo/commit/d2a89a8db76a244eb740687524a7e8529b7554b5"},{"type":"PACKAGE","url":"https://github.com/enspirit/elo"}],"affected":[{"package":{"name":"@enspirit/elo","ecosystem":"npm","purl":"pkg:npm/%40enspirit/elo"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"1.0.1"}]}],"database_specific":{"last_known_affected_version_range":"\u003c= 1.0.0","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/11/GHSA-7w38-ggh5-v542/GHSA-7w38-ggh5-v542.json"}}],"schema_version":"1.9.2","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"}]}