
Proof-of-concept exploit for CVE-2026-22014 demonstrating persisted-query ID manipulation in GraphQL APIs to bypass allowlists and execute arbitrary queries.
// graphql_persisted.js - Accepts persisted query IDs
const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const queries = {
"abc": "query { user { name } }"
};
app.post('/graphql', graphqlHTTP({
schema: schema,
customExecuteFn: (args) => {
const doc = parse(queries[args.queryId] || args.query);
return execute(args);
}
}));
A GraphQL server supports persisted queries but falls back to the provided parameter if the is unknown. An attacker can supply a nonexistent along with an arbitrary GraphQL query, bypassing the intended allowlist of persisted queries.
queryqueryIdqueryIdquery when queryId is not found, instead of rejecting the request.Start the server and send a mixed payload:
python exploit_persisted_query.py
The server executes the malicious query.