CLAUDE LABEN
GATEWAY — v2.1.225 で、ゲートウェイの支出上限に達したときのメッセージに上限額・リセット時刻・運用者からのメッセージが表示されるようになりましたTRUST — claude agents でも、信頼していないディレクトリに対して claude と同じワークスペース信頼の確認が入りますAUTH — 一時的な401をきっかけに長期の OAuth トークンが短命トークンへ置き換わり、ヘッドレスセッションが壊れ続ける問題が修正されましたMCP — macOS でキーチェーンの読み取りがタイムアウトした後、未認証扱いの401が連発する問題が解消されましたAGENTS — SendMessage から、他マシンで動く Remote Control セッションへ名前を指定して会話を始められるようになりましたWORKBENCH — 旧 Workbench と実験的なプロンプトツール API の廃止は8月17日、Sonnet 5 のプロモ価格は8月31日までですGATEWAY — v2.1.225 で、ゲートウェイの支出上限に達したときのメッセージに上限額・リセット時刻・運用者からのメッセージが表示されるようになりましたTRUST — claude agents でも、信頼していないディレクトリに対して claude と同じワークスペース信頼の確認が入りますAUTH — 一時的な401をきっかけに長期の OAuth トークンが短命トークンへ置き換わり、ヘッドレスセッションが壊れ続ける問題が修正されましたMCP — macOS でキーチェーンの読み取りがタイムアウトした後、未認証扱いの401が連発する問題が解消されましたAGENTS — SendMessage から、他マシンで動く Remote Control セッションへ名前を指定して会話を始められるようになりましたWORKBENCH — 旧 Workbench と実験的なプロンプトツール API の廃止は8月17日、Sonnet 5 のプロモ価格は8月31日までです
記事一覧/Claude Code
Claude Code/2026-08-09上級

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

共有した資格情報ファイルは、たった一度の一時的な401で長期トークンを失います。24並列に401を1回だけ注入して被害範囲を実測し、出所フィールドによるガードと隔離のコストを比べました。

Claude Code215ヘッドレス2資格情報2OAuth4自動化77

プレミアム記事

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

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

関連記事

Claude Code2026-08-05
秘密を渡さず、リクエストだけ通す — サンドボックス資格情報マスキングの差し替えが効く境界
Claude Code のサンドボックス資格情報マスキングは、センチネル値を読ませて送信時に実値へ差し替える設計です。差し替えが効く認証方式と効かない方式、そしてボディに載せたときに生じる長さのずれを、最小プロキシを自作して実測しました。
Claude Code2026-08-04
ファイルシステムの分離をネットワークと別に締める — 触ったパスを採り、書き込み面から絞る
Claude Code v2.1.216 でファイルシステムの分離をネットワークと切り離して指定できるようになりました。締める前にジョブが触ったパスを strace で採取し、読み取り面と書き込み面を分けて測った実務メモ。同じジョブを3回走らせたときのパス集合の安定率と、接頭辞に畳んだときの安定率の差まで実測しています。
Claude Code2026-08-03
存在チェックが通っても書けない — 無人実行の前提を能力プローブで測る
ディレクトリが存在することと、そこへ書けることは別です。無人で走る Claude Code のセッションが静かに止まる原因を実測し、能力プローブ方式のプリフライトを設計した記録です。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →