2026-04-21 / セキュリティ緊急対応

セキュリティ手動確認ガイド

一覧へ

このガイドの使い方

2026年4月19日、Vercel と Context.ai のOAuth連携で情報漏洩事件が公表されました。 こーすけさんの環境(Next.js + Supabase + Vercel)は同じ構成のため、自動では確認できない7項目を手動チェックする必要があります。

このページは初心者でも迷わないよう、画面イメージと「押すべきボタン」をSVGで図示しています。 上から順番にやればOK。所要時間の目安も書いています。

⏱ 所要時間の目安
  • ✅ 全体: 30〜45分
  • 🔴 最優先3項目(鍵漏洩確認+Supabase Reset): 10分
  • 🟠 デプロイ保護強化: 15分
  • 🟡 設計相談が必要なもの: 後日

📋 チェックリスト

  1. ① 🔴 posture-* の .env.example に鍵が入っていないか目視確認(3分)
  2. ② 🔴 【①で該当あり時のみ】Supabase で鍵をリセット(5分)
  3. ③ 🔴 Google Workspace で侵害OAuthアプリを検索(5分)
  4. ④ 🟠 Vercel の環境変数を「Sensitive」化(10分)
  5. ⑤ 🟠 Vercel の Deployment Protection を強化(5分)
  6. ⑥ 🟡 drawing-cognitive-test の Firebase APIキー制限(5分)
  7. ⑦ 🟡 bento_order_web の GASトークン改修(要設計相談)
1
🔴 最優先・3分

posture-* の .env.example に鍵が入っていないか目視確認

❓ なぜ確認が必要?

.env.example は「環境変数の書き方サンプル」ファイルで、普通は 値を空にして配布します。 ところがこの2ファイルに eyJhbGci... というSupabaseのJWT(パスワードのようなもの)が書かれている可能性があります。 もし完全な形で書かれていたら、GitHubに上がった時点で世界中に公開されています。

手順

1. VS Code で2つのファイルを開く
saas/posture-corporate/.env.example
saas/posture-personal/.env.example
2. 中身のパターンを見分ける
✅ 安全パターン # Supabase接続情報 NEXT_PUBLIC_SUPABASE_URL= NEXT_PUBLIC_SUPABASE_ANON_KEY= SUPABASE_SERVICE_ROLE_KEY= ↑ イコールの右側が空 もしくは「your-key-here」 のようなプレースホルダ → 何もしなくてOK 🚨 漏洩パターン # Supabase接続情報 NEXT_PUBLIC_SUPABASE_URL= NEXT_PUBLIC_SUPABASE_ANON_KEY= eyJhbGciOiJIUzI1NiIsInR5cCI6I... SUPABASE_SERVICE_ROLE_KEY= eyJhbGciOiJIUzI1NiIsInR5cCI6I... ↑ 長い文字列(200〜400文字) 3つのブロックが ドット「.」で区切られている → STEP 2 へ(鍵リセット)
💡 判別のコツ

= の後ろに 100文字以上の長い文字列があり、ドット「.」で2か所区切られているならJWT本体です。 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 だけ(36文字)で終わっていれば安全(これはヘッダー部分のみ)。

2
🔴 ①で漏洩ありの場合のみ・5分

Supabase で漏れた鍵をリセット

❓ なぜリセット?

Supabase の service_role キーは管理者全権限を持っています。 もし漏れていたら、誰でも全患者データを読み書き・削除可能。即座に無効化して新しい鍵に差し替えます。

手順

1. Supabase Dashboard を開く
https://supabase.com/dashboard
2. 左サイドバーから [Project Settings] → [API] をクリック
https://supabase.com/dashboard/project/xxxx/settings/api Supabase Table Editor SQL Editor Authentication Storage ⚙ Project Settings ← ① ここをクリック General API ← ② API をクリック
3. [Project API keys] セクションで [Reset service_role key] を押す
Project API keys これらの鍵はサーバー側でのみ使用してください anon public eyJhbGciOiJIUzI1NiIs... [Reveal] クライアント側で使用OK service_role secret 🔒 eyJhbGciOiJIUzI1NiIs... [Reveal] ⚠ この鍵はRLSを完全にバイパスします Reset service_role key ← ここを押す
⚠️ 重要

Resetを押した瞬間から、古い鍵を使っているすべてのサーバー処理が止まります(=エラー500が出る)。 本番稼働中のプロジェクトなら、Vercelの環境変数を新しい鍵に差し替えるまで10分程度のメンテナンス時間になります。

4. 新しい鍵を Vercel の環境変数に貼り直す

