🚀 Executive Summary

TL;DR: Next.js servers are susceptible to denial-of-service attacks and inflated cloud bills by exploiting the default image optimization endpoint to process arbitrary external images. The primary solution involves whitelisting allowed image source domains using `remotePatterns` in `next.config.js` or implementing a WAF/CDN for edge-level rate-limiting. This prevents the server from downloading and processing malicious or oversized files, securing infrastructure and controlling costs.

🎯 Key Takeaways

  • The Next.js Image Optimization API (`/_next/image`) can be exploited by instructing it to fetch and process images from any external URL, leading to high CPU/memory usage and significant cloud costs.
  • Implementing `remotePatterns` in `next.config.js` is the essential application-level fix, explicitly whitelisting approved image source domains and preventing the server from processing non-whitelisted external URLs.
  • Deploying a Web Application Firewall (WAF) or CDN with rate-limiting rules (e.g., on `/images/_next/*`) provides an infrastructure-level defense, blocking malicious traffic at the network edge before it impacts Next.js servers.

Taking down Next.js servers for 0.0001 cents a pop

A malicious actor can cripple your Next.js server and run up your cloud bill by exploiting the default image optimization endpoint. Here’s how we stop the bleeding, fix the root cause, and harden your infrastructure for good.

That Next.js “Feature” Costing You Thousands? Let’s Fix It.

I remember getting the PagerDuty alert at 2:17 AM on a Sunday. CPU utilization on our new marketing fleet was pegged at 99% for over an hour. My first thought was a bad deploy or an infinite loop in the code. But when I SSH’d into one of the boxes, `htop` told a different story. It wasn’t our Node process going wild; it was dozens of `sharp` image processing threads, all spun up by Next.js, all trying to download and resize a multi-gigabyte astronomical survey image from some obscure university’s FTP server. Someone found our `/_next/image` endpoint and was having a field day. Our cloud bill for that little “incident” was four figures. This isn’t a theoretical problem; it’s a financial landmine waiting for you to step on it.

The “Why”: An Open-Door Policy for Images

Let’s be clear: this isn’t a “vulnerability” in the traditional sense. It’s a powerful feature with default settings that are, in my opinion, dangerously permissive. The root cause is the Next.js Image Optimization API, exposed at `/_next/image`. By default, it can be instructed to fetch an image from any URL on the internet. An attacker simply crafts a URL like:

https://your-site.com/_next/image?url=https://some-shady-site.com/huge-image.tiff&w=3840&q=100

When your server receives this request, it obediently:

  1. Downloads the massive file from the external URL.
  2. Spends significant CPU and memory resizing it.
  3. Serves the result back to the attacker.

Multiply this by a few thousand requests from a simple script, and your servers are toast, and your cloud provider is sending you a very large invoice. You’re paying for the bandwidth, the compute, and the egress. It’s a denial-of-service attack you pay for.

The Fixes: From Band-Aid to Body Armor

Okay, enough with the horror stories. Let’s get this locked down. I’ve got three tiers of solutions, from the immediate fix you should deploy five minutes ago to the long-term architectural shield.

Solution 1: The Quick Fix (The Configuration Whitelist)

This is the first thing you should do. It’s built right into Next.js, but it’s tragically easy to miss during initial setup. You need to explicitly tell Next.js which domains are allowed to be sources for your images. You do this in your next.config.js file.

Instead of leaving it wide open, you define a strict list of sources using remotePatterns. This is the modern, more flexible way to do it.

/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'assets.your-company-cms.com',
        port: '',
        pathname: '/images/**',
      },
      {
        protocol: 'https',
        hostname: '**.s3.amazonaws.com',
      },
    ],
  },
};

module.exports = nextConfig;

With this in place, if an attacker tries to use a non-whitelisted domain, Next.js will throw a 400 Bad Request and never even attempt to download the image. The attack is stopped at the application layer before it can consume resources.

