CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-44266

CVE-2026-44266: Remote Code Execution in @enspirit/elo Ruby Compiler Backend via Unescaped String Interpolation

Alon Barad
Alon Barad
Software Engineer

Nov 3, 2026·10 min read·2 visits

Executive Summary (TL;DR)

The @enspirit/elo Ruby compiler backend fails to escape '#' characters in double-quoted string literals and subtype constraint failure messages, enabling arbitrary Ruby code and shell command execution via #{...} string interpolation.

CVE-2026-44266 (GHSA-7w38-ggh5-v542) is a code injection vulnerability in @enspirit/elo prior to version 1.0.1. The Ruby target compiler fails to escape the hash character (#) when emitting double-quoted Ruby string literals and subtype constraint failure labels. An attacker who supplies crafted Elo expressions to an application compiling and executing Ruby output achieves arbitrary code execution.

Vulnerability Overview

@enspirit/elo is a functional expression language designed for no-code tools, domain-specific language (DSL) integrations, and rule engines. Rather than using a dedicated virtual machine, Elo operates as a source-to-source compiler that translates an intermediate representation (IR) of an expression into target source code for JavaScript, Python, PostgreSQL SQL, or Ruby. Applications typically ingest user-defined Elo expressions, compile them into the host language, and evaluate the generated code at runtime.

CVE-2026-44266 (also tracked as GHSA-7w38-ggh5-v542) is a code injection vulnerability classified under CWE-94 (Improper Control of Generation of Code) and CWE-116 (Improper Encoding or Escaping of Output). The flaw exists exclusively within Elo's Ruby backend compiler (src/compilers/ruby.ts) in versions prior to 1.0.1. When the compiler translates Elo string literals or subtype constraint error labels into Ruby source code, it wraps the user-controlled text in Ruby double-quoted string literals ("...") without escaping the # character.

In the Ruby programming language, double-quoted strings evaluate embedded expressions prefixed with #, specifically #{...} for arbitrary expression interpolation, as well as #@ivar, #@@cvar, and #$gvar for instance, class, and global variable access. Because the compiler leaves these sequences intact, untrusted data inside an Elo string literal crosses the boundary from passive data into active Ruby code during evaluation.

The attack surface spans three primary deployment models: interactive web playgrounds that compile and evaluate expressions server-side, command-line workflows invoking the compiler with the execution flag (bin/eloc -t ruby -x), and downstream Ruby applications embedding Elo to evaluate user-supplied business logic or validation rules. In any environment where compiled Ruby output is executed, an attacker can embed backtick shell expressions inside an interpolation block to achieve arbitrary command execution under the privileges of the Ruby runtime process.

Root Cause Analysis

The root cause of CVE-2026-44266 is an incomplete output encoding routine in the Ruby code generator (src/compilers/ruby.ts) combined with a secondary code generation path that omits output encoding entirely. When constructing a source-to-source compiler, emitting string literals into the target language requires neutralizing all characters that hold syntactic meaning within the target string delimiter.

In Ruby, single-quoted strings ('...') treat almost all characters literally, recognizing only \\ and \' as escape sequences. Double-quoted strings ("..."), however, support both comprehensive backslash escape sequences (\n, \t, \r, \", \\) and runtime string interpolation triggered by the # symbol. The Elo Ruby compiler selected double-quoted strings as its emission target to support standard control character escaping (\n, \t, \r), but failed to account for Ruby's interpolation mechanics.

The first vulnerable sink is the string_literal handler within the emitRuby function (src/compilers/ruby.ts, lines 180–184). The compiler chains five .replace() calls to sanitize backslashes, double quotes, newlines, tabs, and carriage returns. Because # is not replaced with \#, any # character followed by {, @, or $ remains active when wrapped in double quotes.

The second vulnerable sink resides in the emitTypeExprParser function (src/compilers/ruby.ts, lines 405–412), which compiles type definitions containing subtype constraints and custom failure labels. When a constraint includes a user-defined label (c.label), the compiler formats it into an errorMsg string and interpolates that variable directly into a generated Ruby statement: return p_fail(p, "${errorMsg}") unless (${conditionCode});. This branch applied zero escaping to c.label, allowing both unescaped # interpolation sequences and raw double quotes to break out of the string context when a subtype constraint fails at runtime.

Code Analysis

Prior to version 1.0.1, the Ruby compiler handled string literals and subtype constraint labels separately in src/compilers/ruby.ts. In emitRuby, the string_literal case sanitized control characters and quotes inline, while emitTypeExprParser embedded constraint labels directly into the output template without sanitization.

// Vulnerable code in src/compilers/ruby.ts (prior to 1.0.1)
 
// Sink 1: String literal emitter (lines 177-184)
case 'string_literal': {
  // Ruby double-quoted strings: escape backslash, double quote, and control chars
  // VULNERABILITY: '#' is not escaped, allowing #{...} interpolation in Ruby
  const escaped = ir.value
    .replace(/\\/g, '\\\\')
    .replace(/"/g, '\\"')
    .replace(/\n/g, '\\n')
    .replace(/\t/g, '\\t')
    .replace(/\r/g, '\\r');
  return `"${escaped}"`;
}
 
// Sink 2: Subtype-constraint label emitter in emitTypeExprParser (lines 408-412)
const errorMsg = c.label
  ? (c.label.includes(' ') ? c.label : `constraint '${c.label}' failed`)
  : 'constraint failed';
// VULNERABILITY: errorMsg contains raw user input from c.label with zero escaping
return `return p_fail(p, "${errorMsg}") unless (${conditionCode});`;

Commit 51b869963fbe445c18328714a7ccfbd76b21ba38 resolves both vulnerabilities by introducing a centralized helper function, escapeRubyDQ, and routing both code generation paths through it:

--- a/src/compilers/ruby.ts
+++ b/src/compilers/ruby.ts
@@ -150,6 +150,22 @@ function emitRubyWithHelpers(ir: IRExpr, options: EmitOptions): EmitResult {
   return { code, requiredHelpers };
 }
 
+/**
+ * Escape a raw string for embedding inside a Ruby double-quoted string literal.
+ * In particular, `#` must be escaped so that `#{...}`, `#@ivar`, `#@@cvar` and
+ * `#$gvar` cannot trigger Ruby string interpolation — otherwise attacker-controlled
+ * text (string literals, constraint labels, etc.) becomes executable code.
+ */
+function escapeRubyDQ(s: string): string {
+  return s
+    .replace(/\\/g, '\\\\')
+    .replace(/#/g, '\\#')
+    .replace(/"/g, '\\"')
+    .replace(/\n/g, '\\n')
+    .replace(/\t/g, '\\t')
+    .replace(/\r/g, '\\r');
+}
+
 /**
  * Emit Ruby code from IR
  */
@@ -177,11 +193,8 @@ function emitRuby(ir: IRExpr, requiredHelpers?: Set<string>, options?: EmitOptio
     case 'null_literal':
       return 'nil';
 
-    case 'string_literal': {
-      // Ruby double-quoted strings: escape backslash, double quote, and control chars
-      const escaped = ir.value.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n').replace(/\t/g, '\\t').replace(/\r/g, '\\r');
-      return `"${escaped}"`;
-    }
+    case 'string_literal':
+      return `"${escapeRubyDQ(ir.value)}"`;
 
     case 'date_literal':
       return `Date.parse(${JSON.stringify(ir.value)})`;
@@ -408,7 +421,9 @@ function emitTypeExprParser(
         const errorMsg = c.label
           ? (c.label.includes(' ') ? c.label : `constraint '${c.label}' failed`)
           : 'constraint failed';
-        return `return p_fail(p, "${errorMsg}") unless (${conditionCode});`;
+        // Escape for safe embedding in a Ruby double-quoted string: user-controlled
+        // labels (e.g. `Int(i | 'any text': ...)`) must not trigger `#{...}` interpolation.
+        return `return p_fail(p, "${escapeRubyDQ(errorMsg)}") unless (${conditionCode});`;
       }).join(' ');
 
       return `->(v, p) { _r = (${baseParser}).call(v, p); return _r unless _r[:success]; ${varName} = _r[:value]; ${constraintChecks} _r }`;

The ordering of replacement operations inside escapeRubyDQ is critical to the soundness of the patch. By escaping literal backslashes first (.replace(/\\/g, '\\\\')) before escaping # to \# and " to \", the function prevents an attacker from supplying a payload such as \#{...}. If # were escaped prior to \, \#{...} would first become \\#{...} and then \\\\#{...}, leaving an even number of backslashes (escaped literal backslashes) followed by an unescaped # symbol.

> [!NOTE] > In emitTypeExprParser, applying escapeRubyDQ(errorMsg) also remedies an unescaped double-quote injection bug in c.label, which previously allowed breaking out of the p_fail string argument directly without relying on # interpolation.

Exploitation

Exploiting CVE-2026-44266 requires no authentication or complex state manipulation if an attacker can submit an Elo expression that is subsequently compiled to Ruby and evaluated. Because Elo string literals are enclosed in single quotes ('...'), an attacker can write Ruby double-quote interpolation syntax (#{...}) inside an Elo string without triggering any syntax errors in the Elo parser itself.

Vector 1: Direct String Literal Interpolation

The simplest exploitation path uses a standalone Elo string literal containing a Ruby interpolation block with backtick command execution:

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

When compiled using the Elo CLI (eloc -t ruby -x poc.elo) or an application integration, the compiler emits the following Ruby code:

"RES=#{`id 2>&1`}"

When the Ruby interpreter evaluates this expression, it executes id 2>&1 in a subshell and substitutes the standard output into the resulting string, returning the user and group identifiers of the host process directly to the caller.

Vector 2: Subtype-Constraint Label Injection

If an application restricts top-level return types or filters direct string literals, an attacker can trigger the secondary sink in emitTypeExprParser by defining a constrained subtype with a malicious failure label and immediately passing a value that violates the constraint:

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

During compilation, emitTypeExprParser constructs a lambda parser for type X (Int where i > 0) and embeds the failure label into the p_fail call:

return p_fail(p, "constraint '#{`touch /tmp/pwned2`}' failed") unless ((i > 0));

Because the expression invokes X(-1), the runtime check i > 0 evaluates to false. The unless condition triggers the p_fail return branch, causing Ruby to evaluate the double-quoted error message string and execute touch /tmp/pwned2.

Impact Assessment

CVE-2026-44266 carries a CVSS v3.1 base score of 9.8 (Critical) with the vector CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H. The network attack vector (AV:N), low attack complexity (AC:L), and absence of required privileges (PR:N) or user interaction (UI:N) reflect deployments where Elo expressions are submitted via web APIs, rule configuration interfaces, or interactive playgrounds.

Successful exploitation bridges the gap between a sandboxed functional expression language and full operating system command execution. Elo is specifically designed to be a safe, side-effect-free expression language for evaluating untrusted user rules. By injecting arbitrary Ruby code into the compiled output, an attacker bypasses all expression language restrictions and gains full access to the Ruby runtime (Kernel.system, backticks, File, IO, and ENV).

This access results in complete compromise of Confidentiality (C:H), Integrity (I:H), and Availability (A:H) within the scope of the Ruby process. An attacker can read environment variables containing database credentials or API keys, modify application source code or local files, pivot to internal network services, or terminate the host process.

> [!IMPORTANT] > Only the Ruby compiler backend (src/compilers/ruby.ts) is affected by this vulnerability. Deployments that compile Elo expressions exclusively to JavaScript, Python, or PostgreSQL SQL are not vulnerable to # string interpolation injection.

Remediation

The primary remediation is to upgrade @enspirit/elo to version 1.0.1 or later. Version 1.0.1 incorporates commit 51b869963fbe445c18328714a7ccfbd76b21ba38 (released in commit d2a89a8db76a244eb740687524a7e8529b7554b5), which ensures all string literals and subtype constraint failure messages emitted into Ruby double-quoted strings pass through escapeRubyDQ.

npm install @enspirit/elo@^1.0.1

After upgrading, verify that any pre-compiled Ruby scripts or cached compilation artifacts generated by versions < 1.0.1 are invalidated and recompiled. If an application stores generated Ruby code in a database or filesystem cache prior to evaluation, upgrading the npm package alone will not neutralize malicious payloads that were compiled before the update.

For environments where an immediate package upgrade is not possible, administrators should disable the Ruby compilation target (-t ruby) when processing untrusted inputs. Switching evaluation to the JavaScript or Python backend eliminates the vulnerable code path. Additionally, services that evaluate dynamically compiled code from untrusted users should execute the target runtime inside an isolated sandbox (such as a container with a read-only root filesystem, dropped Linux capabilities, no network egress, and strict seccomp filters).

Official Patches

enspiritPrimary security commit fixing unescaped '#' interpolation in Ruby double-quoted string emission.
enspiritRelease v1.0.1 commit.
enspiritOfficial GitHub Security Advisory (GHSA-7w38-ggh5-v542).

Fix Analysis (2)

Technical Appendix

CVSS Score
9.8/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

Affected Systems

@enspirit/elo (npm package) < 1.0.1Elo CLI (bin/eloc) using the Ruby target (-t ruby)Downstream applications compiling untrusted Elo expressions to Ruby

Affected Versions Detail

Product
Affected Versions
Fixed Version
@enspirit/elo
enspirit
< 1.0.11.0.1
AttributeDetail
Vulnerability TypeCode Injection / Remote Code Execution (CWE-94, CWE-116, CWE-1336)
Affected Component@enspirit/elo Ruby Backend Compiler (src/compilers/ruby.ts)
Attack VectorNetwork / Untrusted Elo Expression Compilation to Ruby
CVSS v3.1 Score9.8 Critical (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)
Patched Version@enspirit/elo 1.0.1
Exploit StatusFunctional Proof of Concept (PoC) Published
CISA KEV StatusNot Listed

MITRE ATT&CK Mapping

T1059Command and Scripting Interpreter
Execution
T1203Exploitation for Client Execution
Execution
CWE-94
Improper Control of Generation of Code ('Code Injection')

The software constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment.

Known Exploits & Detection

GitHub Security AdvisoryOfficial security advisory containing proof-of-concept Elo expressions demonstrating arbitrary command execution via string literals and subtype constraint labels.

Vulnerability Timeline

Vulnerability disclosed and patched in @enspirit/elo v1.0.1
2026-04-20
CVE-2026-44266 published to CVE and NVD databases
2026-11-03

References & Sources

  • [1]GitHub Security Advisory GHSA-7w38-ggh5-v542
  • [2]Fix Commit: Escape '#' in Ruby Double-Quoted Strings
  • [3]Release v1.0.1 Commit
  • [4]Official CVE-2026-44266 Record
  • [5]@enspirit/elo Source Repository

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•31 minutes ago•CVE-2026-44265
7.4

CVE-2026-44265: Code and SQL Injection via Programmatic AST Emission in @enspirit/elo

A code injection and SQL injection vulnerability exists in @enspirit/elo prior to version 1.0.1. When compiling expressions via the programmatic Abstract Syntax Tree (AST) API, the backend emitters for JavaScript, Ruby, Python, and PostgreSQL SQL fail to perform runtime type validation or lexical verification on AST node properties. Applications that construct or deserialize AST nodes from untrusted sources allow attackers to inject arbitrary code or SQL commands directly into the emitted target output.

Alon Barad
Alon Barad
1 views•9 min read
•about 3 hours ago•CVE-2026-44267
9.8

CVE-2026-44267: Sandbox Escape and Arbitrary Code Execution in Elo Expression Language

CVE-2026-44267 is a sandbox escape and code injection vulnerability in @enspirit/elo prior to version 1.0.1. Due to unrestricted member access transformation in the compiler pipeline, plain Elo expression strings can traverse JavaScript object prototypes via .constructor.constructor to access the host runtime Function constructor. This allows attackers supplying untrusted Elo expressions to execute arbitrary JavaScript in Node.js server environments or client browser contexts.

Amit Schendel
Amit Schendel
5 views•9 min read
•1 day ago•CVE-2026-62374
7.1

CVE-2026-62374: Silent Claim-Set Reduction and Verification Bypass in SD JWT JS

CVE-2026-62374 (GHSA-f9j6-8p6x-r9j6) is a verification bypass vulnerability in the OpenWallet Foundation SD JWT JS library (@sd-jwt/core and @sd-jwt/decode versions 0.19.0 and earlier). Due to permissive UTF-8 decoding and the omission of mandatory reference checks during presentation verification, tampered or unreferenced disclosures are silently dropped rather than rejected. This deviates from RFC 9901 §7.1 requirements and allows attackers to execute silent claim-set reduction attacks against relying parties.

Alon Barad
Alon Barad
10 views•10 min read
•1 day ago•GHSA-J656-3HF2-FVJC
6.1

GHSA-j656-3hf2-fvjc: Read-Only SQL Validation Bypass via Comment Interpretation Conflict in Bytebase DBHub

An interpretation conflict in Bytebase DBHub (< 0.22.6) allows attackers to bypass read-only SQL query restrictions when connected to MySQL or MariaDB instances. Because DBHub's custom SQL tokenizer treats any '--' sequence as a comment, whereas MySQL and MariaDB require trailing whitespace or a control character, crafted queries containing '--' immediately followed by non-whitespace characters allow stacked destructive SQL statements to execute on connections configured as read-only.

Alon Barad
Alon Barad
6 views•9 min read
•3 days ago•CVE-2026-118777
4.8

CVE-2026-118777: Prototype Pollution in Forge HTTP Client Cookie Management

CVE-2026-118777 is a prototype pollution vulnerability (CWE-1321) in the Forge JavaScript cryptography and networking library (distributed on npm as node-forge) prior to version 1.4.1. The flaw resides in the forge.http client subsystem, where incoming HTTP cookie names and paths parsed from Set-Cookie response headers are stored directly into standard JavaScript objects without key validation or property isolation. By returning crafted Set-Cookie headers containing keys such as __proto__ or constructor, a malicious HTTP server can inject arbitrary properties into Object.prototype, attach attributes to the global Object constructor, or delete built-in prototype methods to cause an application-wide denial of service.

Amit Schendel
Amit Schendel
10 views•10 min read
•3 days ago•CVE-2026-118775
3.7

CVE-2026-118775: ASN.1 OID First Arc Truncation and Ambiguity in node-forge

CVE-2026-118775 (GHSA-4642-5mcj-2rqw) is an integer overflow and validation flaw in the ASN.1 serialization module of Forge (node-forge) prior to version 1.4.1. The asn1.oidToDer() function fails to validate the range of the first two arcs of an Object Identifier (OID) and truncates the packed initial subidentifier to a single 8-bit integer. Applications that perform policy checks on untrusted OID strings before encoding them into Distinguished Encoding Rules (DER) format can be tricked into emitting DER bytes that correspond to a completely different, restricted OID.

Amit Schendel
Amit Schendel
11 views•10 min read