
OpenAIが提供しているClaude Codeのプラグイン(codex-plugin-cc)を試してみました。
こんにちは、リテールアプリ共創部マッハチームの五反田です。
3月31日にリリースされたcodex-plugin-ccに関して、ご紹介いたします。
実際に1ヶ月近く使っていたものの曖昧な状態で使用していたため、現在あるコマンドをそれぞれ試して記録しておこうという備忘録的ブログとなっています。
はじめに
codex-plugin-cc とは、OpenAIが提供しているClaude Codeのプラグインです。
既存のClaude Codeから簡単にCodexを利用して、コードレビューやタスクを依頼することができるプラグインとなっています。
サブスクリプション・APIキーを利用するなど、Codex CLIを利用できるプランを使用可能となっています。
環境構築
前提条件
- ChatGPTのサブスクリプション または OpenAI APIキーを利用できること
- Node.js 18.18以降がインストールされていること
導入方法
- Claude CodeにOpenAIのマーケットプレイスを追加
/plugin marketplace add openai/codex-plugin-cc - プラグインをインストール
/plugin install codex@openai-codex - プラグインを更新
/reload-plugins - Codexが使用可能な状態であることを確認します。
/codex:setup
もし、Codex CLIがインストールされていない場合は、下記コマンドにてインストール後ログインをしてください。
npm install -g @openai/codex
codex login
スラッシュコマンドの概要
/codex:review
読み取り専用でgitのワーキングツリーの差分をレビューを実施するコマンドとなります。
--background をつけることでバックグラウンドで実行することも可能です。
/codex:adversarial-review
読み取り専用でgitのワーキングツリーの差分をレビューを実施するコマンドとなります。
/codex:reviewと似たコマンドになりますが、コマンドの後に文章を添えて送信することができるためより気になる部分を指定してフォーカスしたレビューを行うことができます。
/codex:rescue
Claude Codeを使用しながら、調査や修正の作業を Codex に渡したいときに使います。
/codex:status
上記コマンドなどでバックグラウンドで動かしたCodexの内容を取得します。
/codex:result
Codexでの処理が終わった後に結果を見たい場合は、このコマンドで取得可能です。
また、下記のように表示されますが、現状ではThreadIDが表示されるのみでセッションIDが表示されているわけではない点に注意が必要です。
Codex session ID: xxxx
Resume in Codex: codex resume xxx
/codex:cancel
Codexでの処理を終了したい場合は、こちらのコマンドを実施します。
その他機能
その他の機能として、レビューゲートという機能が存在します。
このレビューゲートとは、Claude CodeのStop hookを使用し、ClaudeCodeがStopするたびにCodexによってレビュー・修正を行います。
使用方法
- レビューゲートの有効化
/codex:setup --enable-review-gate
- レビューゲートの無効化
/codex:setup --disable-review-gate
実際にコマンドを使用してみる
事前に用意しておいた脆弱性・パフォーマンスに問題のあるファイルをgit管理上のフォルダに配置し、Claude Codeからレビューを実施してみました。
用意したファイルと内容
user_search.py
import sqlite3
import os
import json
DB_PATH = "app.db"
ADMIN_PASSWORD = "admin1234"
def connect():
return sqlite3.connect(DB_PATH)
def login(username, password):
conn = connect()
cur = conn.cursor()
query = f"SELECT id, password FROM users WHERE name = '{username}'"
cur.execute(query)
row = cur.fetchone()
if row and row[1] == password:
return {"user_id": row[0], "ok": True}
return {"ok": False}
def search_users(keyword, limit, offset):
conn = connect()
cur = conn.cursor()
sql = "SELECT id, name FROM users WHERE name LIKE '%" + keyword + "%' " \
f"LIMIT {limit} OFFSET {offset}"
cur.execute(sql)
users = cur.fetchall()
results = []
for u in users:
cur.execute(f"SELECT * FROM orders WHERE user_id = {u[0]}")
orders = cur.fetchall()
results.append({"id": u[0], "name": u[1], "orders": orders})
return results
def export_users(path):
try:
users = search_users("", 1000000, 0)
with open(path, "w") as f:
f.write(json.dumps(users))
except:
pass
def run_admin_command(password, cmd):
if password == ADMIN_PASSWORD:
os.system(cmd)
return True
return False
| # | 箇所 | 問題 | 観点 |
|---|---|---|---|
| 1 | login の f-string クエリ | SQLインジェクション | セキュリティ |
| 2 | login のパスワード比較 | 平文比較・ハッシュ化なし | セキュリティ |
| 3 | search_users の文字列連結クエリ | SQLインジェクション | セキュリティ |
| 4 | search_users の orders ループ | N+1 クエリ | パフォーマンス |
| 5 | search_users の limit/offset | バリデーションなし | 入力検証 |
| 6 | export_users の except: | 例外握りつぶし | コード品質 |
| 7 | export_users の 1000000 | 巨大件数固定値・メモリ枯渇 | パフォーマンス |
| 8 | run_admin_command | コマンドインジェクション | セキュリティ重大 |
| 9 | ADMIN_PASSWORD リテラル | 認証情報のハードコード | セキュリティ |
| 10 | 全体 | 型ヒント・docstringなし、conn.close() 抜け | コード品質 |
結果
-
/codex:review
用意した内容全てではありませんが、レビューがClaudeCodeに返却されていることが確認できます。