Solution 2: The Permanent Fix (The Infrastructure Shield)

Configuring Next.js is essential, but as a cloud architect, I don’t like relying solely on the application for security. We need defense in depth. This is where you put a shield in front of your entire application: a Web Application Firewall (WAF) and a CDN with rate-limiting capabilities, like AWS WAF or Cloudflare.

We configure a specific rule that targets the image optimization path. For example, in Cloudflare, we can set a rate-limiting rule on any request to `/images/_next/*` that allows, say, 100 requests per IP per minute. Any IP address that exceeds this is automatically blocked for a period of time.

Pros Cons
Blocks malicious traffic before it even hits your Next.js server, saving compute resources. Can add a small amount of cost and complexity to your stack.
Protects against more than just this one attack vector (e.g., DDoS, SQL injection). Requires careful configuration to avoid blocking legitimate, high-traffic users.
Globally distributed, so the block happens at the edge, close to the attacker. Another piece of infrastructure to manage and monitor.

This approach moves the fight from your application servers (e.g., `prod-web-app-01`) to the global network edge. Your app never even knows it was under attack.

Solution 3: The ‘Nuclear’ Option (Disabling the Beast)

Let’s say you’re under a massive, sustained attack. The bill is climbing, and you need to stop the bleeding right now. You don’t have time to test and deploy a WAF rule. In this emergency scenario, you can disable the Next.js Image Optimization feature entirely.

You do this with a one-line change in next.config.js:

/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    unoptimized: true,
  },
};

module.exports = nextConfig;

This is the “pull the fire alarm” option. It’s hacky but effective. Once deployed, Next.js will serve all images as-is from their source URL without any processing. The `/_next/image` endpoint effectively goes dead.

Warning: This is a drastic measure. Disabling optimization will likely harm your site’s performance, hurt your Core Web Vitals, and could negatively impact your SEO. Use this only as a temporary emergency stopgap while you implement Solution 1 or 2.

Look, we all love frameworks that make our lives easier, but convenience can’t come at the cost of stability and security. This Next.js image issue is a classic example. It’s a powerful tool, but with great power comes the responsibility to configure it correctly. Don’t wait for that 2 AM alert. Check your config, shield your infrastructure, and sleep well at night.

Darian Vance - Lead Cloud Architect

Darian Vance

Lead Cloud Architect & DevOps Strategist

With over 12 years in system architecture and automation, Darian specializes in simplifying complex cloud infrastructures. An advocate for open-source solutions, he founded TechResolve to provide engineers with actionable, battle-tested troubleshooting guides and robust software alternatives.


🤖 Frequently Asked Questions

âť“ How does the Next.js image optimization endpoint lead to server resource exhaustion?

The default Next.js Image Optimization API (`/_next/image`) can be instructed via a URL parameter to download and process images from any external URL. An attacker can point this to a massive file, causing the server to consume significant CPU, memory, and bandwidth for downloading and resizing, leading to a denial-of-service and high cloud bills.

âť“ What are the trade-offs between configuring `remotePatterns` and using a WAF/CDN for Next.js image optimization security?

Configuring `remotePatterns` is an application-level fix, stopping unapproved image requests early at the Next.js layer, which is effective and built-in. A WAF/CDN provides defense-in-depth at the network edge, protecting against broader attack vectors and offloading traffic before it reaches your server, but adds cost, complexity, and requires careful configuration to avoid blocking legitimate users.

âť“ What is a common implementation pitfall when securing Next.js image optimization and how can it be avoided?

A common pitfall is failing to define `remotePatterns` in `next.config.js`, leaving the image optimization endpoint open to arbitrary external URLs. This can be avoided by explicitly listing all trusted image source domains (e.g., your CMS, S3 buckets) in the `images.remotePatterns` configuration.

Leave a Reply

Discover more from TechResolve - SaaS Troubleshooting & Software Alternatives

Subscribe now to keep reading and get access to the full archive.

Continue reading