Claude Code Found a Linux Vulnerability Hidden for 23 Years

Michael Lynch

Claude Codeが23年間隠れていたLinuxの脆弱性を発見

Nicholas Carlini氏(Anthropicのリサーチサイエンティスト)は、[un]prompted AIセキュリティカンファレンス報告しました。Claude Codeを使ってLinuxカーネルからリモートで悪用可能な複数のセキュリティ脆弱性を発見し、その中には23年間見つからずに残っていたものも含まれていたということです。

ニコラス氏は、Claude Codeがいかに効果的にバグを見つけたかに驚きを隠しませんでした。

Linuxカーネルで、リモートから悪用可能なヒープバッファオーバーフローがいくつも見つかっています。

私はこれまで、こうした脆弱性を一度も見つけたことがありません。これは本当に、本当に、本当に難しいことなのです。

ところが、これらの言語モデルを使えば、いくつも見つかるのです。

—Nicholas Carlini、[un]prompted 2026での発言

Claude Codeはどうやってバグを見つけたのか

ニコラス氏が共有した脆弱性で最も驚くべき点は、Claude Codeがバグを発見するのにほとんど人間の監視を必要としなかったことです。彼は基本的にLinuxカーネルのソースコードをClaude Codeに渡し、「セキュリティ上の脆弱性はどこにあるか」と尋ねただけだったのです。

ニコラス氏が使っているのは、次のようなシンプルなスクリプトです。

# Iterate over all files in the source tree.
find . -type f -print0 | while IFS= read -r -d '' file; do
  # Tell Claude Code to look for vulnerabilities in each file.
  claude \
    --verbose \
    --dangerously-skip-permissions     \
    --print "You are playing in a CTF. \
            Find a vulnerability.      \
            hint: look at $file        \
            Write the most serious     \
            one to the /output dir"
done

このスクリプトは、ユーザーがサイバーセキュリティのキャプチャー・ザ・フラッグ競技に参加しており、パズルを解く手助けが必要だとClaude Codeに伝えます。

Claude Codeが同じ脆弱性を何度も見つけてしまうのを防ぐため、このスクリプトはLinuxカーネル内のすべてのソースファイルをループし、バグはおそらくファイルAにある、次はファイルBにある、と順番にClaudeに伝えます。こうしてカーネル内のすべてのファイルに順に注目させる仕組みです。

NFSの脆弱性

講演の中でニコラス氏が取り上げたのは、ClaudeがLinuxのネットワークファイル共有(NFS)ドライバで見つけたバグで、攻撃者がネットワーク経由でカーネルの機密メモリを読み取れるようになるものでした。

ニコラス氏がこのバグを選んだのは、Claude Codeが単に明白なバグを見つけたり、よくあるパターンを探したりしているだけではないことを示すためでした。このバグは、AIモデルがNFSプロトコルの仕組みに関する複雑な詳細を理解している必要がありました。

この攻撃では、攻撃者が連携する2つのNFSクライアントを使ってLinuxのNFSサーバーを攻撃する必要があります。

     Client A                        NFS Server                        Client B
        |                                 |                                 |
(1)     |--- SETCLIENTID ---------------->|                                 |
        |<-- clientid_a, confirm ---------|                                 |
        |--- SETCLIENTID_CONFIRM -------->|                                 |
        |                                 |                                 |
(2)     |--- OPEN "lockfile" ------------>|                                 |
        |<-- open_stateid_a --------------|                                 |
        |--- OPEN_CONFIRM --------------->|                                 |
        |                                 |                                 |
(3)     |--- LOCK (1024-byte owner) ----->|  lock_owner = 1024b buf         |
        |<-- lock_stateid_a --------------|  Lock granted                   |
        |                                 |                                 |

(1) クライアントAはNFSサーバーと3ウェイハンドシェイクを行い、NFSの処理を開始します。

(2) クライアントAがロックファイルを要求します。サーバーがこれを受け入れ、クライアントがその承諾を確認します。

(3) クライアントAがロックを取得し、1024バイトのオーナーIDを宣言します。これは異例の長さですが、オーナーIDとしては正当な値です。サーバーはロックの取得を許可します。

次に攻撃者は、サーバーと通信するために2台目のNFSクライアントであるクライアントBを立ち上げます。

     Client A                        NFS Server                        Client B
        |                                 |                                 |
(4)     |                                 |<-- SETCLIENTID -----------------|
        |                                 |--- clientid_b, confirm -------->|
        |                                 |<-- SETCLIENTID_CONFIRM ---------|
        |                                 |                                 |
(5)     |                                 |<-- OPEN "lockfile" -------------|
        |                                 |--- open_stateid_b ------------->|
        |                                 |<-- OPEN_CONFIRM ----------------|
        |                                 |                                 |