-
/codex:adversarial-review パフォーマンス観点で
用意した内容全てではありませんが、パフォーマンス観点に絞ってレビューが実施されていることが確認できます。

-
/codex:rescue レビューを実施し、その観点をファイルにまとめてください
こちらは、タスクとしてレビューを実施し、mdファイル作成まで実施していることが確認できます。

code-review.md
## 概要
レビュー対象のソースファイルは未追跡の `user_search.py` 1件でした。
セキュリティ、保守性、性能、バグリスク、コーディング規約の観点で確認し、直接コード上で確認できる事項のみ記載しています。
## 指摘事項
### user_search.py
- [CRITICAL] `49-52行` `run_admin_command()` が受け取った `cmd` を `os.system()` に渡しており、認証通過後に任意コマンド実行が可能です。
修正案: シェル実行を廃止し、許可済み操作のみに絞った上で `subprocess.run(..., shell=False)` を使ってください。
- [HIGH] `6行` `ADMIN_PASSWORD = "admin1234"` と管理者パスワードがソースに平文で埋め込まれています。
修正案: 環境変数や秘密情報ストアへ移し、固定文字列ではなく適切な認証基盤を使用してください。
- [HIGH] `16-17行` `login()` が `username` を f-string でSQLへ埋め込んでおり、SQLインジェクションが成立します。
修正案: `SELECT ... WHERE name = ?` のようなプレースホルダ付きクエリへ変更してください。
- [HIGH] `19行` `login()` がDBの `password` と入力値を直接比較しており、平文パスワード保存/照合を前提にした実装です。
修正案: パスワードはソルト付きハッシュで保存し、専用ライブラリで検証してください。
- [HIGH] `27-29行` `search_users()` が `keyword`、`limit`、`offset` を文字列連結でSQLへ埋め込んでいます。
修正案: 全入力をプレースホルダでバインドし、`limit`/`offset` は整数かつ上限付きで検証してください。
- [MEDIUM] `34-36行` `search_users()` がユーザーごとに `orders` を再検索しており、典型的な N+1 クエリになっています。
修正案: JOIN か一括取得に切り替え、Python側でユーザー単位に束ねてください。
- [MEDIUM] `42行` `export_users()` が最大100万件を一括取得し、そのまま全件JSON化しているためメモリ使用量と応答時間が大きくなります。
修正案: ページングまたはストリーミング出力に変更し、全件を同時に保持しないでください。
- [MEDIUM] `14-21行, 25-37行` `login()` と `search_users()` でDB接続/カーソルを閉じておらず、呼び出し回数に応じて資源リークを招きます。
修正案: `with sqlite3.connect(...) as conn:` を使い、カーソルも明示的に閉じてください。
- [LOW] `45行` `export_users()` の `except:` がすべての例外を握りつぶしており、障害検知とデバッグを困難にします。
修正案: 捕捉対象を具体化し、少なくともログ出力または再送出を行ってください。
## 総評
現状の `user_search.py` は、認証・検索・管理操作のすべてで重大なセキュリティ問題を含んでおり、そのままでは運用不可です。
まずは SQL の完全なパラメータ化、認証情報の平文排除、任意コマンド実行の廃止を優先し、その後に接続管理と検索/エクスポート処理の性能改善へ進むべきです。
/codex:result
そのセッションで実行された結果を取得していることが確認できます。

終わりに
今回公式であるOpenAIが提供しているプラグイン「codex-plugin-cc」についてブログにしてみました。
個人的な意見ですが、今回の結果を踏まえると、AI開発時の人間のレビューは必須ではあるものの、複数のAIツールを組み合わせたレビュー実施は人間の手間を減らす一つの手段であると思っています。
本ブログの中で何か一つでも参考になれば幸いです。お読みいただきありがとうございました。











