CVE-2026-44266: Elo Ruby backend has Remote Code Execution via unescaped `#{...}` interpolation in emitted string literals and subtype-constraint labels

Published Nov 3, 2026
·
Updated

Summary

Elo'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.

The 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.

Vulnerable sinks

Two sinks exist in src/compilers/ruby.ts at commit 749af7b:

1. String-literal emitter — lines 180–184. 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.

2. Labelled subtype-constraint branch — lines 405–412. The error message passed to pfail(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.

Attack surfaces

All 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:

| # | Entry point | Threat model | |---|---|---| | 1 | /try playground on elo-lang.org (Ruby target) | 0-click server-side RCE against elo-lang.org infrastructure from a shared PoC URL | | 2 | bin/eloc -t ruby -x on a CI or DevOps host | RCE on any host that passes Elo strings through the CLI | | 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) |

Proof of Concept

String-literal sink:

poc.elo 'RES=#{id 2>&1}'

$ eloc -t ruby -x poc.elo emitted Ruby contains: "RES=#{id 2>&1}" running it returns the output of id(1).

Replacing id 2>&1 with touch /tmp/pwned produces a trivially observable filesystem side effect.

Subtype-constraint label sink:

poc-subtype.elo let X = Int(i | '#{touch /tmp/pwned2}': i > 0) in X(-1)

The predicate fails for -1, causing pfail(p, "#{...}") to interpolate and execute the backtick command at the Ruby layer.

Both flows are automated in the reproduction script submitted with the original report and were verified against Ruby 3.x.

Root cause

The 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.

Other sources

Elo is a purely functional expression language for no-code tools. Prior to 1.0.1, the Ruby backend in src/compilers/ruby.ts embeds attacker-controlled text in Ruby double-quoted strings without escaping #, so Ruby interpolation forms in the string-literal emitter or the labelled subtype-constraint branch become executable Ruby. The affected entry points include the /try playground with the Ruby target, bin/eloc -t ruby -x, and defaultFormats.elo.parse() followed by Ruby emission. A failing labelled subtype constraint evaluates its message, while an ordinary string literal is evaluated when the compiled Ruby runs, allowing Ruby code and shell command execution through backticks. JavaScript, Python, and SQL emission are not affected by this Ruby-specific path. This issue is fixed in version 1.0.1.

— MITRE

Affected Software

2 affected componentsFixes available
npm/@enspirit/elo<=1.0.0
1.0.1
npm/@enspirit/elo<1.0.1
1.0.1

Event History

Nov 3, 2026
CVE Published
via MITRE·05:51 PM
Data Sourced
via MITRE·05:51 PM
DescriptionSeverityWeakness
Advisory Published
via GitHub·05:51 PM
Data Sourced
via GitHub·05:51 PM
DescriptionSeverityWeaknessAffected Software
Data Sourced
via OSV·05:51 PM
Affected Software
Data Sourced
via NVD·06:18 PM
DescriptionSeverityWeakness

Frequently Asked Questions

1

Which deployments are exposed?

Deployments that compile and run Elo programs through the Ruby backend are exposed when the Elo source can contain attacker-controlled content. The issue occurs in generated Ruby at runtime, so environments using only the JavaScript, Python, or SQL targets are not affected by the same source input.

2

What attacker-controlled input should be treated as dangerous?

Review Elo string literals and labels on subtype constraints. A Ruby interpolation sequence such as #{...} in either location can be emitted into a Ruby double-quoted string and evaluated by the generated program.

3

Does exploitation require an authenticated user or user interaction?

The supplied severity vector indicates network reachability, low attack complexity, no privileges required, and no user interaction. In practice, exploitation depends on an attacker being able to get crafted Elo source compiled and executed with the Ruby backend.

4

How can we identify potentially affected code paths?

Inspect Ruby-backend use for compilation of untrusted or externally supplied Elo programs. The vulnerable emitter locations are identified as src/compilers/ruby.ts lines 180–184 for string literals and lines 405–412 for labelled subtype-constraint errors at commit 749af7b.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203