---
title: "Security"
description: "Learn about the security defaults and how to further harden your OG image endpoint."
canonical_url: "https://nuxtseo.com/docs/og-image/guides/security"
last_updated: "2026-07-28T14:09:11.687Z"
---

Nuxt OG Image ships with secure defaults. The module clamps image dimensions, time limits renders, blocks internal network requests, and sanitizes user-provided props. These protections require no configuration.

The primary security concern with runtime OG image generation is **denial of service**: without protection, anyone can craft arbitrary image generation requests to your `/_og/d/` endpoint, consuming server CPU and memory. URL signing prevents this by ensuring only your application can generate valid image URLs.

For full protection, we recommend combining URL signing with a **web application firewall** (WAF) or rate limiting on the `/_og/` path prefix. Services like [Cloudflare](https://cloudflare.com), AWS WAF, or your hosting provider's built-in rate limiting can add an additional layer of defense.

```bash [.env]
NUXT_OG_IMAGE_SECRET=<your-secret>
```

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  ogImage: {
    security: {
      strict: true,
    }
  }
})
```

The secret is automatically picked up from the `NUXT_OG_IMAGE_SECRET` environment variable.

## Strict Mode

Enabling `strict` mode applies all recommended security defaults in a single flag:

- **URL signing required**: `secret` must be set (rejects unsigned runtime requests with `403`)
- **Inline HTML disabled**: The deprecated `html` option is stripped entirely, preventing SSRF via inline HTML injection
- **Query string size limit**: `maxQueryParamSize` defaults to `2048` characters (instead of no limit)
- **Origin restriction**: `restrictRuntimeImagesToOrigin` defaults to `true`, locking runtime generation to your site config URL host

Any of these can still be overridden explicitly. Strict mode only changes the defaults.

The build will fail if you enable `strict` without a `secret`. Generate one with:

```bash
npx nuxt-og-image generate-secret
```

## URL Signing

OG image URLs are signed by default. Every URL includes a cryptographic signature in the path, and the server rejects any runtime request whose signature is missing or invalid with a `403`. This prevents unauthorized image generation requests that would otherwise consume server resources.

### Default: auto-generated secret

When you do not configure a secret, the module generates a random one at build time, so signing works with no setup. The auto-generated secret **changes on every build**. That is fine for prerendered images (served as static files) and single-instance runtime deploys, but during a rolling or multi-instance deploy a URL signed by one build can fail verification on another.

For those deploys, set a stable secret so every instance shares the same value.

### Disabling signing

To serve unsigned runtime URLs (not recommended), set `secret` to `false`:

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  ogImage: {
    security: {
      secret: false,
    }
  }
})
```

<warning>

With signing disabled, an attacker can do more than trigger arbitrary renders: by supplying a `cacheKey` in the request they can **poison the runtime cache**, overwriting the cached image that your legitimate OG image URLs serve and spoofing the preview shown on social platforms. Only disable signing if the `/_og/` endpoint is otherwise protected (a WAF, origin restriction) or your images are fully prerendered.

URL signing will be **required in v7** whenever runtime image generation is enabled.

</warning>

### Setup (stable secret)

1. Generate a secret:

```bash
npx nuxt-og-image generate-secret
```

1. Set the environment variable:

```bash [.env]
NUXT_OG_IMAGE_SECRET=<your-secret>
```

