CLAUDE LABEN
2.1.273 — 接続まわりがまとめて整理されました。LLM ゲートウェイ向けの 5 ヘッダが opt-in で追加され、MCP が再接続を諦めたときにも通知が出ます09/29 — 廃止予定表にある claude-sonnet-4-5 の日付は残り 12 日ですが、これは「最も早い場合」の暫定日です。現在も Active で、公開モデルの廃止は最低 60 日前に告知されますMCP — セッションを畳まずに繋ぎ直したい、という要望が続いています。切断の通知は出るようになりましたが、再接続そのものはまだ手元の操作に委ねられていますNEW — 定期タスクが動く日と動かない日があったのは、フォルダを1つしか指定していなかったからでしたWINDOWS — Cowork が最初のタスクから失敗するときは、原因を探す前に開発者モードとセットアップの状態を確認しますHANDOFF — 会話が重くなった原稿を次のチャットへ渡すとき、要約に必ず残しておく項目を先に 3 つ決めておきます2.1.273 — 接続まわりがまとめて整理されました。LLM ゲートウェイ向けの 5 ヘッダが opt-in で追加され、MCP が再接続を諦めたときにも通知が出ます09/29 — 廃止予定表にある claude-sonnet-4-5 の日付は残り 12 日ですが、これは「最も早い場合」の暫定日です。現在も Active で、公開モデルの廃止は最低 60 日前に告知されますMCP — セッションを畳まずに繋ぎ直したい、という要望が続いています。切断の通知は出るようになりましたが、再接続そのものはまだ手元の操作に委ねられていますNEW — 定期タスクが動く日と動かない日があったのは、フォルダを1つしか指定していなかったからでしたWINDOWS — Cowork が最初のタスクから失敗するときは、原因を探す前に開発者モードとセットアップの状態を確認しますHANDOFF — 会話が重くなった原稿を次のチャットへ渡すとき、要約に必ず残しておく項目を先に 3 つ決めておきます
記事一覧/Claude Code
Claude Code/2026-08-09上級

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

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

Claude Code254ヘッドレス2資格情報2OAuth4自動化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)

kindlong_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/月 または ¥2,480 の永久アクセス
メンバーシップを見る →

関連記事

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