◉CLAUDE LABEN
●CODE 2.1.319 — Claude Code で MCP のタスク実行が自動でバックグラウンドに回るようになりました。確認待ちを拒否に倒す denyInsteadOfPrompting 設定も入りました●CONSOLE — Console の IP 許可リストがベータで登場しました(11/5)。許可外のアドレスからのリクエストは拒否されます●SONNET 4.5 — Claude API での提供終了は 11/30、残り23日。移行先は Sonnet 5.5●WINDOWS — 日本語の環境でだけフックが黙って壊れる報告があり、文字コードの確認が呼びかけられています●FAST — Opus 4.8 の fast mode は非推奨になり、11/30 に除去されます。移行先は Opus 5.5●NEW — Cowork に渡したフォルダの先頭に、十行の約束ファイルを置いてみました●CODE 2.1.319 — Claude Code で MCP のタスク実行が自動でバックグラウンドに回るようになりました。確認待ちを拒否に倒す denyInsteadOfPrompting 設定も入りました●CONSOLE — Console の IP 許可リストがベータで登場しました(11/5)。許可外のアドレスからのリクエストは拒否されます●SONNET 4.5 — Claude API での提供終了は 11/30、残り23日。移行先は Sonnet 5.5●WINDOWS — 日本語の環境でだけフックが黙って壊れる報告があり、文字コードの確認が呼びかけられています●FAST — Opus 4.8 の fast mode は非推奨になり、11/30 に除去されます。移行先は Opus 5.5●NEW — Cowork に渡したフォルダの先頭に、十行の約束ファイルを置いてみました
記事一覧/Claude Code
⟐ Claude Code/2026-08-09上級

一時的な401が長期トークンを置き換える — ヘッドレス実行の資格情報に「出所」を持たせる

共有した資格情報ファイルは、たった一度の一時的な401で長期トークンを失うことがあります。24並列の実行に401を1回だけ注入して被害範囲を実測し、資格情報に出所フィールドを持たせるガードと隔離のコストを比較、24マイクロ秒で現在地を確定する起動時カナリアまで検証しました。

Claude Code284ヘッドレス資格情報OAuth4自動化87

✦ プレミアム記事

個人開発で回している自動化は、その多くを深夜のスケジュール実行に任せています。その結果を朝いちばんに確認するのが、ここ数年の習慣です。

その朝は、4本のジョブが全部同じところで止まっていました。最初の1本だけが認証エラー。残り3本は、起動直後から一度も通っていません。

手で同じコマンドを叩くと、あっさり通ります。再実行しても通ります。ログを遡ると、最初の1本が踏んだのは一過性の401でした。ネットワークの瞬断か、その時刻だけの何かか。そこまでは想定内です。

腑に落ちなかったのは、その1本の失敗が、無関係なはずの他の3本を巻き込んでいたことでした。

リリースノートの1行が、手を止めさせた

8月8日から9日にかけての Claude Code の更新に、資格情報まわりの修正が入っていました。要旨を私の言葉でまとめると、次のとおりです(原文の引用ではなく要約です。正確な文言は公式の更新履歴でご確認ください)。

一時的な 401 をきっかけに、長期の CLAUDE_CODE_OAUTH_TOKEN が保存済みログインの短命トークンに置き換わり、再起動するまでヘッドレスセッションが復帰しない問題への修正。

読んだ瞬間に、あの朝のログと形が重なりました。修正されたのですから、この経路については追わなくてよいはずです。

それでも手が止まったのは、これが**特定のバグというより、失敗の「形」**に見えたからでした。長期の資格情報と短命の資格情報が、同じ置き場所を共有しています。片方を更新する経路が、もう片方を黙って上書きできます。その構造は、自分が組んだ自動化の中にもいくつか残っているはずです。

そこで、Claude Code の内部実装を推測するのではなく、この失敗の形だけを取り出した最小モデルを書いて、被害の広がり方を数字にしてみることにしました。以下の実測値はすべてその自作モデルのもので、Anthropic の実装を再現したものではありません。測っているのは「共有された可変の資格情報ストアが持つ性質」そのものです。

計測環境は Linux 6.8.0 / Python 3.10.12 / 4 vCPU のサンドボックスです。

失敗の形を、最小構成で組む

必要な部品は3つだけでした。資格情報を置く1つのファイル。それを読んで使う複数のワーカープロセス。そして、401 を踏んだときに走るリフレッシュ経路。