Alternatively, you can set the secret directly in your nuxt config:

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  ogImage: {
    security: {
      secret: 'your-secret',
    }
  }
})
```

### How It Works

With signing active:

- `defineOgImage()` appends a signature to the URL path: `/_og/d/w_1200,h_600,s_abc123def456.png`
- The server extracts and verifies the signature before processing the request
- Requests with missing or invalid signatures receive a `403` response
- All query parameter overrides are ignored (the signed path is the single source of truth)

The signature is deterministic: the same options with the same secret always produce the same URL. This means URLs are stable across server restarts and deployments as long as the secret does not change.

### Defense in Depth

URL signing works alongside the other security options (`maxDimension`, `maxQueryParamSize`, `renderTimeout`, `restrictRuntimeImagesToOrigin`) which continue to apply as defense-in-depth. When signing is active, query parameter overrides are ignored but the query string size limit still applies to reduce parsing overhead.

<note>

Dev mode and prerendering bypass signature verification. Signing only applies to runtime requests in production.

</note>

## Prerender Your Images

The most effective security measure is to **prerender your OG images at build time** using [Zero Runtime mode](/docs/og-image/guides/zero-runtime). Prerendered images are served as static files with no runtime rendering code in your production build.

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  ogImage: {
    zeroRuntime: true
  }
})
```

When you enable zero runtime:

- Your production build includes no server-side rendering code
- The build generates images once and serves them as static assets
- The `/_og` endpoint is not available at runtime

If your OG images don't need to change dynamically after deployment, this is the recommended approach.

For sites that need a mix of static and dynamic images, you can prerender specific routes while keeping runtime generation available for others. See the [Zero Runtime guide](/docs/og-image/guides/zero-runtime) for configuration details.

## Dimension and Render Limits

Every request has its `width` and `height` clamped to `maxDimension` (default `2048` pixels). The Takumi renderer's `devicePixelRatio` is capped to `maxDpr` (default `2`).

If a render exceeds `renderTimeout` (default `15000ms`), it is aborted and the server returns a `408` status.

These are all enabled by default. You only need to configure them if you want different limits.

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  ogImage: {
    security: {
      maxDimension: 2048,
      maxDpr: 2,
      renderTimeout: 15000,
    }
  }
})
```

## Query String Size Limit

OG image options can be passed via query parameters when URL signing is not enabled. You can set `maxQueryParamSize` to reject requests with oversized query strings.

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  ogImage: {
    security: {
      maxQueryParamSize: 2048, // characters
    }
  }
})
```

Requests exceeding this limit receive a `400` response.

<note>

When URL signing is active, query parameter overrides are ignored, but this size limit still applies to reduce request parsing overhead.

</note>

If you find yourself passing large amounts of data through query parameters (titles, descriptions, full text), consider loading that data inside your OG image component instead. See the [Performance guide](/docs/og-image/guides/performance#reduce-url-size) for the recommended pattern.

## Restrict Runtime Images to Origin

When you enable runtime image generation, anyone who knows the `/_og` endpoint pattern can request an image directly. The `restrictRuntimeImagesToOrigin` option limits runtime generation to requests whose `Host` header matches your configured site URL.

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  ogImage: {
    security: {
      restrictRuntimeImagesToOrigin: true,
    }
  }
})
```

### How It Works

The module reads the `Host` header from each runtime request using h3's `getRequestHost` (with `X-Forwarded-Host` support for reverse proxies) and compares it against the host from your [Nuxt Site Config](/docs/site-config/getting-started/introduction) `url`. If the hosts don't match, the request receives a `403` response.

Because HTTP/1.1 requires the `Host` header, this check works with all clients including social media crawlers. The server does not need an `Origin` or `Referer` header.

### Allowing Additional Origins

To allow extra origins (e.g. a CDN or preview deployment), pass an array. Your site config origin is always included automatically.

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  ogImage: {
    security: {
      restrictRuntimeImagesToOrigin: ['https://cdn.example.com', 'https://preview.example.com'],
    }
  }
})
```

We **disable this option by default** to avoid surprises for sites behind non-standard proxy setups. If your reverse proxy forwards the correct `Host` or `X-Forwarded-Host` header, you can safely enable it.

<note>

Prerendering and dev mode bypass the host check entirely.

</note>

## Debug Mode Warning

Enabling `ogImage.debug` in production exposes the `/_og/debug.json` endpoint. The module will log a warning at build time if you enable debug outside of dev mode. Make sure to disable it before deploying.

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  ogImage: {
    debug: false, // never enable in production
  }
})
```
