AIによる脆弱性診断gem『Omamori』をリリースしました

脆弱性診断ツール『Omamori』

omamori
Omamoriはプログラミング初心者が発生させがちな脆弱性を診断するツールです。
AI(Gemini API)による診断と静的解析ツールによる診断を同時に行うことができます。
静的解析にはBrakemanとbundler-auditを使っています。
この記事では簡単なOmamoriの説明を行います。

使い方

リポジトリに含まれるdemoディレクトリ配下には様々な脆弱性を含んだファイルが含まれています。
これらのファイルを使って実際に脆弱性診断される様子を見てみましょう。

準備

git clone https://github.com/rira100000000/omamori.git
cd omamori
  • gem をインストールします
gem install omamori
  • 解析したいコードをコピーしステージングします
cp -r demo demo_
git add demo_

コンフィグの設定

  • コンフィグファイル(.omamorirc)を作成します
omamori init
  • .omamorircに以下のようにAPIキーを記述します
api_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  • モデルを指定したい場合、以下のように書きます
model: gemini-2.5-flash-preview-04-17
language: ja

実行

  • 解析を実行します
omamori scan
  • AI解析だけ実行したい場合、--aiオプションが使えます。(静的解析がスキップされます)
omamori scan --ai

実行結果

AI診断で7か所、Brakemanでは2か所の脆弱性が指摘されています。
AI診断の詳細は以下のように表示されます。

脆弱性のタイプ、重大性、該当箇所、詳細、実際のコードが表示されます。(デモファイル自体に脆弱性の詳細が書いてあるので Code Snippetがごちゃごちゃして見づらいですね…)

以下のように様々な脆弱性が検出されています。

AI診断では以下のように脆弱性を定義しており、これらを発見することに努めます(実装では英語で書かれています)

RISK_PROMPTS = {
  xss:                           "XSS(クロスサイトスクリプティング):ユーザー入力が適切にエスケープされず HTML や JavaScript に埋め込まれ、他ユーザーのブラウザ上で任意スクリプトが実行される脆弱性。入力値のサニタイズ漏れや出力時エンコーディング不備を検知。",
  csrf:                          "CSRF(クロスサイトリクエストフォージェリ):ユーザーの認証済みセッションを悪用し、意図しないリクエストを第三者サイトから実行させる攻撃。トークン検証不足や Referer チェック漏れパターンを検出。",
  idor:                          "IDOR(Insecure Direct Object Reference):アクセス制御チェックなしに連番や直接的なオブジェクト参照を行い、他ユーザーのデータを取得・操作できる脆弱性。パラメータ値の検証・権限チェック漏れを見つける。",
  open_redirect:                 "オープンリダイレクト:外部サイトへのリダイレクト先をパラメータで受け取り、正当性検証なしに転送する脆弱性。ホワイトリストチェックやドメイン制限の欠如を検知。",
  ssrf:                          "SSRF(Server-Side Request Forgery):外部から指定された URL にサーバー自身がリクエストを送信し、内部ネットワーク資源やメタデータを不正取得する脆弱性。URL バリデーション不足を検出。",
  session_fixation:              "セッション固定(Session Fixation):攻撃者があらかじめ用意したセッション ID を利用者に使わせ、認証後も同一セッションでアクセスさせる設計上の欠陥。セッション再生成漏れを検出。",
  inappropriate_cookie_attributes: "不適切なクッキー属性:HttpOnly, Secure, SameSite といった重要属性が未設定で、XSS や CSRF、セッションハイジャックを許す設定ミスを検知。",
  insufficient_encryption:       "不十分な暗号化設定:MD5 や SHA1 といった脆弱なハッシュ、平文送信や鍵長不足の暗号を利用しているパターンを検出。",
  insecure_deserialization_rce:   "インセキュアなデシリアライズによる RCE:外部入力をそのままオブジェクト復元に使い、任意コード実行を招く。信頼しないデータのデシリアライズ箇所を見つける。",
  directory_traversal:           "ディレクトリ・トラバーサル:パスに「../」などを含めることで上位ディレクトリへ不正アクセスする脆弱性。入力パスの正規化・バリデーション不足を検出。",
  dangerous_eval:                "危険な eval/動的コード実行:ユーザー入力を eval, exec, new Function などで評価し、任意コード実行可能となるコードを検出。",
  inappropriate_file_permissions:  "不適切なファイルパーミッション:ファイルやディレクトリが 777 モードなどで公開され、意図しない読み書き・削除を許可している設定ミスを検出。",
  temporary_backup_file_leak:     "テンポラリ・バックアップファイルの漏洩:*.bak, *.tmp, ~ ファイルが公開ディレクトリに残存し、ソースコードや機密情報が流出するパターンを検知。",
  overly_detailed_errors:        "詳細すぎるエラーメッセージ:スタックトレースや SQL 文、ファイルパスなど内部情報をクライアントへ出力している箇所を検出。",
  csp_not_set:                   "CSP(Content Security Policy)未設定:XSS 防御のための CSP ヘッダーがレスポンスに含まれていないパターンを検出。",
  mime_sniffing_vulnerability:   "MIME スニッフィング対策漏れ:X-Content-Type-Options: nosniff が未設定で、ブラウザがコンテンツを誤解釈するリスクを検知。",
  clickjacking_vulnerability:    "クリックジャッキング対策漏れ:X-Frame-Options や Content-Security-Policy: frame-ancestors が未設定・不適切で、クリックジャッキングを許す箇所を検出。",
  auto_index_exposure:           "オートインデックス公開:ディレクトリリスティングが有効化され、ファイル一覧が外部から参照可能な設定ミスを検知。",
  inappropriate_password_policy: "不適切なパスワードポリシー:最小文字数不足、複雑性ルール欠如、ブルートフォース防御なしのパターンを検出。",
  two_factor_auth_missing:       "二要素認証未導入:認証フローに SMS や TOTP など 2FA 要素が存在せず、認証強度が低い箇所を検出。",
  race_condition:                "レースコンディション:並行アクセスで不整合状態を招くロック・排他制御不足のコードを検出。",
  server_error_information_exposure: "サーバーエラー情報の曝露:500 エラー応答時に詳細情報を出力し、内部実装情報を漏出している箇所を検出。",
  dependency_trojan_package:     "依存関係のトロージャンパッケージ:npm, pip 等で公式外や名前詐称パッケージをインストールしているリスクを検出。",
  api_overexposure:              "API 過剰公開:認証不要のエンドポイントや過剰なデータ返却を行い、情報漏洩を招く実装を検出。",
  security_middleware_disabled:  "セキュリティミドルウェア無効化:CSRF 保護や入力サニタイズをオフにしている設定箇所を検出。",
  security_header_inconsistency: "セキュリティヘッダー未統一:XSS, CSRF 防御ヘッダーの欠如や環境ごとの不整合を検出。",
  excessive_login_attempts:      "過剰なログイン試行許可:レートリミット未設定でブルートフォース攻撃を受けやすい実装を検出。",
  inappropriate_cache_settings:  "不適切なキャッシュ設定:認証ページに public キャッシュを設定し、機密情報をキャッシュさせる設定ミスを検出。",
  secret_key_committed:          "秘密鍵・JWT シークレットのコミット:リポジトリに .env や設定ファイルで秘密情報を直接書き込んでいる差分を検出。",
  third_party_script_validation_missing: "サードパーティスクリプト検証欠如:外部スクリプト読み込み時の署名・ハッシュ検証を行っていない実装を検出。",
  over_logging:                  "オーバーロギング:パスワードやトークンなど機密情報をログ出力している箇所を検出。",
  fail_open_design:              "フェイルオープン設計:エラー時に安全拒否ではなく許可動作するコードパスを検出。",
  environment_differences:       "環境間設定差異放置:開発/本番でセキュリティ設定が異なるままデプロイしている差分を検出。",
  audit_log_missing:             "監査ログ欠如:重要操作や認可チェック結果をログに記録していない箇所を検出。",
  time_based_side_channel:       "タイムベースのサイドチャネル:処理時間差で秘密情報を推測可能な実装を検出(例:文字列比較のタイミング差)。",
}.freeze