資格情報には最初から src フィールドを持たせています。あとでガードを実装するときに使いますが、まずはただ記録されるだけの値です。

# store.py — 資格情報ストアの最小実装
import json, os, time, fcntl, tempfile
 
def write_naive(path, obj):
    """アトミックでない書き込み。実際のクラッシュ窓を再現するため2回に分けて書く"""
    with open(path, "w") as f:
        s = json.dumps(obj)
        half = len(s) // 2
        f.write(s[:half]); f.flush()
        time.sleep(0.0008)          # この隙間に他プロセスが読むと壊れた JSON を掴む
        f.write(s[half:]); f.flush()
 
def read_naive(path):
    with open(path) as f:
        raw = f.read()
    return json.loads(raw)          # 途中の状態を読むと ValueError
 
def write_atomic(path, obj):
    """同一ディレクトリに書いてから rename。POSIX では rename が原子的"""
    fd, tmp = tempfile.mkstemp(dir=os.path.dirname(path))
    with os.fdopen(fd, "w") as f:
        json.dump(obj, f); f.flush(); os.fsync(f.fileno())
    os.replace(tmp, path)
 
def with_lock(path, fn):
    """flock による排他。ロックファイルは資格情報本体とは別に持つ"""
    with open(path + ".lock", "a+") as lf:
        fcntl.flock(lf, fcntl.LOCK_EX)
        try:
            return fn()
        finally:
            fcntl.flock(lf, fcntl.LOCK_UN)

ワーカー側は、現実のヘッドレスセッションに寄せて 一度読んだ資格情報をプロセス内に保持する ようにしました。毎回ファイルを読み直すプロセスは、そもそも実装として不自然です。

def worker(wid, q):
    path = os.path.join(BASE, "credentials.json")
    cached = None; used_session = 0; poisoned_at = None
    for it in range(ITERS):
        if cached is None:
            try:
                cached = with_lock(path, lambda: read_naive(path))
            except Exception:
                torn += 1; time.sleep(0.001); continue
        if cached.get("kind") != "long_lived":
            used_session += 1
            if poisoned_at is None:
                poisoned_at = it        # 何イテレーション目で汚染されたか
        if random.random() < P401:      # 一時的な401 → リフレッシュ経路へ
            new = {"token": session_token(wid), "kind": "session", "src": "saved_login"}
            with_lock(path, lambda: write_atomic(path, new))
            cached = None               # 書き戻したので次は読み直す
        time.sleep(0.0005)

kind が long_lived のまま最後まで走れば健全。途中で session に変わったら、そのワーカーは運用者が意図していない資格情報で動き続けていることになります。

✦

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

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
✦1回の一時的な401が24並列のワーカー全部を10イテレーション以内に汚染していく過程を、実測値で追えるようになる
✦flock を足すと破損読み取りは25件から0件になるのに、上書き被害は16/16のまま変わらない理由がわかる
✦出所フィールドによるガードで汚染を0にしたうえで、隔離コストを1セッション4.7ms・2.9MBから0.2ms・4.5kBへ落とす実装が手に入る
Stripe による安全な決済 · いつでもキャンセル可能
✦

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

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

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

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

関連記事

⟐ Claude Code2026-08-05
秘密を渡さず、リクエストだけ通す — サンドボックス資格情報マスキングの差し替えが効く境界
Claude Code のサンドボックス資格情報マスキングは、センチネル値を読ませて送信時に実値へ差し替える設計です。差し替えが効く認証方式と効かない方式、ボディに載せたときの長さのずれ、そしてチャンク分割転送で置換そのものが空振りする境界を、最小プロキシを自作して実測しました。
⟐ Claude Code2026-09-02
モデル切り替えの記録と歯止めを、フック2本で作る
PreModelSwitch と PostModelSwitch を使い、無人実行中のモデル切り替えを記録するフックと、約束していない切り替えだけを止めるフックをゼロから作ります。実測値つきの手順です。
⟐ Claude Code2026-09-01
heredoc のクォートを1つ落とすと、ログに書いた金額や日付が別物になります
未クォートの heredoc は本文の変数とバックティックを実行します。実測した4通りの書き換わり方、3種類のクォート記法の比較、プレースホルダと sed で値を安全に埋める手順、既存スクリプトを棚卸しする検出コードまでをまとめました。