Vercel Dashboard → 該当プロジェクト → Settings → Environment Variables で SUPABASE_SERVICE_ROLE_KEY を編集 → Save → Redeploy。

5. .env.example の該当行を「空」に戻してコミット
SUPABASE_SERVICE_ROLE_KEY=# Supabase dashboard → Settings → API

git add .env.example && git commit -m "chore: mask leaked example keys"

3
🔴 最優先・5分

Google Workspace で侵害OAuthアプリを検索

❓ なぜこの検索?

2026年4月19日に公表された Vercel の情報漏洩事件で、Context.ai という会社のGoogle OAuthアプリが攻撃に使われました。 もし過去にこのアプリへ「Allow All」で許可を出していると、Gmail/Drive/カレンダーが読まれた可能性があります。 医療法人・full-lafu の両方のWorkspaceで確認する必要があります。

手順

1. Google Workspace 管理コンソールを開く
https://admin.google.com

※ 特権管理者アカウントでログイン

2. [セキュリティ] → [アクセスとデータ管理] → [APIの制御] へ移動
Google Admin 🛡 セキュリティ アクセスとデータ管理 APIの制御 ↓ すると、下のような画面が開きます APIの制御 サードパーティ製アプリのアクセスを管理 個別のアプリのアクセスを表示・制限する ↑ このカードをクリック
3. 検索ボックスに以下を1つずつ貼り付ける
110671459871-30f1spbu0hptbs60cb4vsmv79i7bbvqj
Context.ai
context.ai
✅ ヒットしなかった場合

何もしなくてOK。医療法人とfull-lafuの両方で同じ検索を行ってください。両方クリアなら完了。

🚨 ヒットした場合(緊急)
  1. 該当アプリの右側メニューから 「アクセスをブロック」を選ぶ
  2. 許可したユーザーを特定(メールアドレス)
  3. Google Workspace の [レポート] → [監査と調査] → [Drive] で過去180日の操作ログを確認
  4. 該当ユーザーのパスワードリセット+2段階認証再設定
  5. 個人情報へのアクセスがあれば、個人情報保護委員会への報告要否を検討
4
🟠 重要・10分

Vercel の環境変数を「Sensitive」化

❓ Sensitiveって何?

Vercel の環境変数には 「Plain(平文)」「Sensitive(暗号化)」の2種類があります。 Sensitiveにすると:

  • Vercel ダッシュボードでも値が表示されない(鍵アイコン)
  • API経由でも読み出せない(書き込みのみ)
  • 今回のContext.ai事件で漏れたのはPlainの変数のみでした

手順(プロジェクトごとに実施)

1. 対象プロジェクトを開く

医療データを扱う以下を優先:

  • endai-system
  • visitcare
  • e-sign
  • posture-corporate / posture-personal
  • revenue-attribution
  • editorial-manager
2. Settings → Environment Variables を開く
▲ Vercel / endai-system Overview Deployments Analytics Settings Environment Variables Key Value Type 操作 SUPABASE_SERVICE_ROLE_KEY eyJhbGci... Plain Edit ANTHROPIC_API_KEY 🔒 Encrypted 🔒 Sensitive Edit ↑ 「Plain」表示の変数を全て Edit → Sensitive に変更 ※ NEXT_PUBLIC_ で始まる変数は Plain のままでOK(クライアントに公開される前提のため) ※ ただし NEXT_PUBLIC_ に鍵が入っていないことは必ず確認 💡 変更後は「Deployments」タブで最新デプロイを [...] → Redeploy する必要があります
3. 編集ダイアログで「Sensitive」にチェック

Edit ボタンを押すとダイアログが出るので、値はそのまま、「Sensitive」のトグルをONにして Save。 ※ 一度Sensitiveにすると値を読み出せなくなるので、値をメモしておきたい場合は先にコピーしておく。

⚠️ 危険な変数名の例

以下のどれかに「NEXT_PUBLIC_」が付いていたら即座に修正(値をサーバー側変数へ移す):

  • NEXT_PUBLIC_*_SECRET
  • NEXT_PUBLIC_*_TOKEN
  • NEXT_PUBLIC_*_SERVICE_ROLE
  • NEXT_PUBLIC_ADMIN_*

NEXT_PUBLIC_FIREBASE_API_KEY は Firebase の設計上OK(公開前提)

5
🟠 重要・5分

Vercel の Deployment Protection を強化

❓ なぜ必要?

Vercel は本番以外に Preview デプロイ(プルリクごとに発行されるURL)を自動生成します。 デフォルトではURLを知っていれば誰でも見られるため、開発中の医療データが外部から覗ける状態になりがち。 パスワード or SSO を必須にすれば、URLが漏れても中身は守られます。