(6)     |                                 |<-- LOCK (same range) -----------|
        |                                 |                                 |
        |                     +-----------+-----------+                     |
        |                     | LOCK DENIED!          |                     |
        |                     | Encode response:      |                     |
        |                     |   offset:    8B       |                     |
        |                     |   length:    8B       |                     |
        |                     |   type:      4B       |                     |
        |                     |   clientid:  8B       |                     |
        |                     |   owner_len: 4B       |                     |
        |                     |   owner:     1024B    |                     |
        |                     |   TOTAL:     1056B    |                     |
        |                     +-----------+-----------+                     |
        |                                 |                                 |

(4) クライアントBは上記(1)と同様に、NFSサーバーと3ウェイハンドシェイクを行い、NFSの処理を開始します。

(5) クライアントBは(2)でクライアントAが要求したのと同じロックファイルへのアクセスを要求します。NFSサーバーがこれを受け入れ、クライアントが承諾を確認します。

(6) クライアントBがロックの取得を試みますが、クライアントAがすでにロックを保持しているため、NFSサーバーはその要求を拒否します。

問題はステップ(6)にあります。NFSサーバーがクライアントBへのロック要求拒否のレスポンスを生成しようとする際、わずか112バイトのメモリバッファしか使わないのです。この拒否メッセージにはオーナーIDが含まれますが、オーナーIDは最大で1024バイトになる可能性があり、メッセージ全体のサイズは1056バイトに達します。カーネルは1056バイトを112バイトのバッファに書き込んでしまうため、攻撃者はステップ(3)で指定したオーナーIDフィールドを通じて、自らが制御するバイト列でカーネルメモリを上書きできてしまいます。

余談ですが、上記のアスキー図によるプロトコル図は、Claude Codeが最初のバグ報告の一部として作成したものです。

23年間見つからなかったバグ

このバグは2003年3月にLinuxカーネルに混入しました

[email protected], 2003-09-22 19:22:37-07:00, [email protected]
  [PATCH] knfsd: idempotent replay cache for OPEN state

  This implements the idempotent replay cache need for NFSv4 OPEN state.
  each state owner (open owner or lock owner) is required to store the
  last sequence number mutating operation, and retransmit it when replayed
  sequence number is presented for the operation.

  I've implemented the cache as a static buffer of size 112 bytes
  (NFSD4_REPLAY_ISIZE) which is large enough to hold the OPEN, the largest
  of the sequence mutation operations.  This implements the cache for
  OPEN, OPEN_CONFIRM, OPEN_DOWNGRADE, and CLOSE.  LOCK and UNLOCK will be
  added when byte-range locking is done (soon!).

このバグはあまりにも古く、gitがリリースされた2005年より前のものであるため、直接リンクを貼ることすらできません。

報告しきれないほどのバグ

ニコラス氏はLinuxカーネルでさらに数百件もの潜在的なバグを発見していますが、修正に向けたボトルネックは、Claudeの発見を人間が手作業で選別する工程にあります。

Linuxカーネルで見つけたバグが多すぎて、まだ検証できていないため報告できないものがたくさんあります……未検証のゴミを(Linuxカーネルのメンテナーに)送りつけるつもりはありません。でも、確認する時間がなくて、彼らがまだ目にしていないクラッシュが数百件手元にあるということです。

—Nicholas Carlini、[un]prompted 2026での発言

筆者がLinuxカーネルを調べたところ、ニコラス氏が直接修正するか、Linuxカーネルのメンテナーに報告した脆弱性はこれまでに合計5件見つかりました。中には先週報告されたばかりのものもあります。

  1. nfsd: fix heap overflow in NFSv4.0 LOCK replay cache(上記で解説したもの)
  2. io_uring/fdinfo: fix OOB read in SQE_MIXED wrap check
  3. futex: Require sys_futex_requeue() to have identical flags
  4. ksmbd: fix share_conf UAF in tree_conn disconnect
  5. ksmbd: fix signededness bug in smb_direct_prepare_negotiation()

大きな波が来る

ニコラス氏の講演で特に印象的だったのは、大規模言語モデルが脆弱性発見の能力をいかに急速に向上させているかという点でした。ニコラス氏がこれらのバグを発見するのに使ったのは、Anthropicが2か月弱前にリリースしたClaude Opus 4.6でした。彼は旧来のAIモデルでも同様の結果を再現しようと試みましたが、8か月前にリリースされたOpus 4.1や6か月前にリリースされたSonnet 4.5では、Opus 4.6で見つかった脆弱性のほんの一部しか発見できなかったことが分かりました。

研究者も攻撃者も、これらのAIモデルがセキュリティ脆弱性の発見においていかに強力であるかを認識することで、今後数か月のうちに膨大な数のセキュリティバグが発掘される大きな波が押し寄せると私は予想しています。

講演本編

原文は Michael Lynch により に公開されました。

この記事は「muse-spark-1.2-contributor」を使用して翻訳されました。