Graphql Introspection in Express with Hmac Signatures
Graphql Introspection in Express with Hmac Signatures — how this specific combination creates or exposes the vulnerability
GraphQL introspection is a feature that allows a client to query the structure of a GraphQL schema at runtime. In an Express server, enabling introspection on production endpoints can expose types, queries, and mutations that should remain internal. When Hmac Signatures are used for request authentication but are applied only to selected routes or inconsistently, an attacker can exploit the disparity to learn about the API surface without needing valid credentials.
Consider an Express setup where Hmac Signatures validate only specific admin routes, while the GraphQL endpoint remains open for introspection. An attacker can send an introspection query to the GraphQL endpoint and analyze the returned schema to discover other routes that require Hmac Signatures. By correlating endpoint paths and operation names revealed through introspection with the protected routes, the attacker can infer which operations might accept Hmac Signatures and potentially craft replay or tampering attacks.
GraphQL introspection responses include type definitions, input fields, and example values, which can inadvertently reveal business logic, data models, and authorization boundaries. If Hmac Signatures are generated using a predictable pattern or shared secret without additional context (such as timestamps or nonce), an attacker who observes a signed request can attempt to reproduce the signature for related operations discovered via introspection.
Moreover, misconfigured CORS settings combined with introspection can amplify the risk. An attacker can run browser-based introspection queries from a malicious page if CORS permits the GraphQL endpoint, and then use the schema details to plan further attacks against Hmac-protected routes. Even without modifying server-side code, the information leakage from introspection can guide social engineering or token replay attempts.
In practice, this combination becomes a two-phase process: first, gather schema and endpoint information through introspection; second, use that knowledge to target Hmac-signed operations with tampered payloads or signature reuse. Because GraphQL allows querying nested and relational fields, an attacker can probe for data exposure risks that align with privileged operations protected by Hmac Signatures.
Hmac Signatures-Specific Remediation in Express — concrete code fixes
To mitigate risks related to GraphQL introspection and Hmac Signatures in Express, apply consistent authentication, disable introspection in production, and ensure Hmac verification covers all relevant routes with secure practices.
1. Disable GraphQL introspection in production
Set introspection to false when initializing your GraphQL server. This prevents runtime schema discovery while preserving functionality in development.
const { ApolloServer } = require('apollo-server-express');
const typeDefs = require('./schema');
const resolvers = require('./resolvers');
const server = new ApolloServer({
typeDefs,
resolvers,
introspection: process.env.NODE_ENV === 'development',
});
2. Apply Hmac Signatures uniformly to all sensitive routes
Use middleware to validate Hmac Signatures for both GraphQL and REST endpoints. This removes the route-level disparity that attackers exploit.
const crypto = require('crypto');
const express = require('express');
const app = express();
const SHARED_SECRET = process.env.HMAC_SECRET;
function verifyHmac(req, res, next) {
const signature = req.headers['x-hmac-signature'];
const timestamp = req.headers['x-timestamp'];
const nonce = req.headers['x-nonce'];
if (!signature || !timestamp || !nonce) {
return res.status(401).json({ error: 'Missing Hmac headers' });
}
// Basic replay protection: reject if timestamp is older than 5 minutes
const now = Math.floor(Date.now() / 1000);
if (Math.abs(now - parseInt(timestamp, 10)) > 300) {
return res.status(401).json({ error: 'Request expired' });
}
const payload = `${timestamp}:${nonce}:${req.method}:${req.path}`;
const expected = crypto.createHmac('sha256', SHARED_SECRET)
.update(payload)
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
return res.status(403).json({ error: 'Invalid Hmac signature' });
}
return next();
}
app.use(verifyHmac);
app.use('/graphql', (req, res, next) => {
// Ensure GraphQL endpoint also respects Hmac validation
verifyHmac(req, res, next);
}, graphqlHTTP({
schema: server.schema,
graphiql: process.env.NODE_ENV === 'development',
}));
3. Include contextual data in Hmac payload
Avoid using only static path and method. Include a nonce and timestamp to prevent replay attacks and ensure each signature is unique.
const payload = `${timestamp}:${nonce}:${req.method}:${req.path}:${JSON.stringify(req.body)}`;
4. Enforce CORS and limit exposure
Restrict origins and avoid exposing GraphQL endpoints to untrusted domains. This reduces the chance that introspection results are harvested from browser contexts.
const cors = require('cors');
app.use(cors({
origin: process.env.ALLOWED_ORIGINS ? process.env.ALLOWED_ORIGINS.split(',') : false,
credentials: true,
}));
5. Combine with schema directives
Use schema-level directives to conditionally hide introspection fields or require elevated privileges for sensitive queries, complementing Hmac-based route protection.
# Example directive usage (schema definition)
directive @auth(role: String!) on OBJECT | FIELD_DEFINITION
6. Monitor and rotate secrets
Regularly rotate the Hmac secret and audit access patterns. If introspection must remain enabled in staging, ensure it is strictly limited to trusted networks.
Related CWEs: dataExposure
| CWE ID | Name | Severity |
|---|---|---|
| CWE-200 | Exposure of Sensitive Information | HIGH |
| CWE-209 | Error Information Disclosure | MEDIUM |
| CWE-213 | Exposure of Sensitive Information Due to Incompatible Policies | HIGH |
| CWE-215 | Insertion of Sensitive Information Into Debugging Code | MEDIUM |
| CWE-312 | Cleartext Storage of Sensitive Information | HIGH |
| CWE-359 | Exposure of Private Personal Information (PII) | HIGH |
| CWE-522 | Insufficiently Protected Credentials | CRITICAL |
| CWE-532 | Insertion of Sensitive Information into Log File | MEDIUM |
| CWE-538 | Insertion of Sensitive Information into Externally-Accessible File | HIGH |
| CWE-540 | Inclusion of Sensitive Information in Source Code | HIGH |