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-2025-31481

The Relay Race: Bypassing Auth in API Platform's GraphQL Node Interface

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 20, 2026·6 min read·103 visits

Executive Summary (TL;DR)

API Platform's GraphQL implementation dropped the ball on the Relay `node` query. By asking for a resource via its global ID (IRI) through the `node` field, the system failed to load the specific security rules attached to that resource. This means an unauthenticated attacker could access data restricted to admins simply by knowing the resource's ID URL.

A critical authentication bypass vulnerability in API Platform Core's GraphQL subsystem allows attackers to read protected resources by leveraging the Relay `node` interface. The flaw stems from a failure to correctly load security operations when resolving Global Object Identifiers (IRIs), effectively neutralizing access control lists (ACLs) for specific queries.

The Hook: When Magic Becomes Tragic

GraphQL is magical. It lets front-end developers ask for exactly what they want, and the backend just... provides. One of the most powerful features in the GraphQL ecosystem is the Relay Global Object Identification specification. It introduces a standardized interface called Node. The promise is simple: give me a global ID (usually an IRI like /users/1), and I will return the object, no matter what type it is.

It’s the ultimate skeleton key for data fetching. You don't need to know if you are querying a User, a Product, or a SecretDocument; you just ask for the Node, and the server resolves the type for you. But here is the problem with magic skeleton keys: if you forget to check who is holding them, you are going to have a bad time.

In API Platform, a framework designed to automagically build APIs around your PHP classes, this convenience feature had a nasty side effect. While the framework is usually paranoid about checking @Security annotations and voters before handing out data, the node query path found a loophole. It was the digital equivalent of a bouncer checking IDs at the VIP entrance, while leaving the loading dock wide open because 'surely nobody knows where the loading dock is.' (Spoiler: We always know where the loading dock is).

The Flaw: Identity Crisis

To understand this bug, you have to understand how API Platform handles requests. When you hit a standard endpoint, say query { book(id: "/books/1") { ... } }, the system knows exactly what you are doing. It maps the request to a specific Operation on the Book resource. That Operation carries metadata, including security rules like is_granted('ROLE_USER').

However, the Relay node query is polymorphic. It starts at the root. The request is just query { node(id: "...") }. At the moment the query starts, the system doesn't necessarily know what specific resource operation is being performed. It just knows it needs to resolve an ID.

The vulnerability lived in the ResolverFactory. When processing the node field, the system initialized a context for the resolver. In the affected versions, if the operation context wasn't explicitly passed (which is the case for the root node field), the code defaulted to a generic, empty Query object.

Here is the kicker: that generic Query object didn't have your custom security attributes. It was a blank slate. So when the security listener asked, "Are there any rules preventing this user from seeing this?", the generic object replied, "Nope, looks clear to me." The actual resource class (e.g., SecuredDummy) had rules defined, but because the resolver was looking at the generic placeholder operation instead of the specific resource operation, those rules were completely ignored.

The Code: Null Coalescing to Disaster

Let's look at the smoking gun. The vulnerability was centered in src/GraphQl/Resolver/Factory/ResolverFactory.php. The logic tried to determine which operation was currently being executed to enforce permissions.

In the vulnerable version, the code looked something like this (simplified for clarity):

// Vulnerable Code
$operation = $context['operation'] ?? null;
 
// If we don't know the operation, just make up a blank one!
$operation ??= new Query(); 
 
// ... later ...
if (!$this->security->isGranted($operation->getSecurity(), ...)) {
    throw new AccessDeniedException();
}

See that ??= new Query()? That is the developer shrugging. Since a fresh new Query() has no security attributes, isGranted checks nothing. It defaults to allowing access because there are no restrictions to enforce.

The fix, applied in commit 60747cc8c2fb855798c923b5537888f8d0969568, forces the system to actually do the homework. Instead of guessing, it now uses a RuntimeOperationMetadataFactory to look up the real operation associated with the IRI.

// Patched Code
try {
    // Actually figure out what resource this IRI belongs to
    $operation = $this->runtimeOperationMetadataFactory->create($operationName, $resourceClass, true);
} catch (OperationNotFoundException) {
    // If we can't find the operation security rules, don't just let them in.
    if (null === $operation) {
        // Fallback logic that implies strictness or failure
    }
}

By ensuring the $operation object is hydrated with the metadata from the actual target resource, the security voters are correctly invoked.

The Exploit: Skirting the Bouncer

Exploiting this is trivially easy if you know the IRI format of the target application. Let's assume we have a resource PrivateDocument that requires ROLE_ADMIN. Normal users should get a 403 Forbidden.

Step 1: The Sanity Check (Failed Access) A standard GraphQL query against the resource works as expected:

query {
  privateDocument(id: "/private_documents/1") {
    secretContent
  }
}

Result: "Access Denied." (Because the privateDocument query operation has the security check attached).

Step 2: The Bypass Now, we switch to the Relay node interface. We ask for the exact same object, but we route the request through the global resolver:

query {
  node(id: "/private_documents/1") {
    ... on PrivateDocument {
      id
      secretContent
    }
  }
}

Step 3: Execution Because the node resolver uses the generic Query object (which lacks the ROLE_ADMIN requirement), the API fetches the object from the database and serializes it. The security listener sees an operation with no restrictions and waves it through.

Result:

{
  "data": {
    "node": {
      "id": "/private_documents/1",
      "secretContent": "The launch codes are 12345"
    }
  }
}

Here is a visualization of the logic flow:

The Impact: Authorization is Optional

