◉RORK LABEN
●GPT-6.1 SOL — Rork のモデルメニューに追加(09-29)。Low/Medium/High を選べ、Pro・Max に含まれます●SONNET 5.5 — UI づくりが得意で、Sonnet 5 より出力が速いモデルが選べます(09-28)●SDK 58 — Expo SDK 58 が 10/15 に正式リリースされました(Beta は 09/15 から)。上げる前に依存の対応状況を確認しましょう●SDK 58 ISSUE — Android ウィジェットが定期更新されない、Stripe が静的リンクになるなど初期報告が出ています●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…●GPT-6.1 SOL — Rork のモデルメニューに追加(09-29)。Low/Medium/High を選べ、Pro・Max に含まれます●SONNET 5.5 — UI づくりが得意で、Sonnet 5 より出力が速いモデルが選べます(09-28)●SDK 58 — Expo SDK 58 が 10/15 に正式リリースされました(Beta は 09/15 から)。上げる前に依存の対応状況を確認しましょう●SDK 58 ISSUE — Android ウィジェットが定期更新されない、Stripe が静的リンクになるなど初期報告が出ています●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…
記事一覧/Rork入門
◈ Rork入門/2026-10-20中級

Rork が書いたコードに鍵が直書きされていないか、40行ほどのスクリプトで一度だけ確かめます

Rork が生成したコードに API キーが書き込まれていないかを、GitHub に書き出したファイルから探す方法です。鍵の形・名前・EXPO_PUBLIC_ の3つの目印を使う Python スクリプトと、見つかったときの正しい差し替え順をまとめました。

Rork594APIキー3セキュリティ15GitHub連携Secretsコードレビュー3

More → Code を開くと、ファイルツリーの下に src/ や components/ がずらりと並びます。どこから読めばいいのか分からないまま、スクロールだけして閉じた経験が、私にもあります。

Rork のドキュメントは、鍵は Secrets に置き、コードにも会話にも貼らないようにと案内しています。その約束が守られているか、つまりコードの中に鍵が実際に入っていないかを、私たちは普段なかなか確かめられません。

最初にお伝えしたいのは、全ファイルを読む必要はない、ということです。鍵には「形」と「名前」の癖があります。そこだけを機械に探させれば、読む場所は数行に絞れます。ここからは、そのための小さなスクリプトと、見つかったときの手順を書き残します。確かめる手段がないまま「たぶん大丈夫」と思ってしまうのは、よくあることなのかもしれません。

探す前に、コードを手元に出す方法を決めます

Rork の Code タブはそのまま読めます。無料プランでは「Read-only」の表示が出て編集はできませんが、全ファイルの閲覧はできる、とドキュメントにあります。目で探すだけなら、ここで足ります。

スクリプトで探すなら、GitHub 連携でコードを手元に置くのが近道です。ドキュメントによれば、連携するとコードは通常のリポジトリになり、エージェントの1ターンにつき1コミットで積み上がります。clone して、そのフォルダにスクリプトを向ければ準備は終わりです。

ひとつ、安心材料があります。Secrets に入れた値は、コードとは別にプロジェクトに保管され、コミットには含まれないとドキュメントの FAQ に書かれています。逆に言えば、GitHub 側のコードに鍵が見つかったなら、それは Secrets を通らずにコードへ書かれた鍵です。

鍵が紛れ込むときの目印は、3つに分けられます

私が探しているのは、次の3種類です。

目印探し方見つかる例
鍵そのものの形プロバイダごとの接頭辞(sk-、sk_live_、AIza、ghp_ など)OpenAI 互換、Stripe 秘密鍵、GitHub トークン
名前が秘密らしい変数への直代入SECRET・TOKEN・API_KEY を含む名前に、16 文字以上の文字列を直接代入している行天気 API のキーを定数に書いた行
EXPO_PUBLIC_ を付けた秘密EXPO_PUBLIC_ のあとに SECRET・SERVICE_ROLE などが続く名前Supabase の service role キーを公開名で読んでいる行

3つ目は、ドキュメントの警告に直結します。EXPO_PUBLIC_ で始まる変数はアプリ本体に送られ、それ以外はサーバー側に留まる、というのが Rork の決まりです。秘密の鍵にこの接頭辞を付けた時点で、アプリを入れた人なら誰でも取り出せる場所に置いたことになります。

