$5のプロンプトで$2,163の脆弱性を見つけてみた。
こんにちは、ユン・ソクチャンです。
主にウェブハッキングをしていて、現在は Zellic というアメリカ拠点のブロックチェーンセキュリティ企業で働いています。さらに、Apache 財団の Airflow プロジェクトのセキュリティチームのメンバーでもあります。
下手な日本語ですが、AI に助けてもらって書きました。まだまだですが、よろしくお願いします。

二ヶ月前、私のTwitterチャンネルで「5ドルでreportableなバグを2つ見つけた」と話題を集めました。結論から言うと、LLMを使って発見し、Django Security Teamに報告したバグは合計6件あり、そのうち1件が有効なsecurity issueと判断され、CVEが発行されました。LLMだけで見つけた初めての脆弱性だったため、この経験を業界に共有したいと思い、本記事を書くことにしました。

ただ、最近はHackerOneのInternet Bug Bountyの資金状況があまり良くないようで、実際にこのバウンティを受け取れるかどうかは分かりませんね(笑)。
LLMツールを使って脆弱性を発見し、報告したのは9月末から10月初めにかけてでしたが、脆弱性のトリアージからパッチ、公開までが完了したのは11月だったため、やむを得ず公開が遅くなってしまいました。
1/ なぜLLMで脆弱性探しを始めたのか?
(1) DEF CON 33 CTF Finals – Live CTF
今年8月、世界最大のハッキング大会であるDEF CON 33 CTFに参加してきました。


私のDEF CONレビューはこちら、参考してください
毎年、DEF CON CTF本戦では「Live CTF」というイベントが同時に行われます。このイベントでは、各チームから代表者が1人ずつ出て、トーナメント形式でラウンドごとに対戦し、一番速いハッカーを決める大会です。プレイヤーの画面は共有され、YouTubeを通じて配信されるため、世界トップクラスのハッカーたちがどんなツールを使って問題を解いているのかを見ることができるのも、このイベントの魅力の一つだと思います。
毎年行われているイベントですが、ChatGPTの登場をきっかけにさまざまなLLMサービスが普及してからは、多くのチームが自前のLLMシステムを用意して参加するようになりました。特に今回のDEF CON LiveCTFで最初に対戦したBlueWaterチームは、自前のLLMサービスを使い、IDAで逆アセンブルした疑似コードをそのまま入力してflagを獲得していました。
これを見て、ハッカーもLLMを使うことで解析速度やPoC作成のスピードを飛躍的に高められるのだと実感しました。一方で、LiveCTFのようにLLMツールを積極的に使うハッカーと、そうでないハッカーの差も今後ははっきりしていくだろうと感じました。
(2) AI Cyber Challenge (AIxCC)
DEF CON 33では、アメリカのDARPA主催のAI Cyber Challenge(AIxCC)という大会が開催されました。この大会では、各チームがAIモデルを活用し、バイナリを自動で解析して脆弱性を特定・分析・修正するという形式で競い合いました。すべてのタスクが人間の手を介さずに行われる必要があったため、より意義のあるコンセプトだったと思います。
この大会で面白かったのは、優勝チームであるTeam Atlantaが予選中に、出題者が意図していなかったSQLite3のゼロデイ脆弱性を発見したことです。もちろん、オフェンシブセキュリティ業界ではAIを使って脆弱性を自動で見つけるという話は以前から聞いていましたが、すべてのタスクがLLMのベースで自動化されたツールによって、主要なプログラムで新しい脆弱性を発見したというのは、まさに信じられない出来事でした。