The impact here is a classic Broken Access Control (CWE-284), but widely distributed. In API Platform, security is often defined centrally on the Resource class (e.g., `#[ApiResource(security:

The Fix: Closing the Loophole

The maintainers patched this in API Platform Core versions 3.4.17 and 4.0.22. The fix involves a mechanism that properly resolves the underlying resource class from the IRI provided to the node query, ensuring that the correct operation context (and thus the correct security rules) is loaded.

If you are running a vulnerable version, you have two choices:

  1. Upgrade immediately. This is the only clean fix. The patch logic involves complex metadata factory chaining that is not easily hot-patched manually.
  2. Disable the node query. If your frontend application does not rely on Relay standards, you can disable the node definition in your GraphQL configuration. This removes the attack vector entirely.

To developers using API Platform: Do not assume global mechanisms inherit specific constraints. Explicitly test your permissions models using the node query, not just your custom query endpoints.

Official Patches

API PlatformOfficial Security Advisory

Fix Analysis (2)

Technical Appendix

CVSS Score
7.5/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
EPSS Probability
0.04%
Top 100% most exploited

Affected Systems

API Platform Core 4.0.0 through 4.0.21API Platform Core < 3.4.17

Affected Versions Detail

Product
Affected Versions
Fixed Version
API Platform Core
api-platform
>= 4.0.0, < 4.0.224.0.22
API Platform Core
api-platform
< 3.4.173.4.17
AttributeDetail
Vulnerability TypeAuthentication Bypass / Broken Access Control
CWE IDCWE-284
CVSS Score7.5 (High)
Attack VectorNetwork
Affected ComponentGraphQL ResolverFactory (Relay Node)
Exploit StatusPoC Available

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1592Gather Victim Host Information
Reconnaissance
T1078Valid Accounts
Defense Evasion
CWE-284
Improper Access Control

Improper Access Control

Known Exploits & Detection

GitHub Security AdvisoryTechnical description and reproduction steps provided by vendor.

Vulnerability Timeline

Vulnerability Disclosed / Advisory Published
2025-04-03
Patched Version 3.4.17 Released
2025-04-03
NVD Metadata Updated
2025-04-08

References & Sources

  • [1]GitHub Advisory GHSA-cg3c-245w-728m
  • [2]Patch Commit 60747cc

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

•1 day 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
8 views•10 min read
•1 day 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
9 views•10 min read
•1 day ago•CVE-2026-119194
7.5

CVE-2026-119194: Algorithmic Complexity Denial of Service in pyasn1 Schemaless ASN.1 Decoder

CVE-2026-119194 is an algorithmic complexity vulnerability (CWE-407) in the pyasn1 library for Python, affecting versions 0.3.3 through 0.6.4. The flaw resides in the schemaless decoding routine ConstructedPayloadDecoderBase._decodeComponentsSchemaless used across BER, CER, and DER codecs. By sending an ASN.1 container populated with child components whose tag identifiers are separated by multiples of CPython's integer hash modulus (sys.hash_info.modulus), an unauthenticated attacker can force worst-case hash collisions in an unbounded Python set, degrading decoding performance from O(N) to O(N^2) and causing a Denial of Service (DoS).

Alon Barad
Alon Barad
8 views•9 min read
•1 day ago•CVE-2026-119195
7.5

CVE-2026-119195: Quadratic-Time Denial of Service in pyasn1 BER/CER/DER Decoders

CVE-2026-119195 is an algorithmic complexity vulnerability (CWE-407) in the pyasn1 library for Python, affecting all versions prior to 0.6.5. When decoding constructed strings or indefinite-length ANY types across BER, CER, and certain DER code paths, the payload decoders repeatedly concatenate incoming fragments onto an immutable bytes object using the += operator. Because Python bytes objects cannot be resized in-place, each fragment iteration allocates a new buffer and copies all previously accumulated bytes, resulting in quadratic O(N^2) time and memory copy complexity. An unauthenticated remote attacker can supply a highly fragmented ASN.1 stream to exhaust CPU cycles and stall application worker threads.

Amit Schendel
Amit Schendel
9 views•10 min read
•1 day ago•CVE-2026-119197
7.5

CVE-2026-119197: Quadratic Algorithmic Complexity Denial of Service in pyasn1 REAL Mantissa Decoder

An algorithmic complexity vulnerability (CWE-407) in pyasn1 versions prior to 0.6.5 allows unauthenticated attackers to cause a Denial of Service (DoS) via crafted ASN.1 payloads. The flaw resides in the binary-encoded ASN.1 REAL mantissa deserialization routine within RealPayloadDecoder.valueDecoder. By performing iterative byte-string slicing and repeated bitwise shifts on a growing arbitrary-precision integer, the decoder exhibits quadratic time and memory allocation complexity relative to the mantissa length. Supplying a BER-, CER-, or DER-encoded payload with a large REAL mantissa causes excessive CPU consumption and blocks application worker processes.

Amit Schendel
Amit Schendel
8 views•10 min read
•1 day ago•CVE-2026-119196
7.5

CVE-2026-119196: Quadratic CPU Consumption in pyasn1 Constructed BIT STRING Decoding

A vulnerability classified under CWE-407 (Inefficient Algorithmic Complexity) exists in the pyasn1 library prior to version 0.6.5. When parsing constructed ASN.1 BIT STRING payloads under BER, CER, or schema-driven DER encoding rules, the BitStringPayloadDecoder repeatedly shifts and copies the entire accumulated bit value for each incoming fragment. Processing inputs with a large number of small constructed fragments induces quadratic CPU consumption, allowing unauthenticated remote attackers to cause a denial of service via resource exhaustion during the initial decoding phase.

Alon Barad
Alon Barad
9 views•10 min read