スクリプト本体です

Python 3 の標準ライブラリだけで動きます。拡張子は .ts、.tsx、.js、.swift、.kt、.plist などを見ます。

#!/usr/bin/env python3
"""GitHub に書き出した Rork のコードから、鍵の直書きを探す。"""
import re, sys, pathlib
 
SKIP_DIRS = {"node_modules", ".git", "Pods", "build", "dist", ".expo"}
EXTS = {".ts", ".tsx", ".js", ".jsx", ".json", ".swift", ".kt", ".env", ".plist", ".md"}
 
# 1) 鍵そのものの「形」
SHAPES = {
    "OpenAI/互換 sk-":  re.compile(r"\bsk-[A-Za-z0-9_-]{20,}"),
    "Stripe 秘密鍵":    re.compile(r"\b[sr]k_(live|test)_[A-Za-z0-9]{16,}"),
    "Google API キー":  re.compile(r"\bAIza[0-9A-Za-z_-]{35}\b"),
    "GitHub トークン":  re.compile(r"\bgh[pousr]_[A-Za-z0-9]{36,}"),
    "Resend":           re.compile(r"\bre_[A-Za-z0-9]{20,}"),
}
# 2) 秘密っぽい名前に、長い文字列を直接代入している
ASSIGN = re.compile(
    r"""(?i)\b([A-Z0-9_]*(SECRET|TOKEN|PRIVATE|SERVICE_ROLE|API_?KEY)[A-Z0-9_]*)\b\s*[:=]\s*["']([^"'\s]{16,})["']"""
)
# 3) 公開される接頭辞に、秘密っぽい名前を付けている
PUBLIC_SECRET = re.compile(
    r"(?i)\bEXPO_PUBLIC_[A-Z0-9_]*(SECRET|PRIVATE|SERVICE_ROLE|TOKEN)[A-Z0-9_]*"
)
 
def walk(root):
    for p in root.rglob("*"):
        if p.is_file() and p.suffix in EXTS and not any(s in p.parts for s in SKIP_DIRS):
            yield p
 
hits = 0
for path in walk(pathlib.Path(sys.argv[1] if len(sys.argv) > 1 else ".")):
    for n, line in enumerate(path.read_text(errors="ignore").splitlines(), 1):
        found = [name for name, rx in SHAPES.items() if rx.search(line)]
        if ASSIGN.search(line) and "process.env" not in line:
            found.append("秘密っぽい名前に値を直書き")
        if PUBLIC_SECRET.search(line):
            found.append("EXPO_PUBLIC_ に秘密っぽい名前")
        for f in found:
            hits += 1
            print(f"{path}:{n}: [{f}]")   # 行の中身は出さない
print(f"-- {hits} 件")
sys.exit(1 if hits else 0)

print で出すのは、ファイル名・行番号・種類だけです。行の中身は意図して出していません。画面共有や、ログを Rork のチャットに貼る場面で、鍵そのものを二次的に漏らしたくないからです。

使い方は clone したフォルダで次のように実行するだけです。

python3 scan_keys.py ./my-rork-project

手元のサンプルで動かした結果です

本物の鍵は使えませんので、形だけ似せた偽の値で小さなプロジェクトを作り、動かしました。天気 API のキーを定数に書いたファイル、apiKey に sk- 形式の文字列を入れたファイル、EXPO_PUBLIC_SERVICE_ROLE_KEY を読むファイル、Firebase の設定 JSON、そして問題のないファイルを一つずつ用意しています。

出力はこうなりました。

demo/src/weather.ts:1: [秘密っぽい名前に値を直書き]
demo/src/ai.ts:1: [OpenAI/互換 sk-]
demo/src/ai.ts:1: [秘密っぽい名前に値を直書き]
demo/src/ai.ts:3: [EXPO_PUBLIC_ に秘密っぽい名前]
demo/config/firebase.json:1: [Google API キー]
-- 5 件

読み取れることが三つあります。まず、process.env.RESEND_API_KEY のように環境変数を読んでいるだけの行と、TOKEN_REFRESH_SECONDS = 3600 のような設定値は、どちらも引っかかりませんでした。次に、ai.ts の1行目は2種類の目印に同時に当たっています。同じ行が複数回数えられるのは、仕様です。そして最後が、いちばん大事な点です。