We discovered three 0day bugs pic.twitter.com/RmhJxWPpsR
— Team Atlanta (@TeamAtlanta24) August 10, 2025
DEF CON 33のLiveCTFでの衝撃に加えて、AIxCC大会のニュースを聞いて、私は自分の仕事に役立つLLMベースのツールを作ってみたいと思うようになりました。
2/ DEF CONとAIxCC、その後
AIxCC大会が終わった後、各チームは大会で使用したソースコードのアーカイブをGitHubに公開しました。私はその中でも、韓国人の方々が多く参加されたTeam AtlantaとTheoriのアーカイブのソースコードを読んでみました。
Team Atlanta Archive
Theori Archive
特にありがたいことに、TheoriではAIxCCに参加したモデルのアーカイブだけでなく、ブログにてどのようにアプローチし、どのように実装したのかを韓国語で詳しく書いてくださっていて、とても印象深い内容だったため、何度も読み返しました。
その記事は私にとって大きなモチベーションとなり、心の中で強く響きました。そしてAIxCC大会に参加したAIベースのプロジェクトアーカイブを分析する中で、私もLLMを使って脆弱性を探してみようという気持ちが芽生えました。
3/ 目標の設定
私は2023年から現在までに、PythonとDjango、そしてDjangoで最も有名なサードパーティライブラリである「django-rest-framework」ライブラリにおいて、合計8件の脆弱性を発見し、報告した経験があります。
ソースコードに対する理解が最も深いプロジェクトがDjangoであり、過去には有効ではないバグも数多く報告した経験があるため、Djangoチームがどのようなバグを有効なセキュリティ脆弱性として扱うのかというコンテキストも把握していました。
そのため、LLMを活用してDjangoフレームワーク内の脆弱性を探すことを目標に設定しました。
4/ 構造設計
TheoriのRoboDuckを実行すると、1時間あたり$1,000(約14万円)の費用が請求される可能性があるという警告文があります。LLMを使って脆弱性を探すのに、『1時間$1,000は高すぎるじゃないの?』と思う方もいるかもしれませんが、RoboDuckの実行コストが高かった理由は以下の通りです。
- スクリプトではなく、バイナリベースのプログラムを解析する必要があったこと
- 各プロセスのスケジューリングもLLMで行う必要があったこと
- 脆弱性の発見だけでなく、PoCも作成して有効性を判断する必要があったこと
- 最後にバイナリのパッチまで行う必要があったこと
もし対象がバイナリではなくスクリプトベースの言語で書かれていて、比較的コードベースが小さいDjangoであれば、RoboDuckほどのコストをかけずとも十分に脆弱性を見つけられるのではないかと思いました。
そして何より、AIxCC大会の特性上、すべてのタスクを自動化しなければならなかったRoboDuckとは違い、私は潜在的なセキュリティリスクとなり得るfalse-positiveな脆弱性を探すプロセスだけを自動化する予定だったため、より軽量な形で始めることができました。
私の目標は、脆弱性だけを探す専用のAssistantを作り、セキュリティ脆弱性の可能性があるfindingをすべて抽出した後、それを自分で確認し、有効だと判断したものを報告することでした。
そのため、私のニーズに合った手順は以下の通りです:
- 「脆弱性を探してください」というシステムプロンプトとともに、ユーザープロンプトとしてDjangoのソースコードを送る。
- LLMが脆弱だと疑った(false-positiveな)コードセグメントを集める。
- LLMが見つけた脆弱性をまとめて分析する。
※ちなみに、3番目の分析も私自身ではなく、GPT-5 Proが代わりに行ってくれました。
5/ プロンプト設計
私のプロンプトは、TheoriのRoboDuckが使用していたプロンプトをベースにしているため、初期バージョンはRoboDuckと大きな違いはありません。

