
Next.js Vercelで「AI APIキー」を漏らさない構成と、漏れたときの初動
AIのAPIキーが漏れると、他人があなたのアカウントでAPIを呼べてしまいます。Claude APIでも、第三者による不正利用と、それに伴う課金につながると公式のサポート記事で説明されています。
2025年12月には、ReactのServer Componentsに、認証なしでリモートからコードを実行できる重大な脆弱性(CVE-2025-55182、通称React2Shell)が公表されました。Next.jsのApp Routerでは、同じ問題がCVE-2025-66478として扱われました。サーバー側の環境変数に入れていれば安全、とは言い切れなくなった出来事です。
この記事は、運用を見直す中で調べた内容を、公式の情報をもとに整理したものです。例はClaude APIとNext.js + Vercelですが、他社のAPIキーでも考え方は同じです。
2026年10月16日 追記: Vercelの環境変数の区分が変わりました
「Sensitive」は「Config / Secret」の区分に: 本文の「Vercelでは「Sensitive」にする」の節は公開時点の内容です。現在の公式ドキュメントでは、環境変数は Config と Secret の2種類で、APIキーやトークンは Secret にします。Secret は保存後に値を読み出せません。既存の Sensitive の変数は、Secret として引き続き動きます。
Development でも使える: 本文では「作れるのは Preview と Production の環境変数」と書きましたが、現在は Secret を Development でも使えます(以前の制限はなくなりました)。
チームのポリシー: すべての変数を Sensitive にさせる「Enforce Sensitive Environment Variables」は廃止予定(deprecated)で、「Separate Production Secret Values」に置き換えられています。
関連記事
出典: Vercel Docs「Config and Secret environment variables」 https://vercel.com/docs/environment-variables/sensitive-environment-variables(2026年10月16日に確認)。最新は公式ドキュメントで確認してください。
この記事が関係する人・関係しない人
関係する人
Next.js(Vercel など)のアプリから、Claude API などAIのAPIキーを使っている人
APIキーを環境変数で管理していて、NEXT_PUBLIC_ の扱いや、漏れたときの手順を確認したい人
App Router を使う Next.js 15.x・16.x、または 14.3.0-canary.77 以降の canary 版を使っている人(React2Shell の対象)
関係しない人
React2Shell(CVE-2025-66478)の節は、Next.js 13.x、14.x の安定版、Pages Router のアプリ、Edge Runtime は対象外です(APIキーの管理の節は、バージョンに関係なく当てはまります)
自分が当てはまるかの確認方法
React2Shell の対象バージョンかどうかは、Next.js 公式アドバイザリーが案内している次のツールで確認できます(必要ならバージョンの更新も行えます)
npx fix-react2shell-nextAPIキーが漏れる主な経路
1. Gitに入る
コードや設定ファイルにキーを書いて、そのままコミットしてしまうパターンです。AnthropicはGitHubのシークレットスキャンと連携していて、公開リポジトリでClaudeのAPIキーが見つかると、Anthropic側でキーが自動的に無効化されます。ただし対象は公開リポジトリなので、ログ、スクリーンショット、チャットなど、それ以外の経路は自分で防ぐ必要があります。
2. ブラウザに配られるJavaScriptに入る
Next.jsでは、NEXT_PUBLIC_ を付けた環境変数は、ビルド時にブラウザへ配るJavaScriptの中に値が埋め込まれます。付けていない環境変数は、Node.js側(サーバー)でだけ使えます。APIキーに NEXT_PUBLIC_ を付けると、誰でもブラウザから読めるようになります。
Non-NEXT_PUBLIC_ environment variables are only available in the Node.js environment, meaning they aren't accessible to the browser (the client runs in a different environment).
訳: NEXT_PUBLIC_ が付いていない環境変数は Node.js の環境でだけ使え、ブラウザからはアクセスできません(クライアントは別の環境で動くためです)。(How to use environment variables in Next.js)
3. サーバー自体が侵害される
React2Shellのような脆弱性で、サーバー上でコードを実行されると、サーバー側の環境変数も読み取られる可能性があります。Next.jsの公式アドバイザリーでも、パッチを当てて再デプロイしたあとに、アプリが使うシークレットをすべてローテーションすることを勧めています。特に、2025年12月4日午後1時(PT)の時点でオンラインかつ未パッチだった場合は、重要なものから順に入れ替えるよう案内されています。
If your application was online and unpatched as of December 4th, 2025 at 1:00 PM PT, we strongly encourage you to rotate any secrets it uses, starting with your most critical ones.
訳: 2025年12月4日午後1時(PT)の時点でアプリケーションがオンラインかつ未パッチだった場合は、使っているシークレットを、最も重要なものから順にすべてローテーションすることを強く勧めます。(Security Advisory: CVE-2025-66478)
4. 管理画面や運用の中で見えてしまう
環境変数の値が、ダッシュボードやCLIからあとで読み出せる状態だと、アカウントの権限が奪われたときに一緒に漏れます。
5. ログ・スクリーンショット・チャットに貼る
Anthropicのサポート記事は、APIキーを他人と共有しないことを基本に挙げています。デバッグ中にログやスクリーンショットへうっかり載せるのも、結果としては共有したのと同じです。
対策
キーはサーバー側のRoute Handlerだけで使う
ブラウザからはAPIを直接呼ばず、自分のRoute Handlerを経由します。キーはサーバーの環境変数に置き、NEXT_PUBLIC_ は付けません。
# .env.local(Gitには入れない)
ANTHROPIC_API_KEY=sk-ant-xxxxxxxx
# NG: ブラウザに配られてしまう
# NEXT_PUBLIC_ANTHROPIC_API_KEY=sk-ant-xxxxxxxx// app/api/chat/route.ts
import Anthropic from "@anthropic-ai/sdk";
import { NextResponse } from "next/server";
const client = new Anthropic(); // 環境変数 ANTHROPIC_API_KEY を読む
export async function POST(req: Request) {
// ここで認証と、ユーザーごとの利用回数の上限チェックを行う
const { prompt } = await req.json();
const message = await client.messages.create({
model: "claude-sonnet-5-5", // 使うモデルIDに置き換える
max_tokens: 1000,
messages: [{ role: "user", content: prompt }],
});
return NextResponse.json({ message });
}Route Handlerに認証や利用回数の制限がないと、キーが見えなくても、誰でもこのAPIを叩いて課金させられます。キーを隠すことと、APIを守ることは別の話です。

