crafted by Mize ↗
Open Repository Intelligence Open Repository Intelligence
CodeLens ACTIVE
CodeLens Engine
StatusOnline
Versionv0.4
ModelClaude Sonnet
Latency—
0
GOOD
改善余地があります
mize1978/codelens-ai
「AIでコードの脆弱性を指摘するツール」自身がプロンプトインジェクションとパストラバーサルを抱えているという、皮肉の権化——まずは自分自身をレビューしてもらうべきでは?
⭐ 1 Stars
·
🍴 0 Forks
·
📝 70 Commits
·
💬 0 Issues
·
🔵 Blade
·
Laravel
🔍 重要ファイル 12 件を精査 全 152 ファイル中 AI が優先度順に選択
0
✦ 品質
0
🛡 セキュリティ
0
⚙ 保守性
📋 概要

Laravel 13.x / PHP 8.4 製の AI コードレビューSaaS。GitHub リポジトリのコードを Claude AI (Anthropic) に送信して品質スコア・issue・修正提案を返すサービスで、Queue Job による非同期処理と Docker でのデプロイを採用している。

🎯 今すぐ直すべき3点
  1. app/Services/ClaudeReviewService.php fixIssue() 内の file_content タグ閉じタグエスケープ処理 `str_replace('<\/file_content>', ...)` が buildReviewPrompt() には適用されていない箇所を確認・統一し、ユーザー提供コードによるプロンプトインジェクション耐性をすべてのメソッドで同一ロジックで担保する。また、送信前にファイルパスと内容をXML的に構造化するラッパーメソッドを切り出すこと。
    ↗
  2. app/Http/Controllers/ReviewController.php fix() メソッド内で `$review->review_data` から取得したファイルパスを `getFileContent()` に直接渡している箇所(`$request->input('file')` のバリデーションが `max:255` のみ)に対し、パストラバーサル防止のために `basename()` 正規化または allowlist チェックを追加し、GitHub API に任意パスを渡せないよう制限する。
    ↗
  3. .env.example `APP_DEBUG=true` がデフォルト値のまま残っており、本番環境にそのままコピーされるリスクがある。`APP_DEBUG=false` に変更し、`SESSION_ENCRYPT=true` は維持しつつ `APP_ENV=production` を本番向けコメントとして明記。さらに `ANTHROPIC_API_KEY` と `GITHUB_TOKEN` の空欄に必要性の説明コメントを追記すること。
    ↗