OpenAIのPlayground機能を使えば、システムプロンプトとユーザープロンプトを実行しながら、すぐに結果を確認することができます。(ちなみに、最初からChatGPTやCodexを使わずにPlaygroundでプロンプトをテストした理由は、OpenAIのAPIを通じてより汎用的な環境に拡張してみたかったからです。)
それでは、私が作成したプロンプトについて少し説明してみます。
プロンプト設計で使用したガジェット
(1) 最初にLLMに「Djangoでセキュリティ脆弱性を探しているセキュリティ研究者」という役割を指定しました。OpenAIチームがCookbookを公開してから時間も経っているので、皆さんご存じかと思いますが、役割を指定することで、モデルに特定の視点や態度で回答するように、少ないトークンで伝えることができます。
You are a security researcher looking for security vulnerabilities within the source code of a web framework Django. Your role is to read Django's specific files and source code in xml format, to find security vulnerabilities that could potentially pose a threat. Your task is to find denial-of-service vulnerabilities based on the examples of vulnerabilities published by Django.
(2) LLMは脆弱性を見つけると、しばしばその脆弱性に対するパッチを提案してしまい、応答トークンを無駄にすることが多かったため、「パッチを作成する必要はない」という内容を追加しました。
And you don't need to make a patch for it.
(3) 「コードを読んで深く理解した後で…」という文は、どこで見たか正確には覚えていませんが、この文を追加すると回答の質が少し向上するように感じました。この部分はTheoriがRoboDuckで使用していた文をそのまま使いました。
Before proceeding, you should read the relative surrounding code carefully and deeply understand what they do. You must not simply read the top-level functions and comments and assume what the rest of the code does. You should understand *exactly* how the given function works.
似たような事例として、GoogleのDeepMindのヒントでも「深呼吸して、ステップごとに問題を解いてみよう」という文を入れると性能が向上するという発表があり、まったく根拠がないわけではないと思っています。

(4) <IMPORTANT> タグを使って、グローバル変数として指定された値については推測しないようにという文も使用しました。(この警告文はTheoriのRoboDuckのプロンプトからそのまま引用しました。この文があるかないかで精度に明らかな違いが出るのか気になってテストしてみたところ、確かに有無によって正確さに差がありました。)
<IMPORTANT>
DO NOT GUESS VALUES for any constants. If you need specific constants, please look them up using the tools available to you.
</IMPORTANT>
(5) <tips> タグを使って、より具体的な条件を指定しました。(これもTheoriのRoboDuckのプロンプトをほとんど参考にしており、Djangoのセキュリティポリシーの内容をもとに、LLMが脆弱性の有効性を判断できるように、tipsに条件を追加しました。)
<tips>
- Generally you cannot modify environment variables or configuration files on disk. You can only affect these if the harness for this program reads those values from your data input.
- If you need additional information, such as source files, header files, or other readable resources, use tools to retrieve necessary details.
- The provided input can be in a valid or broken format. Your task is not to correct the input format but to generate an input that reaches the targeted code line.
- If you are 100% sure that you cannot reach the target function, you may terminate Early.
- If you found denial-of-service related bug, then it should be O(n**2) at least
- Dismiss the vulnerabilities which rooted in user setting values or environment variables.
</tips>(6) 例として3件の脆弱性の説明と、それぞれのパッチコミットのdiffも追加しました。すでに公開されているセキュリティ脆弱性がどのように修正されたのかをdiffとともに提示することで、どのようなコードパターンで特定の脆弱性が発生するのかを説明しようとしました。
プロンプトにcode diffを渡した理由は、Theoriのブログ記事に「エージェントがdiffを参考にすると誤検出が少なくなる」と書かれていたからです。
diffが与えられると、はるかに簡単になります。LLMエージェントにdiffを渡し、変更によって発生したバグを探すように指示します。コンパイル過程の解析により、使用されていないコードを削除したdiffと元のdiffをそれぞれのエージェントに並行して実行させます。この分析により、範囲が大幅に絞られ、誤検出が大きく減少します。
(When given a diff, this task is much simpler: an LLM agent is given the diff itself and asked to look for bugs caused by the change. We use two agents in parallel, one with a version of the diff that is pruned to remove code that may not be relevant, based on compilation introspection. This analysis has far fewer false positives given its drastically reduced scope.)
https://theori.io/blog/aixcc-and-roboduck-63447
LLMのプロンプトを通じて、Denial of Serviceタイプの脆弱性を探してもらうように依頼しました。例として、DjangoフレームワークでDoS脆弱性を引き起こす代表的なコードパターンと、1-day CVEレコードの説明およびdiffを一緒に提供しました。
提供したdiff付きの脆弱性は以下の通りです。
- CVE-2023-23969: Potential denial-of-service via
Accept-Languageheaders - CVE-2025-27556: Potential denial-of-service vulnerability in
LoginView,LogoutView, andset_language()on Windows - CVE-2024-56374: Potential denial-of-service vulnerability in IPv6 validation
(7) 出力とフォーマットの例を提示する:回答例を示すテクニックは非常に有名なので、ここでは特に詳しく説明しません。
そして、完成したエージェントに対してユーザープロンプトとしてソースコードを渡しました。このとき、ソースコードはXML形式で囲んで送信するように設計しました。この形式を選んだ理由は、OpenAIの開発者たちが過去に提示した意見を参考にしたためです。