Vercelでは「Sensitive」にする
Vercelの環境変数は、Sensitiveにすると、作成後は値を読み出せなくなります。APIキーのような値向けの機能で、プロジェクトの環境変数でもチーム共有の環境変数でも使えます。作れるのはPreviewとProductionの環境変数です。既存の変数をSensitiveにするには、削除して、Sensitiveを有効にして作り直します。チームの設定で、新規の環境変数をSensitiveに強制することもできます。
キーを分けて、上限と期限をつける
キーを分ける: 環境(開発・本番)や用途ごとに別のキーにします。漏れたときに、そのキーだけを止められます。ClaudeのConsoleでは、ワークスペースごとにキーを分けられます。
上限を設定する: Anthropicのサポート記事では、組織の種別に応じて、利用額の上限や自動チャージの設定を行うよう案内されています。
有効期限を付ける: キーの作成時に有効期限を設定でき、漏れた資格情報が使える期間を短くできます。ただし、期限を付けても、キーの管理そのものの代わりにはなりません。
定期的にローテーションする: 侵害されたときに、その用途だけを止めて被害を抑えられます。
シークレットスキャンをCIに入れる
Anthropicのサポート記事は、CI/CDのパイプラインにシークレットスキャンを組み込んで、メインブランチに入る前に検出することを勧めています。コミット前にスキャンするツール(git-secrets、trufflehogなど)もあります。
Next.js / React を更新し続ける
React2Shellは、回避策がなく、パッチ版へのアップデートが必要でした。Next.jsの公式アドバイザリーによると、影響を受けたのは、App Routerを使う15.xと16.x(14.3.0のcanary以降を含む)で、13.x、14.xの安定版、Pages Router、Edge Runtimeは対象外とされています。修正版は、15.0.5、15.1.9、15.2.6、15.3.6、15.4.8、15.5.7、16.0.7です。自分のバージョンが該当するかは、npx fix-react2shell-next で確認できます。
Next.js 13.x, Next.js 14.x stable, Pages Router applications, and the Edge Runtime are not affected.
訳: Next.js 13.x、Next.js 14.x の安定版、Pages Router のアプリケーション、Edge Runtime は影響を受けません。(Security Advisory: CVE-2025-66478)
保管場所をどうするか
Anthropicのドキュメントは、APIキーをシークレットマネージャーに保管し、定期的にローテーションし、漏れた疑いがあれば無効化または削除することを勧めています。Vercelの環境変数のまま(Sensitive)にするか、外部のシークレットマネージャーに移すかは、運用の手間と、守りたい範囲で決めることになります。
漏れたときの初動
キーを無効化する: Consoleで、漏れた(疑いのある)キーを削除または無効化します。
新しいキーを発行して差し替える: 環境変数を更新して、再デプロイします。Vercelの公式ドキュメントによると、環境変数の変更は新しいデプロイにだけ反映され、過去のデプロイは古い値のままです。キーを無効化したあとは、古い値のままのデプロイ(Previewを含む)がエラーになるので、そのキーを使っているデプロイはすべて再デプロイします。
使用量を確認する: 利用履歴や請求に、身に覚えのない使われ方がないかを見ます。
原因をたどる: Gitの履歴、フロントエンドのバンドル、ログ、スクリーンショットを確認します。
フレームワークが未パッチなら更新する: アップデートしたうえで、ほかのシークレットも入れ替えます。

まとめ
APIキーは NEXT_PUBLIC_ を付けず、Route Handlerの中だけで使う
Route Handler自体にも、認証と利用回数の制限を入れる
VercelではSensitiveにして、キーは環境・用途ごとに分け、上限と期限をつける
シークレットスキャンをCIに入れて、Next.js / Reactは更新し続ける
漏れたら、無効化 → 差し替え → 再デプロイ → 使用量の確認 → 原因調査の順に動く
出典: Next.js「Security Advisory: CVE-2025-66478」、Next.js「How to use environment variables in Next.js」、Vercel「Sensitive environment variables」「Managing environment variables」「Rotating environment variables」、Anthropic「API Key Best Practices」(サポート記事)、Claude Platform Docs(認証)。仕様や対象バージョンは更新されるので、最新の内容は各公式ページで確認してください。
開発ツールの仕様変更・提供終了の情報を毎朝お届けしています。見逃したくない方は、フォローしてください。