🔍 検出された問題 (7件)
🟥 Critical 📄 app/Services/ClaudeReviewService.php
プロンプトインジェクション対策が不完全・非対称
ClaudeReviewService.php の fixIssue() は file_content 閉じタグをエスケープしているが、buildReviewPrompt() の同様処理はコードが途中で切れており確認不可能。また sanitizeInput() は NULL バイトと改行正規化のみで、`</file_content>` タグの挿入によるプロンプト脱出を防ぐロジックが一部メソッドにしか適用されていない。悪意あるコードをリポジトリに仕込むことで Claude へのシステムプロンプトを上書きできる可能性があり、API料金の不正消費・機密情報漏洩につながる。
🟥 Critical 📄 app/Http/Controllers/ReviewController.php
fix() エンドポイントでのファイルパス未検証によるパストラバーサルリスク
ReviewController.php の fix() では `$request->input('file')` を `max:255` のみで検証し、そのまま GitHubService::getFileContent() に渡している。`../../../etc/passwd` や絶対パスを送ることで GitHub API に任意パスを要求でき、リポジトリ外ファイルの取得試行が可能になる。加えて取得したコンテンツが Claude に送信されるため、機密ファイルの内容が外部LLMに漏洩する経路となる。
🟧 Warning 📄 .env.example
.env.example の APP_DEBUG=true がデフォルト本番リスク
.env.example に `APP_DEBUG=true` が設定されており、Render等のPaaS環境でこのままコピー・デプロイされるとスタックトレースとアプリケーション内部情報がHTTPレスポンスに露出する。特に Anthropic APIキーやGitHubトークンのパスが含まれるエラーが公開されるリスクがある。
🟧 Warning 📄 Dockerfile
Dockerfile で秘匿情報なしに composer install を実行しているが COPY . . が全ファイルを含む
Dockerfile の Stage 2 で `COPY . .` を実行すると、ビルド時に .env が存在すれば Dockerイメージレイヤーに含まれる。.dockerignore の存在が確認できず、APIキーがイメージにベイクされてレジストリに push されるリスクがある。
🟧 Warning 📄 app/Jobs/ProcessReviewJob.php
ProcessReviewJob で取得した全ファイル内容が review_data カラムにそのまま保存されない一方、analyzed_files キーにパスのみ保存されているが、ファイル内容のキャッシュ戦略が欠如
ProcessReviewJob.php は毎回 GitHub API を叩いてファイル内容を取得し、fix() でも再度取得する二重フェッチ構造になっている。GitHub API のレートリミット(認証済み5000req/h)を無駄に消費し、トークン未設定環境では60req/hで詰まりジョブが全失敗する。
🟨 Suggestion 📄 app/Models/Review.php
Review モデルに ip_hash フィールドが fillable 未定義
ReviewController.php の store() で `ip_hash` を Review::create() に渡しているが、app/Models/Review.php の `$fillable` 配列に `ip_hash` が含まれていない。Mass Assignment 保護により silently 無視されるため、レートリミットのIP追跡データが実際には保存されていない可能性がある。
🟨 Suggestion 📄 tests/
テストコードが皆無でCI設定も確認できない
composer.json に phpunit が require-dev で存在するが、tests/ ディレクトリのテストファイルが提供されていない。ClaudeReviewService::parseJson() や GitHubService::parseUrl() のような境界値が多い関数にユニットテストがないと、プロンプト形式変更時のリグレッションを検出できない。
✅ 良い点
  • app/Jobs/ProcessReviewJob.php の sanitizeError() メソッドが `Bearer [REDACTED]` 置換を行っており、エラーログにAPIトークンが漏洩するリスクを防いでいる点は実務的に正しい対策。
  • app/Http/Controllers/ReviewController.php の store() と fix() 両エンドポイントで `RateLimiter::tooManyAttempts()` + IP の SHA-256 ハッシュキーによるレートリミットを独立して設けており、APIコスト爆発と濫用を双方向で抑制している。
  • app/Models/Review.php の `getOverallScoreAttribute()` / `getScoreLabelAttribute()` / `getScoreColorAttribute()` がモデル層にスコア表示ロジックをカプセル化しており、Viewに計算ロジックが散在するのを防いでいる。

作り切ることが第一歩。改善を続けることがエンジニアリング。

🔧 リファクタ提案
  • ClaudeReviewService.php のプロンプト生成ロジックを `buildFileSection(string $path, string $content): string` として単一メソッドに抽出し、review・fixIssue 両方で使い回す。エスケープ処理を一箇所に集約することでプロンプトインジェクション対策の漏れをなくす。
  • GitHubService::getFileContent() の結果を Laravel の Cache::remember() で TTL 1時間程度キャッシュし、ProcessReviewJob と ReviewController::fix() の二重フェッチを排除する。キャッシュキーは `github:{owner}:{repo}:{path}:{sha}` の形式でファイルのSHAを含めること。
  • Review モデルの overall_score / score_label / score_color の3アクセサを `ScorePresenter` ValueObject または `ReviewScore` DTOクラスに切り出し、モデルをデータ層に専念させる。将来的にスコア計算ロジックを変更する際の影響範囲を局所化できる。
🔒 セキュリティ注意点
  • ANTHROPIC_API_KEY と GITHUB_TOKEN は環境変数で渡されているが、Dockerfile に .dockerignore が確認できないため `docker build` 時に .env がイメージに含まれるリスクがある。.dockerignore に `.env` を明示的に追加し、docker-entrypoint.sh でのシークレット注入パターンを採用すること。
  • GitHubService::parseUrl() の出力 owner/repo 文字列は ClaudeReviewService::buildReviewPrompt() 内で preg_replace によるサニタイズが行われているが、GitHub API URLへの直接埋め込み(`/repos/{$owner}/{$repo}`)はサニタイズ前に行われている箇所がないか全フローを追跡し、URL インジェクションの経路を確認すること。
📤 PRコメント出力

このレビューをGitHub PRコメントとして貼り付けられるMarkdown形式で出力します。