Firebase の設定ファイルに出る警告は、慌てなくて大丈夫です

上の結果の最後、firebase.json の1件は、本物の漏えいではありません。Firebase の設定に入っている API キーは、Google のドキュメントでも一般的な秘密鍵とは性質が違うものとして説明されています。アプリに同梱されて配られる前提の識別子で、守りはキー自体ではなく、Firebase 側のセキュリティルールや制限設定にあります。

個人開発で運用している私の iOS アプリでも、GoogleService-Info.plist に API キーの欄があります。スクリプトに .plist を含めたのは網羅のためですが、そこで当たる分は、誤検知として読み飛ばしています。

要するに、スクリプトの出力は「疑う順番の一覧」であって、「漏えいの確定通知」ではありません。1件ずつ、次の問いで仕分けます。

  • その値は、アプリを入れた人に見えても困らないものか(公開前提の識別子か)
  • 見えると困るなら、誰が使うと請求や被害が起きるか
  • いま使える鍵か、すでに失効した鍵か

本物が見つかったときは、順番がすべてです

ここで間違えやすいのが、Rork の画面でコードの鍵を消して終わりにしてしまうことです。ドキュメントには、鍵が公開された場所に出たときの手順が4段階で書かれています。

  1. 提供元のダッシュボードで、その鍵を失効またはローテーションします。実際に鍵を使えなくするのは、ここだけです。
  2. 新しい鍵を作って、値を控えます。
  3. Rork の Secrets で、同じ変数名に新しい値を入れて Save します。
  4. コードに鍵が書かれていた場合は、Rork に頼んで鍵を取り除き、変数から読むように直してもらいます。

順番を逆にして、先にコードだけ直すと、GitHub の履歴にはもとの鍵が残ったままです。履歴に残った値は、コードを直しても使えます。止めるのは、必ず提供元での失効が先です。

直すときの依頼文は、場所と置き場所をはっきり書くと通りやすくなります。

src/ai.ts の1行目に API キーが直接書かれています。
その行を削除して、サーバー関数から OPENAI_API_KEY を読む形に直してください。
EXPO_PUBLIC_ の名前は使わないでください。

鍵をどこに置くのが正しいかは、環境変数と Edge Function の使い分けとして別にまとめています。置き場所の線引きはこちらの記事をご覧ください(そのAPIキー、アプリの中に入っていませんか)。

今日の一手

置き場所は決めたら終わりではなく、確かめて初めて決まります。 公開の前と、大きな機能を足した日の終わりに、このスクリプトを一度走らせます。それだけを、まず習慣にしていただければと思います。

件数がゼロでも、それは「目印にかからなかった」というだけで、安全の保証ではありません。それでも、数十ファイルを目で追うより、はるかに少ない手間で、いちばん多い失敗を先に拾えます。

鍵をサーバー側に置いたあと、アプリからの申告を信じすぎないことも、同じくらい大切です。リワード広告の報酬を端末からの合図だけで配らない設計は、有料記事にまとめています(リワード広告の報酬を、端末からの合図だけで配らない)。

シェア

お読みいただきありがとうございます

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

◈ Rork 入門2026-10-19
plugins に何も書いていないのに、Info.plist に権限の説明文が 9 件並んでいました
app.json の plugins が空でも、入れたパッケージの分だけ Info.plist に権限の説明文が出ます。Expo SDK 58 で prebuild して数え、外す設定と点検スクリプトを実測つきでまとめます。
◈ Rork 入門2026-10-17
Expo SDK 58 に上げる前に、自分のコードで消える API を一覧にしておく
Expo SDK 58 の変更履歴から、削除・挙動変更・非推奨の API を拾って自分のプロジェクトを走査する検査スクリプトを書きました。試験プロジェクトでの実行結果と、走らせて初めて気づいた落とし穴つきで書き残します。
◈ Rork 入門2026-10-16
Play Console の提出ボタンが押せない夜 — リリースノートは1言語500文字でした
Google Play のリリースノートは1言語あたり500文字までです。長い更新メモをそのまま貼って提出が止まった経験から、短い版の作り方と、下書きリリースが残っているときの進め方をまとめました。