結論

Omamoriを使うことで脆弱性を発見することができましたが、AI診断の精度にはかなりのムラがあります。
デモファイルでも何回か診断すると発見される脆弱性が4件程度になったり、発見されづらい(できない)脆弱性があることがわかりました。
利用するモデルによって精度もかわるので、今後モデルが賢くなることでさらに安全に使うことができるようになるとは思います。
また、名前の通りこのgemはあくまでも「お守り」であり、プログラムの安全性を保証するものではありません。人間がきちんとチェックした上で発生してしまった脆弱性をもしかしたら発見してくれるかもしれない、というあくまで補助的な性能であることを理解した上で利用いただければと思います。

※プロンプトエンジニアリングで精度が向上しました プロンプトエンジニアリングでOmamori Gemの精度向上を目指す - rira100000000のブログ

お気持ち

ここからはgemを作った動機や作った過程、感想になります。作者に興味がない人は読まなくて大丈夫です。

作った動機

先日、GeminiのAPIを叩くgemを作りました。

ruby-gemini-api

コードのほとんどをAIに書かせたのですが、gemを作って公開するにあたり、一番気を使ったのはユーザーが不利益を被るような実装が含まれていないか、ということでした。
今後バイブコーディングで何かを作る人、プログラミングの入り口としてバイブコーディングを選択するという人は増えると予想されます。
ですが、脆弱性に関する知識のない人がコードやプログラムを公開してもいいのでしょうか?
別の言い方をすれば、脆弱性に関する完璧な知識が無ければプログラムを公開してはいけないのでしょうか?
私としては誰もが気ままにプログラムを作って、気軽に公開できる世界の方が楽しいと思います。しかし、セキュリティ面を全く無視したプログラムがあふれるのも望むところではなく、脆弱性に関する知識も必要だと思います。
そこで、バイブコーディングで作ったコードの脆弱性診断をAI自身にやらせようという発想が生まれ、Omamoriを作りました。

作ってみて

gemini-2.5-flashを持ってしても診断精度は決して高くないというやや残念な結果にはなりました。
LLMを使って診断する以上、精度にブレが発生することは想定していましたが、想定よりも性能が低い感は否めません。
しかしLLMへの期待感はむしろ上がりました。今回はコーディングのほとんどをClineにやらせました。モデルはgemini-2.5-flashを利用しました。
API利用料は全体で1000円かかってないくらいです。Claude 3.7 Sonnetに比べて格段に安く、性能も十分に感じました。
実装にかかった時間は約2.5日といったところでしょうか。
READMEは自分で書いたものよりDeepWikiの方が詳しくて衝撃を受けました。README書かなくてよくなったら嬉しいですね。

https://deepwiki.com/rira100000000/omamori

おしまい

今後の展望としてはGemini以外のモデルも使えるようにできるといいと思うのですが、OpenAIやAnthropicはRuby公式SDKが出たばかりなのでちょっと様子を見たい気もします。
GeminiのAPIは無料枠もあるので興味があれば使ってみてください~。