ZeroTool Workbench
シークレットマスキング
ログ・コード・.env・docker-compose に含まれる API キー、JWT、秘密鍵、DB パスワードをブラウザ内で検出・置換。AI の返答はプレースホルダーから元の値へ復元。アップロードなし。
使い方
- 相談したいログ、スタックトレース、
.env、設定ファイルを ① 欄に貼り付けます。入力と同時に検出が走ります。 - カテゴリ切り替えの件数を確認し、検出一覧を開いて一致した内容を見ます。シークレットでないものを拾うカテゴリはオフにします。
- ② 欄のマスキング済みテキストをコピーし、ChatGPT や Claude などのアシスタントに貼り付けます。
- 返ってきた回答を ③ 欄に貼ると、残っていたプレースホルダーが実際の値に戻り、そのままターミナルやエディターにコピーできます。
復元が終わるまで ① 欄は変更しないでください。プレースホルダーと値の対応表は、このテキストが変わるたびに作り直され、ほかのどこにも記録されません。
置換される対象
| カテゴリ | 例 | 見えたまま残る部分 |
|---|---|---|
| AI プロバイダーキー | sk-ant-…、sk-proj-…、hf_…、DeepSeek・OpenRouter・Moonshot などの sk- キー | 変数名 |
| クラウド・SaaS トークン | AKIA… と対になる AWS シークレット、AIza…、ghp_…、github_pat_…、glpat-…、xoxb-…、Slack Webhook URL、sk_live_…、whsec_…、SendGrid、npm、PyPI、Telegram Bot トークン | 変数名。Stripe の公開用 pk_ キーは Stripe ルールの対象外 |
| JWT・認証ヘッダー | eyJ….eyJ….…、Authorization: Basic …、Bearer … | ヘッダー名と認証方式 |
| 秘密鍵 | -----BEGIN … PRIVATE KEY----- から対応する END 行までの PEM ブロック(RSA、EC、OpenSSH、PGP、暗号化鍵) | なし。ブロック全体が 1 つのプレースホルダーになります |
| パスワード・接続文字列 | postgres://app:…@db、DB_PASSWORD=…、client_secret: …、?api_key=… | ユーザー名、ホスト、ポート、DB 名 |
| 高エントロピー文字列 | 変数名のない 32 文字以上のランダム文字列 | 周囲のテキストすべて |
変数名で判定するルールは、名前がキーワードで終わる場合だけ一致します。そのため max_tokens: 1024 や token_count=12 は置換されません。${DB_PASS} のような環境変数参照、<your-key> のようなテンプレート、**** のような伏せ字、true や null などのリテラルも対象外です。
高エントロピー判定の仕組み
base64 / base64url の文字が 32 文字以上続く部分が候補になります。大文字・小文字・数字をすべて含み、シャノンエントロピーが 1 文字あたり 4.2 ビットに達したものだけを置換します。同じ長さのランダムな base64 は平均で約 4.56 ビットです。
「大文字・小文字・数字の混在」という条件が CI ログの読みやすさを守ります。git のコミット SHA、MD5・SHA-256 ダイジェスト、Docker イメージのダイジェスト、UUID はいずれも 16 進数か単一ケースなので該当しません。lockfile の sha512-… 整合性ハッシュ、data: URI、ファイルパス、証明書や公開鍵の本文はもともと公開情報なので、明示的に除外しています。
これは意図的なトレードオフです。変数名が隣にない 32 文字の 16 進トークンは、この判定では拾えません。TWILIO_AUTH_TOKEN=… のように名前が付いていれば、パスワードルールが拾います。
プレースホルダーのルール
- 形式は
[種別_番号]です([OPENAI_KEY_1]、[URL_PASSWORD_1]、[SECRET_2])。種別名によって AI は値を見ずに何の値かを把握でき、「[AWS_ACCESS_KEY_1]をローテーションしてください」といった回答が成り立ちます。 - 同じ値には常に同じプレースホルダーが付きます。20 回出現しても、2 つのルールに一致しても同じです。
- 番号は種別ごとに振られ、元のテキストにすでにあるプレースホルダーは飛ばします。貼り付けた
[SECRET_1]が生成されたものと衝突することはありません。 - マスキング済みのテキストをもう一度処理しても、結果は変わりません。
- 復元では
[OPENAI_KEY_1]、\[OPENAI_KEY_1\]、[openai_key_1]、[ OPENAI_KEY_1 ]、インラインコード内のプレースホルダーを受け付けます。角括弧のないOPENAI_KEY_1は環境変数名と区別できないため対象外です。 - 返答に含まれていても対応表にないプレースホルダー(AI が作り出したものなど)はそのまま残し、復元欄の下に一覧表示します。
対応範囲
| このツールでは行わないこと | 代わりの方法 |
|---|---|
| ファイル・フォルダ・git 履歴の走査 | ローカルで gitleaks git / gitleaks dir または trufflehog を実行 |
| 個人情報(メール、氏名、電話番号、IP アドレス、ホスト名) | 手作業で編集。接続文字列のホスト名は、AI が設定を読み解けるようあえて残しています |
| 誤検出 1 件だけの取り消し | そのカテゴリをオフにするか、コピー後のテキストを編集 |
| キーがまだ有効かどうかの確認 | 行いません。確認するにはキーをプロバイダーに送る必要があるためです |
| 角括弧が外されたプレースホルダーの復元 | AI にプレースホルダーをそのまま残すよう指示 |
入力の上限は 1,000,000 文字です。秘密鍵ルール以外はすべて行末で止まるため、改行で分かれたシークレットは検出されません。
FAQ
AI に「シークレットを消して」と頼むのではだめですか?
頼んだ時点で漏えいが起きています。モデルが何かを消す前に、キーはすでにプロバイダーのサーバーやログ、場合によっては学習データに届いています。このツールの検出は固定の正規表現とエントロピー判定だけで構成され、すべてブラウザ内で動きます。手元の PC から出ていくのは、マスキング後にあなたがコピーしたテキストだけです。
入力内容はアップロードや保存をされますか?
されません。ページは入力テキストを伴うネットワーク通信を一切行わず、localStorage・sessionStorage・Cookie・URL にも書き込みません。プレースホルダーの対応表はページのメモリ上にだけ存在し、クリア、Ctrl/Cmd+L、再読み込み、タブを閉じる操作で破棄されます。JavaScript では文字列をその場で上書きできないため、メモリは次のガベージコレクションで解放されます。
何を検出しますか?
Anthropic、OpenAI と OpenAI 互換の sk- 形式(DeepSeek、OpenRouter、Moonshot など)、Hugging Face、AWS、Google、GitHub、GitLab、Slack、Stripe、SendGrid、npm、PyPI、Telegram のキー、JWT、Bearer / Basic 認証ヘッダー、PEM 秘密鍵ブロック、postgres://user:pass@host のような接続文字列内のパスワード、名前が password・secret・token・api_key で終わる変数の値、そして 1 文字あたり 4.2 ビット以上のエントロピーを持つ長いランダム文字列です。対象は認証情報だけで、メールアドレス・ホスト名・IP アドレスはそのまま残ります。
復元の仕組みは? AI がプレースホルダーを書き換えたら?
異なるシークレットごとに [OPENAI_KEY_1] のような番号付きプレースホルダーを割り当て、同じ値には必ず同じプレースホルダーを使います。AI の返答を復元欄に貼ると、プレースホルダーが元の値に戻ります。大文字小文字の違い、角括弧内の余分な空白、Markdown でエスケープされた角括弧は許容します。角括弧を外されたものは復元せず、足りない数として表示されるので、AI にはプレースホルダーをそのまま残すよう指示してください。
シークレットが検出されなかったのはなぜ?
改行で分断されたシークレット、変数名の手がかりがない 16 進数だけのトークン、既知の接頭辞も変数名もない 32 文字未満のキーは検出されません。16 進数を除外しているのは、CI ログのコミット SHA やチェックサムで本当の検出結果が埋もれないようにするためです。送信前にマスキング結果を目で確認してください。リポジトリ全体や git 履歴の走査には、ローカルで gitleaks か trufflehog を使ってください。