Looking for the vulnerability index of Invicti's legacy products?
GraphQL Non-JSON Queries over GET: Potential CSRF Vulnerability - Vulnerability Database

GraphQL Non-JSON Queries over GET: Potential CSRF Vulnerability

Description

This GraphQL endpoint accepts queries via HTTP GET requests with non-JSON content types (such as query parameters or form data). Unlike JSON POST requests which browsers restrict from cross-origin forms, GET requests and non-JSON POST requests can be triggered through simple HTML forms or image tags, making them vulnerable to Cross-Site Request Forgery (CSRF) attacks. An attacker can craft malicious web pages that cause authenticated users' browsers to unknowingly execute GraphQL mutations or queries against your application.

Remediation

Configure your GraphQL server to only accept queries via POST requests with JSON content type (application/json), and reject GET requests entirely. Additionally, implement CSRF protection tokens for state-changing operations. Here are implementation examples for common frameworks:

Express.js with express-graphql:

const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const app = express();

// CSRF protection middleware - MUST come before GraphQL handler
app.use('/graphql', (req, res, next) => {
  // Reject GET requests
  if (req.method === 'GET') {
    return res.status(405).json({ error: 'GET requests not allowed' });
  }
  // Verify Content-Type is application/json
  if (!req.is('application/json')) {
    return res.status(415).json({ error: 'Content-Type must be application/json' });
  }
  next();
});

// GraphQL handler comes after security checks
app.use('/graphql', graphqlHTTP({
  schema: mySchema,
  graphiql: false // Disable GraphiQL in production
}));
Apollo Server:
const { ApolloServer } = require('apollo-server-express');
const express = require('express');
const app = express();

const server = new ApolloServer({
  typeDefs,
  resolvers,
  csrfPrevention: true, // Enable built-in CSRF prevention
  introspection: false, // Disable in production
  playground: false // Disable in production
});

await server.start();
server.applyMiddleware({ app });
For additional defense-in-depth, implement CSRF tokens using libraries like csurf for Express.js, and verify custom headers (e.g., X-Requested-With) that cannot be set by simple HTML forms.

Related Vulnerabilities