Initializing Enclave...

How to Fix Next.js 'Invalid src prop' Error for External Image URLs (domains & remotePatterns Config)

Threat/Impact Level: HIGH | Exploitability/Downtime Risk: HIGH | Time to Fix: 5 mins


TL;DR

  • What broke: Next.js <Image> received an src from an external host not listed in next.config.js, throwing Error: Invalid src prop and hard-crashing the render.
  • How to fix it: Add the hostname to remotePatterns (Next.js 13+) or domains (legacy) inside the images key of next.config.js, then restart the dev server or redeploy.
  • Shortcut: Use our Client-Side Sandbox below to auto-refactor this — paste your failing src URL and current next.config.js and get a corrected config instantly.

The Incident (What Does the Error Mean?)

The raw error thrown at runtime:

Error: Invalid src prop (https://cdn.example.com/images/hero.png) on `next/image`,
hostname "cdn.example.com" is not configured under images in your `next.config.js`.
See more info: https://nextjs.org/docs/messages/next-image-unconfigured-host

Next.js's <Image> component does not proxy or render external images unless the origin hostname is explicitly whitelisted. The component fails at render time — not build time — meaning this hits production users first, not your CI pipeline. The page either white-screens or throws an unhandled error boundary depending on your setup.


The Attack Vector / Blast Radius

This is not just a DX annoyance. The whitelist exists to prevent Server-Side Request Forgery (SSRF) via Next.js's built-in image optimization API (/_next/image?url=...&w=...&q=...).

If you "fix" this by setting an overly broad wildcard — e.g., allowing ** as a hostname or using protocol: 'https', hostname: '**' — you've just turned your Next.js image optimization endpoint into an open proxy. An attacker can craft requests like:

GET /_next/image?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/&w=16&q=75

This hits the AWS EC2 Instance Metadata Service (IMDS). Your server fetches it, and depending on error handling, may leak credentials in logs or error responses. The blast radius: full IAM credential exfiltration from your compute environment.

Minimum-privilege hostname scoping is not optional.


How to Fix It (The Solution)

Basic Fix — Legacy domains Array (Next.js < 12.3, still works but deprecated)

// next.config.js
module.exports = {
  images: {
-   // no images config
+   domains: ['cdn.example.com'],
  },
};

Do not use this for new projects. domains allows all protocols and all paths on that hostname. It's a blunt instrument.


Enterprise Best Practice — remotePatterns (Next.js 13+, required for 14+)

remotePatterns enforces protocol + hostname + port + pathname at the pattern level. Scope it as tightly as possible.

// next.config.js
module.exports = {
  images: {
-   domains: ['cdn.example.com'],
+   remotePatterns: [
+     {
+       protocol: 'https',
+       hostname: 'cdn.example.com',
+       port: '',
+       pathname: '/images/**',
+     },
+   ],
  },
};

Key hardening decisions:

| Field | Insecure Value | Hardened Value | |---|---|---|| | protocol | omitted (allows http) | 'https' explicit | | hostname | '**.example.com' | 'cdn.example.com' exact | | pathname | '/**' (all paths) | '/images/**' scoped |

After editing next.config.js, a full server restart is required — this is not hot-reloaded.

# Kill and restart
kill $(lsof -t -i:3000) && npm run dev
# or in production
pm2 restart next-app

💡 Tired of pasting proprietary configs into ChatGPT? Generic AI tools log your company's ARNs, DB strings, and private keys. StackEngine is a zero-backend, pure Client-Side WASM utility. Drop your failing config into the sandbox above. We redact your secrets locally in the browser and auto-generate the refactored code using your own API key.


Prevention in CI/CD

This class of misconfiguration should never reach production. Here's how to gate it:

1. Checkov Static Analysis

Checkov has checks for Next.js misconfigs. Add to your pipeline:

# .github/workflows/security.yml
- name: Run Checkov on next.config.js
  uses: bridgecrewio/checkov-action@master
  with:
    file: next.config.js
    framework: javascript

2. Custom ESLint Rule

Write a lint rule that fails the build if remotePatterns contains hostname: '**' or if domains is non-empty in a Next.js 13+ project:

// eslint-plugin-local/no-wildcard-image-domains.js
module.exports = {
  create(context) {
    return {
      Property(node) {
        if (
          node.key.name === 'hostname' &&
          node.value.value === '**'
        ) {
          context.report({
            node,
            message: 'Wildcard hostname in remotePatterns is an SSRF risk.',
          });
        }
      },
    };
  },
};

3. OPA / Conftest Policy

If you manage next.config.js generation via infrastructure tooling:

# policy/next_image.rego
package nextjs.image

deny[msg] {
  pattern := input.images.remotePatterns[_]
  pattern.hostname == "**"
  msg := "remotePatterns wildcard hostname is prohibited. Scope to exact CDN hostname."
}

deny[msg] {
  count(input.images.domains) > 0
  msg := "Deprecated 'domains' key detected. Migrate to remotePatterns with scoped pathname."
}
conftest test next.config.js --policy policy/

4. Dependency and Config Drift Alerts

Pin your Next.js version in package.json and use Renovate or Dependabot with a custom regex manager to detect if domains re-appears after a merge:

// renovate.json
{
  "regexManagers": [{
    "fileMatch": ["next\\.config\\.js"],
    "matchStrings": ["domains:\\s*\\[(?<currentValue>[^\\]]+)\\]"],
    "depNameTemplate": "next-image-domains-audit"
  }]
}

The pattern: shift left. Catch this at lint → PR check → deploy gate. Never in production.

Related Diagnostics

"Part of the Security Utility Matrix."

View all 140 Security Tools →