手順

1. 各プロジェクトの Settings → Deployment Protection を開く
Deployment Protection このプロジェクトのデプロイメントへのアクセスを制限 Disabled(保護なし) URLを知っていれば誰でもアクセス可能 — 医療データには不適切 ✅ Standard Protection(推奨) Preview とブランチデプロイに Vercel ログインを要求(Teamメンバーのみ) ← 選択 Advanced Protection(Pro plan) すべてのデプロイ(本番含む)にパスワード要求も可能 Save
💡 ポイント

Standard Protection は無料プランでも使えます。これだけで Preview 経由の情報漏洩リスクは大幅に下がります。 本番URL(カスタムドメイン)はそのまま公開アクセス可能なので、顧客の利便性は下がりません。

6
🟡 中優先・5分

drawing-cognitive-test の Firebase APIキー制限

❓ なぜ必要?

Firebase の API Key(AIza...)は設計上 クライアント(ブラウザ)に露出する前提なので、git履歴に残っても致命的ではありません。 ただし 制限なしで放置すると、第三者がそのキーを使って Firestore 読み込みや Cloud Functions 呼び出しを試みる可能性があります。 GCP Console で「このキーは特定のウェブサイトからのみ使える」と制限すれば安全です。

手順

1. GCP Console の認証情報を開く
https://console.cloud.google.com/apis/credentials

※ Firebase プロジェクトに対応するGCPプロジェクトを選択

2. 対象のAPIキーを編集
API キーの編集 アプリケーションの制限 なし HTTP リファラー(ウェブサイト) ← これ IP アドレス Android アプリ / iOS アプリ ウェブサイトの制限(追加するリファラー) https://drawing-cognitive-test.web.app/*
3. 追加すべきリファラー
https://drawing-cognitive-test.web.app/*
https://drawing-cognitive-test.firebaseapp.com/*
http://localhost:5173/*

※ 最後のは開発用。本番公開後は削除してもOK

4. APIの制限

同じ編集画面の下部で「キーを制限」を選び、以下のみにチェック:

  • Firebase Installations API
  • Token Service API
  • Cloud Firestore API(使っている場合)
  • Identity Toolkit API(Auth使用時)
5. Firebase App Check の有効化(追加推奨)
https://console.firebase.google.com

→ 左サイドバー [App Check] → reCAPTCHA v3 or Enterprise で有効化

7
🟡 後日・要設計相談

bento_order_web の GASトークン改修

❓ 何が問題?

bento_order_web は Google Apps Script (GAS) でスプレッドシートに書き込んでおり、 その認証に VITE_GAS_AUTH_TOKEN という共有トークンを使っています。 VITE_ プレフィックスはクライアントのビルドに埋め込まれるため、 ブラウザの DevTools を開くと誰でも値が読めてしまいます。 さらにGAS側も !GAS_AUTH_TOKEN なら検証スキップする実装のため、空値のままでも動いてしまう設計。

改修方針(3択)

A案: Firebase Auth ID Token 検証(おすすめ)

ユーザーがログイン済みなら Firebase が発行する ID Token を取得し、 GAS 側で Firebase の JWT を検証する。既にFirebase認証を使っているので実装追加コストが少ない。

B案: Cloudflare Worker 経由プロキシ

クライアント → Cloudflare Worker → GAS の構造にし、 認証トークンは Worker に置く。クライアントから見えなくなる。

C案: 現状維持(社内のみ・Tailscale内)

アプリが社内ネットワーク限定で使われており、一般公開されていないなら現状維持も選択肢。 ただし「社内スタッフがDevToolsで鍵を見られる」リスクは残る。

💬 次の一手

Claude Code に「bento_order_web の VITE_GAS_AUTH_TOKEN を A案(Firebase Auth ID Token)で改修するプラン出して」と相談するのが最短。 所要時間の見積もり:実装2〜3時間、テスト1時間程度。

✅ すべて完了したら

  1. Claude Code で /security-check を再度実行して仕上げ確認
  2. ~/work/SECURITY.md の §8 インシデント履歴に対応結果を追記
  3. 次回は月1回(毎月第1月曜朝)の /morning でOAuth棚卸しを自動化
🎯 これで守れるもの
  • Vercel x Context.ai と同種のサプライチェーン攻撃
  • Preview URL 経由の情報漏洩
  • OAuth アプリ経由の Gmail/Drive 情報漏洩
  • git 履歴に残った鍵の悪用