Next.js 16.3.6: patch crítico no next/og e o que revisar na sua rota de imagem

Falha crítica no ImageResponse do next/og (CVE-2026-94545): quem é afetado, como atualizar e o padrão de código que você deve abandonar hoje.

Alessandro Melo//4 min de leitura
Next.js 16.3.6: patch crítico no next/og e o que revisar na sua rota de imagem

O que aconteceu

Hoje, 22 de setembro de 2026, o time do Next.js publicou uma atualização de segurança fora do calendário: as versões 16.3.6 e 15.5.26. O comunicado oficial explica que as duas atualizam dependências upstream, entre elas o Satori, a biblioteca que transforma JSX em SVG por baixo do ImageResponse de next/og. O advisory GHSA-vcvr-r3jv-pc5j (CVE-2026-94545) tem severidade crítica, com nota 9.5, e descreve execução remota de código.

O recorte é estreito, e isso importa. Só as versões >=16.2.0 <16.3.6 são afetadas, e só a implementação Node.js do ImageResponse. Quem gera imagem no runtime Edge está fora. O 15.x não tem a falha de execução remota: o 15.5.26 traz só endurecimento relacionado. A condição para explorar também é específica. A aplicação precisa colocar um valor controlado pelo atacante dentro do conteúdo, dos atributos ou dos estilos do SVG gerado. Um escape mal feito nesse SVG abre caminho para falhas em outras dependências.

Por que isso importa mais do que parece

Imagem de Open Graph é o tipo de código que ninguém revisa. Ela nasce num tutorial, gera aquela prévia bonita do link no LinkedIn e no WhatsApp, e fica esquecida em opengraph-image.tsx ou numa rota /api/og. O padrão mais copiado da internet é exatamente o que o advisory usa como exemplo de código vulnerável: ler ?title= da URL e desenhar esse texto na imagem.

Esse padrão já era ruim antes da falha. Qualquer pessoa consegue gerar uma imagem com o seu domínio e o texto que quiser, e ainda gasta CPU do seu servidor a cada variação. A falha só transforma um problema de reputação num problema de servidor comprometido.

Tem um segundo ponto. Muita gente trata o bump de patch do framework como tarefa de segunda-feira. Aqui o advisory e o patch saíram juntos, com o detalhe técnico público. A janela entre "saiu a correção" e "tem gente varrendo rota /api/og na internet" costuma ser curta.

Na prática

Primeiro, descubra se você está no intervalo afetado:

npm ls next

Se aparecer 16.2.x ou 16.3.0 a 16.3.5, atualize:

npm install next@16.3.6

No 15.5, atualizar para next@15.5.26 é recomendado, mas não é emergência de execução remota.

Depois, procure onde o projeto usa ImageResponse e olhe de onde vem cada valor que entra no JSX:

grep -rn "ImageResponse" app src --include=*.tsx --include=*.ts

A correção de verdade, que vale mesmo depois do patch, é não desenhar entrada do usuário. Troque o texto vindo da query string por dado que você controla, buscado pelo parâmetro da rota. No Next 16, params é uma Promise:

// app/blog/[slug]/opengraph-image.tsx
import { ImageResponse } from 'next/og'
import { getPostBySlug } from '@/lib/posts'

export const size = { width: 1200, height: 630 }
export const contentType = 'image/png'

export default async function Image({
  params,
}: {
  params: Promise<{ slug: string }>
}) {
  const { slug } = await params
  const post = await getPostBySlug(slug)

  // O slug só serve para buscar. Nunca vai para o SVG.
  if (!post) return new Response('Not found', { status: 404 })

  return new ImageResponse(
    (
      <div
        style={{
          width: '100%',
          height: '100%',
          display: 'flex',
          alignItems: 'center',
          padding: 80,
          fontSize: 64,
          background: '#0b0b0b',
          color: '#fafafa',
        }}
      >
        {post.title}
      </div>
    ),
    { ...size },
  )
}

O título sai do banco ou do markdown do próprio site, não da URL. Se o slug não existe, a rota devolve 404 em vez de desenhar qualquer coisa. getPostBySlug é a sua função de leitura, seja do banco ou do markdown. De bônus, sem API de request a imagem fica em cache, conforme a documentação, e não é redesenhada a cada acesso.

Se você não pode atualizar hoje, o próprio advisory dá o contorno: parar de passar valor controlado pelo atacante para conteúdo, atributo ou estilo do SVG. Na prática, é aplicar o exemplo acima antes do bump.

O que eu faria

Atualizaria hoje quem estiver no 16.2 ou no 16.3. O custo é um patch dentro da mesma minor, e o risco de não fazer é execução remota no servidor.

Quem está no 15.5 pode colocar o 15.5.26 no próximo deploy normal, sem correria. Mas eu aproveitaria para fazer a busca por ImageResponse do mesmo jeito. Se a rota de OG lê texto da query string, isso vira o próximo problema na hora em que o projeto subir para o 16.

E eu tiraria uma regra desse caso: gerador de imagem é renderizador, e renderizador que recebe texto de fora precisa da mesma desconfiança que um template de e-mail ou uma query SQL. A prévia do link parece enfeite, mas o código roda no seu servidor.

Fontes

  1. Fonte
Voltar para o blog