Fix Lack of Resources & Rate Limiting in Gatsby
Gatsby Functions (serverless API routes) are often overlooked during security audits. While the frontend is static, the /api/* endpoints are dynamic and vulnerable to resource exhaustion. Without rate limiting, an attacker can script thousands of requests to expensive operations—like database writes or heavy image processing—leading to Denial of Service (DoS) or astronomical cloud compute bills. In Gatsby, we solve this by wrapping our handlers with middleware-like logic to enforce request quotas.
The Vulnerable Pattern
export default async function handler(req, res) { // VULNERABLE: No rate limiting or request validation // An attacker can flood this endpoint to exhaust backend resources const { email, message } = req.body;await sendToDatabase(email, message);
return res.status(200).json({ status: ‘Message sent’ }); }
The Secure Implementation
The secure implementation utilizes 'express-rate-limit' wrapped in a Promise to bridge the gap between Express middleware and Gatsby's serverless function signature. By setting a 'windowMs' and a 'max' request count, we ensure that an IP address cannot spam the endpoint. In a production environment, specifically for serverless architectures like Gatsby Cloud or Netlify, it is critical to use a Redis-backed store (e.g., rate-limit-redis) for the 'store' option in the limiter. This is because serverless functions are stateless, and local memory stores will reset every time a new lambda instance is spun up, allowing attackers to bypass limits by triggering new instances.
import rateLimit from 'express-rate-limit';const limiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 5, // Limit each IP to 5 requests per window standardHeaders: true, legacyHeaders: false, });
const runMiddleware = (req, res, fn) => { return new Promise((resolve, reject) => { fn(req, res, (result) => { if (result instanceof Error) return reject(result); return resolve(result); }); }); };
export default async function handler(req, res) { try { // Apply rate limiting middleware before processing request await runMiddleware(req, res, limiter);
const { email, message } = req.body; await sendToDatabase(email, message); return res.status(200).json({ status: 'Message sent' });
} catch (error) { // If rate limit is hit, express-rate-limit sends 429 automatically // or we catch the error here return res.status(429).json({ error: ‘Too many requests. Slow down, hacker.’ }); } }
Your Gatsby API
might be exposed to Lack of Resources & Rate Limiting
74% of Gatsby apps fail this check. Hackers use automated scanners to find this specific flaw. Check your codebase before they do.
Free Tier • No Credit Card • Instant Report
Verified by Ghost Labs Security Team
This content is continuously validated by our automated security engine and reviewed by our research team. Ghost Labs analyzes over 500+ vulnerability patterns across 40+ frameworks to provide up-to-date remediation strategies.