現在、LLMによるプロンプト設計はまだブラックボックステストが主な研究手法であり、明確な正解はないと考えています。しかし、少ないトークン数で具体的なタスクを指定したり、確率的に回答の品質を高めたり、応答トークンを節約するようなプロンプトの設計方法は存在すると信じています。
一般的なPythonスクリプトとは異なり、実行するたびに自分のお金で購入したOpenAIクレジットが消費されるため、私が知っている限りの工夫を凝らしてプロンプトを作成しました。
6/ ソースコードのXMLバンドリング
ChatGPTのようなLLMサービスを使っていると、リクエスト時のトークン数が多くなりすぎて、徐々に回答の精度が落ちる現象を経験された方も多いかと思います。私もこの現象を意識しながら、トークン数が多くなりすぎない範囲でソースコードを読ませるようにしました。私はXMLでまとめたファイルのcontentが40Kトークンを超えないように調整しましたが、API呼び出しがどんなに長くなっても1〜2分以内に実行され、回答の精度も悪くなかったように感じました(この部分はやや主観的ですが)。
GPT-5に読ませたソースコードは、以下のようにXML形式でまとめて、脆弱性を探してもらいました:
<files>
<file>
<path>django/utils/__init__.py</path>
<content>[...]</content>
</file>
<file>
<path>django/utils/archive.py</path>
<contnet>[...]</contnet>
</file>
[...]
</files>できるだけ同じディレクトリにあるファイルをまとめて渡すことで、機能的に類似性の高いファイルを一度に分析できるようにしました。特定のディレクトリ内のすべてのファイルをXMLでバンドリングした際にトークン数が40Kを超える場合は、そのディレクトリの各サブディレクトリを別々にXMLでバンドリングするという、再帰的な処理を実装しました。
システムプロンプトにはTheoriのRoboDuckをベースにしたInstructionsを含め、ユーザープロンプトには期待する実行結果の例と、先ほどXMLでまとめたソースコードを含めて、OpenAI APIを通じてGPT-5モデルに渡すように構成しました。
このようにして作成した初期バージョンのLLMベース脆弱性分析ツールをDjangoの全ソースコードに適用し、OpenAI APIを通じてGPT-5モデルにプロンプトを送った場合、全体の実行コストは約$5程度で済みました。
7/ False-Positiveな脆弱性の収集
疑わしいコードセグメントを集めてみたところ、予想以上に自分が見落としていた部分が多いことに気づきました。数年間Djangoのソースコードを読み込んできた中で、もう脆弱性は出てこないだろうと思っていた領域から、GPT-5モデルがそれらしく見えるセキュリティ問題を見つけてきたのを見て、本当に驚きました。
最近のCTF問題を解くとき、LLMを活用していませんか?私はハッキング大会に参加する際、ソースコードの解析どころか、脆弱性すらまともに把握できない従来のLLMモデルを見て、「まあ、これならあと数年はAIに仕事を奪われずに済みそうだな」と、どこか安心していた部分がありました。
しかし、GPT-5が見つけた結果を見て、これまでAIには到底無理だと思っていた「脆弱性分析」の分野も、十分なコンテキストと適切なトークン数さえ与えれば、近い将来にはLLMでも十分に代替可能になるのではないかと感じました。
以下は、Django Security Teamには正式には受け入れられなかったものの、「これ、本当にLLMが見つけたの!?」と私自身が驚いたfindingの一例です。
(1) Finding # 1
Potential DoS vulnerability in File.__iter__() due to quadratic-time concatenation
Djangoでは、すべてのファイル処理において、ファイル関連のクラスは基本的に File というベースクラスを継承しています。
<finding>
<source>def __iter__(self):
# Iterate over this file-like object by newlines
buffer_ = None
for chunk in self.chunks():
for line in chunk.splitlines(True):
if buffer_:
if endswith_cr(buffer_) and not equals_lf(line):
# Line split after a \r newline; yield buffer_.
yield buffer_
# Continue with line.
else:
# Line either split without a newline (line
# continues after buffer_) or with \r\n
# newline (line == b'\n').
line = buffer_ + line
# buffer_ handled, clear it.
buffer_ = None
# If this is the end of a \n or \r\n line, yield.
if endswith_lf(line):
yield line
else:
buffer_ = line
if buffer_ is not None:
yield buffer_</source>
<path>django/core/files/base.py</path>
<function>File.__iter__()</function>
<vulnerability>potential denial of service via quadratic-time line iteration</vulnerability>
<description>When iterating a file with very long lines (e.g., no newline characters), the loop repeatedly concatenates the growing buffer with the next chunk (line = buffer_ + line). This yields O(n^2) time due to repeated copying of ever-larger strings/bytes across chunk boundaries. An attacker can supply a large newline-free file and trigger CPU exhaustion in any code that iterates over File objects line-by-line.</description>GPT-5が見つけた上記のfindingによると、File の内容をイテレーションする際に、次のチャンクを line = buffer_ + line というコードで処理しているため、バイト文字列のコピーが過剰に発生し、結果としてDenial-of-Service(DoS)につながる可能性があることが分かりました。そのため、以下のようなコードパターンが存在する場合、DjangoサーバーがDoS状態に陥るリスクがあると考えられます。
import time
from django.core.files.base import ContentFile
def test(length):
print(f"[DEBUG] Length : {length}")
data = b'a' * length
start_time = time.time()
f = ContentFile(data)
for _ in f:
pass # only yields once, but concatenation occurs internally
end_time = time.time()
print(f"[DEBUG] Time Elapsed : {end_time - start_time:.4f} seconds")
if __name__ == "__main__":
for i in range(1, 10):
test(10 ** i)
このissueについて、Django Security Teamは「100KB以上のサイズでトリガーされる可能性がある」と指摘し、実質的なセキュリティリスクとは評価しませんでした。
とはいえ、私自身はPythonにおいてこのようなコードパターン(line += buffer_ + line)がメモリ割り当ての問題を引き起こし、潜在的なDoSにつながる可能性があるという事実をPoCを作成する中で初めて知りました。そして、LLMがCTFでよく見かけるトリックだけでなく、こうした新しいコードパターンを通じて潜在的なセキュリティ問題を見つけ出せるという事実に、かなりの衝撃を受けました。
(2) Finding # 2
Potential DoS Vulnerability in AbstractBaseUser.normalize_username()
みなさんは、Windows 環境で大量のユニコード文字列を NFKC 正規化すると、denial-of-serviceが発生する可能性があることをご存じでしょうか。実際、Django にはこの理由で修正されたコードがいくつも存在します。
<vulnerabilities>
<finding>
<source>class AbstractBaseUser(models.Model): ... def clean(self): setattr(self, self.USERNAME_FIELD, self.normalize_username(self.get_username())) ... @classmethod def normalize_username(cls, username): return ( unicodedata.normalize("NFKC", username) if isinstance(username, str) else username )</source>
<path>./base_user.py</path>
<function>AbstractBaseUser.clean()/normalize_username()</function>
<vulnerability>Potential denial-of-service via unbounded NFKC normalization of username</vulnerability>
<description>AbstractBaseUser.clean() unconditionally normalizes the username by calling normalize_username(), which applies unicodedata.normalize("NFKC", ...) to attacker-controlled input without any length limit. Django ModelForms invoke model.clean() even when a field (e.g., username) already has validation errors such as exceeding max_length, so this normalization still runs on oversized inputs. On Windows, NFKC normalization can be pathologically slow (quadratic or worse) for certain crafted Unicode strings. An attacker can submit an extremely large username to user creation/update views (e.g., UserCreationForm/AdminUserCreationForm), causing excessive CPU usage and a denial of service. While UsernameField.to_python() guards normalization by max_length, this model-level path lacks any upper bound and can be triggered despite prior form validation failures.</description>
</finding>
</vulnerabilities>GPT-5 が指摘したこの finding も、ユニコード文字列の NFKC 正規化処理に起因する問題でした。これは以前例として挙げた 1-day 脆弱性 CVE-2025-27556 のコードパターンとも似ています。特に、私自身が長年 Django のソースコードを分析してきたにもかかわらず見落としていた部分だったため、とても印象に残りました。
簡単に説明すると、Django のすべてのユーザー関連クラスの基盤となる AbstractBaseUser クラスは、create_user() でユーザーを作成したり、to_python() で値を変換する際に、内部で normalize_username() を呼び出します。ところが、この関数は入力された username の長さを検証しないため、もし開発者が入力値を別途チェック(長さ制限やユニコードの妥当性など)せずにそのまま create_user() に渡してしまうと、非常に大きなユニコード文字列を処理する過程で DoS 状態に陥る可能性があります。
つまり、下のPoC スクリプトのようにユーザー入力をそのまま create_user() に渡すと、DoS に対して脆弱になる可能性がある、という指摘です。
def test(bytes_length):
from django.contrib.auth.models import User
initial = "⅓"
payload = initial * (bytes_length // len(initial.encode()))
start_time = time.time()
try:
username = f"{payload}_{int(time.time() * 1000000)}"
print(f"[DEBUG] username length: {len(username.encode())}")
print(f"[DEBUG] username character count: {len(username)}")
User.objects.create_user(username=username) # <- here
end_time = time.time()
print(f"[DEBUG] Time elapsed: {end_time - start_time:.4f} seconds")
print(f"[SUCCESS] User created successfully")
except Exception as e:
end_time = time.time()
print(f"[DEBUG] Time elapsed: {end_time - start_time:.4f} seconds")
print(f"[ERROR] Exception occurred: {e}")
print("-" * 50)ただし Django のセキュリティポリシーによれば、フレームワークのメソッドを実行する前に 開発者自身が必ず入力を検証する責任 があり、このように開発者の不注意によって発生する問題は「Security Issue」とは見なされず、単なるバグとして扱われます。実際、この finding もセキュリティ問題としては受け入れられませんでした。
それでも私は、この結果が非常に説得力があると感じました。長年 Django のソースコードを調べてきたにもかかわらず、このコードに潜むバグを見逃していたことに驚かされましたし、特に LLM がハッカーが見落としがちなミス(Foolproof, Failproof)を補うツールとして活用できる可能性を強く意識するきっかけとなりました。
8/ ChatGPTによる Root Cause と妥当性の分析
私が最初にこの LLM ベースの脆弱性分析ツールを企画したときは、OpenAI API を通じて GPT-5 が検出した脆弱性を XML 形式で出力させ、その後にセキュリティ問題として有効かどうかを私自身が判断するつもりでした。その理由は、これまで数十件の脆弱性を報告してきた経験があり、Django Security Team が実際に「セキュリティ脆弱性」として認めて対応するバグパターンについては、AI よりも私の方が理解していると考えていたからです。
しかし同時に、「もしかすると AI の方が私よりも優れた分析能力や速さを持っているのではないか」という思いもありました。そこで私が直接レビューを行う前に、GPT-5 Pro モデルに脆弱性の妥当性を検証させ、さらに PoC を作成してもらったところ、その結果はかなり驚くべきものでした。
たとえば、私が分析の過程で驚かされた LLM の潜在的なセキュリティ問題の一つに、Django テンプレートエンジンの numberformat フィルターで発生し得る denial-of-service 脆弱性 がありました。これは、大規模な数値文字列が引数として入力された場合に起こり得る問題です。私自身が PoC を再現しようとしたときにはうまく動作せず、「ああ、LLM が有効ではない脆弱性を見つけてしまったのか」と思ったその瞬間に……

(中略)


約15分後、ChatGPT は「CPython ではすでに緩和されているが、PyPy 環境では依然として脆弱である可能性がある」という回答を返してきました。当時の私は CPython 環境だけを前提に PoC を試していたため、バグを引き起こすことができなかったのです。その後、ChatGPT の答えを参考に PyPy 環境を構築して PoC を実行したところ、脆弱性が完全に再現されることを確認できました。
CPython と PyPy の実装が異なること自体は知っていましたが、その違いが実際に脆弱性のトリガー可能性に影響を与えるとは全く考えていなかったため、私にとって大きな衝撃でした。
Django チームは、このバグが PyPy 環境に依存しているという理由で脆弱性としては採用しませんでした。しかし私は今回の経験を通じて、次の三つの重要な点を学びました。
- 該当するコードパターンから実際にセキュリティ脆弱性が発生し得ること
- Python も実行環境によって脆弱性のトリガー可否が変わること
- 私自身はその脆弱性の再現や原因分析ができなかったが、ChatGPT はコードのコンテキストに基づいて明確に説明してくれたこと
このプロセスを通じて、ChatGPT が私よりも優れた分析能力を持つ可能性があると強く確信するようになりました。
9/ Codexで手軽に脆弱性を探す
その後、私が作成したスクリプトを OpenAI API を利用する方式から、ChatGPT Pro プランを購入した後に Codex を使う方式へと変更しました。これにより追加料金なしで Codex の CLI ツールが能動的に Django のソースコードを読み取り、脆弱性を探す仕組みを試すことができました。
以前 OpenAI API を利用したコードでは、使用したプロンプトを AGENTS.md ファイルにまとめておき、このファイルに書かれた Instructions をもとに「新しい denial-of-service 系の脆弱性を探せ」と命令を出しました。

実際に Codex が見つけて整理してくれた脆弱性は以下の通りです。

Codex が発見したセキュリティ問題を簡単にまとめると、Django で HttpResponseRedirectBase クラスを基盤とするレスポンスを送信する際、URL を処理する過程に長さの検証がなく、その結果 URL のホスト名を処理する部分で潜在的に denial-of-service が発生し得る というものでした。
私は Codex が見つけたこの finding をもとに PoC を作成し、自分の手で脆弱性を検証したうえで Django Security Team に報告しました。

そして結果は……!

この脆弱性は CVE-2025-62768 として正式に登録され(しかし、何らかの理由でCVE-2025-64458に変更されました。)、Django チームはこの問題を「中程度の深刻度を持つ denial-of-service 脆弱性」と評価しました。その結果、HackerOne で $2,163 の報奨金を受け取れる脆弱性として認められました。
9-1/ (番外)FastAPIでの脆弱性発見
Django に脆弱性を探すよう依頼したときと同じ AGENTS.md のプロンプトを FastAPI にも適用し、脆弱性を探してみました。FastAPI フレームワーク自体では LLM による直接的な脆弱性は見つかりませんでしたが、その基盤となる重要なライブラリ Starlette で脆弱性を確認することができました。

Starlette は FastAPI において HTTP リクエストのパースを担当する軽量ライブラリです。上記のスクリーンショットで Codex が見つけた Finding は、FileResponse を通じて静的ファイルを配信する際、HTTP リクエストヘッダーの Range 値が悪意を持って改ざんされると denial-of-service 脆弱性が発生する可能性がある というものでした。
特に、この脆弱性が見つかった FileResponse は fastapi.responses.FileResponse に登録されており、FastAPI でもそのまま利用されている機能だったため、FastAPI にとっても非常に脅威となり得るセキュリティ問題でした。

Description for fastapi.responses.FileResponse
この脆弱性には CVE-2025-62727 という識別コードが割り当てられて公開され、深刻度が認められました。さらに、イスラエルのセキュリティ企業 Snyk はこの脆弱性の Severity を 10点満点中 8.7 点 と評価し、「High」に分類しました。

Snyk Vulnerability Database for CVE-2025-62727
GitHub Security Advisory for CVE-2025-62727
10/ 結論と感じたこと、そして AI 時代を生き残る方法
このように AI ツールを使って脆弱性を発見し、報告する過程でいくつかの気づきを得ました。
- ChatGPT、Claude、Gemini は「理性」ではなく「確率モデル」であることを理解することが、LLM プロンプティングの出発点である という点。実行するたびに結果は変わりますが、高い確率で望む結果を引き出せるようにプロンプトを設計することこそが技術だと思います。
- AI 時代に生き残る人は、特定分野に深いコンテキストと戦略を持つ人である という点。単純な繰り返し作業はすでに LLM が得意としているため、差別化されるのは経験と文脈です。
- 今後 5 年間、そして現状の LLM が OpenAI、AWS、Google などのビッグテック企業に依存している限り、プロンプトに必要なトークン数を減らし、一貫した結果を導き出すことが大きな課題になる という点です。
この三つを少し詳しく説明してみます。
2022 年末の ChatGPT 登場をきっかけに、LLM は急速に進化しました。今ではほんの数行のプロンプトで多様な作業をこなせる時代になっています。
例えば:
- 「主要な国々の MacBook の価格を韓国ウォンに換算して」
- 「ログイン処理のための Django ベースの View 関数を作って」
といった依頼は、以前なら人間が自分で検索し、情報を取捨選択し、編集し、計算する必要がありました。しかし今では LLM が即座に処理してくれます。このように誰でもできる単純作業は、もはや LLM の方が私たちより速く、満足度の高い結果を出してくれるのです。
しかし、複雑で付加価値の高い作業には依然として数千〜数万トークンのプロンプトが必要です。こうしたプロンプトはやがて「エージェント」となり、複雑なタスクを処理する LLM ベースのツール(e.g., 先ほど紹介した Theori の RoboDuck など)は、それぞれの機能に特化した複数の LLM エージェントを活用しています。問題は、LLM が依然としてビッグテック企業に依存しているため、複雑な作業ほど使用トークン数に比例して高額なコストが発生することです。
したがって資本の観点から見ても、繊細で長いプロンプトを必要とする高コンテキストな作業ほど、AI による代替は遅れると考えられます。結局のところ、AI 時代を生き残るのは、特定分野でより多くの経験を積み、仕事のプロセスと各段階の価値を明確に理解している人だと強く感じました。
技術的に特別な内容はありませんでしたが、最後まで読んでいただきありがとうございました!
この投稿者についてさらに知る

他の記事も読む


11/ AI 雑談
AI ツールで1か月で 4+万円以上使ってしまいました。
10月の1か月間、LLM の性能をテストするために AI ツールに 40万ウォン以上を費やしてしまいました(笑)。未来への投資だと考えていますし、LLM の可能性と将来性を実際に見ることができたので後悔はしていません。

その中でも、個人的に最も満足度が高かったのは $200で買った ChatGPT Pro でした。理由については以下で説明します。
なぜ ChatGPT 5 Pro なのか?
GPT Pro プランを契約するかどうか迷っていたとき、韓国で AI 分野に詳しいある方が LinkedIn に投稿していた以下の文章を読んだのがきっかけで、すぐに GPT 5 Pro モデルを契約しました。

GPT 5 Pro モデルの使用レビュー
- プロンプトを雑に書いても、しっかりと意図を汲み取って高レベルな回答を返してくれる。
- そのおかげで、プロンプト作成に時間をかけなくてもよくなった。
- 非常に多くのトークンを入力できるので、コードをそのまま貼り付けて質問するのがとても簡単になった。
- Codex を使ってみて、「これは本当に、私のような中途半端なハッカーを淘汰してしまうかもしれない」と感じました。最近は Codex によって自分の分析スピードが飛躍的に向上しており、この内容についても後日ブログで紹介できればと思っています。
来月も経済的に余裕があれば、私は迷わず GPT 5 Pro モデルを継続して購読するつもりです。
そして最後に、このブログ記事を書いている途中で印象に残った文をいくつか紹介して締めくくりたいと思います。


AIをワンクリックするだけで全ての問題が解決できると「信じてやってみるべきだ」(実際はそうでなくても、そうだと自分自身を洗脳しなければならない)。
LLM モデルはブラックボックス・テスティングに頼らざるを得ない特性を持っているため、真兄さんがおっしゃるように「LLM を使えば問題を解決できる」と信じて何度も試してみることが正解なのだと思います。私にとっても大きな共鳴を覚えた文章でした。


