APC 技術ブログ

株式会社エーピーコミュニケーションズの技術ブログです。

株式会社 エーピーコミュニケーションズの技術ブログです。

GHASをパブリックリポジトリで無料試用したら、AIアプリの脆弱性が想像以上に見えた話

こんにちは、エーピーコミュニケーションズ ACS事業部の福井です。
最近、AI系のセキュリティ標準である OWASP AISVS(Artificial Intelligence Security Verification Standard)を勉強しながら、GitHub Advanced Security(GHAS)との組み合わせを検証していました。
「GHASって有料じゃないの?」と思われるかもしれませんが、実はパブリックリポジトリなら全機能が無料で使えます。
せっかくなので、意図的に脆弱性を仕込んだ AI アプリのデモプロジェクトを作って、GHAS に読ませてみました。

その結果が、予想以上に面白かったんです。

GHAS とは何か、そしてなぜ試したか

GHAS(GitHub Advanced Security)は、GitHub が提供するセキュリティ機能の総称です。
主な機能は以下の3つで構成されています。

機能 役割 学習・運用上のメリット
CodeQL 静的解析(SAST) コードの「論理」を追跡し、脆弱性のデータフローを検知
Dependabot 依存関係解析(SCA) 脆弱なライブラリを検知し、自動で修正 PR を作成
Secret Scanning 秘匿情報検知 APIキー等の漏洩を Push 前にブロック(Push Protection)

通常はエンタープライズ向けの有料機能ですが、パブリックリポジトリに限りすべてが無料で提供されています。
私が取り組んでいた AISVS の検証ともセットで動作を確認したくなり、意図的に脆弱性を埋め込んだデモリポジトリを作って試してみました。

デモプロジェクトAI 搭載の便利ツールを作ってみる。

「AI 搭載の便利ツール」を装いつつ、OWASP Top 10 および LLM 特有の脆弱性を凝縮した最小構成のリポジトリを用意しました。
Python(Flask)で書いた Web アプリに、以下の脆弱なシナリオを意図的に実装しています。

  • Prompt Injection(LLM01): ユーザー入力をそのままプロンプトに結合
  • SSRF(A10:2021): 指定 URL へのバリデーションなしリクエスト
  • XSS(A03:2021): AI の回答を innerHTML でサニタイズなしの出力
  • スタックトレース漏洩: 例外メッセージをそのままレスポンスに返す

いわゆる「悪い書き方の見本帳」です。
これを GitHub のパブリックリポジトリに push して、GHAS がどこまで検知できるかを確認しました。

Secret Scanning:「万能ではない」を体で学んだ

まず試したのが Secret Scanning の Push Protection です。
OpenAI の API キーを main.py に直書きして push すると、ターミナルに以下のメッセージが出てブロックされました。

remote: error: GH013: Repository rule violations found for refs/heads/main.
remote:
remote: - GITHUB PUSH PROTECTION
remote:   ——————————————————————————————————————————
remote:     Resolve the following violations before pushing again
remote:
remote:     - Push cannot contain secrets
remote:
remote:       OpenAI API Key
remote:        locations:
remote:          - commit: 69f5cc3a03df0d0d28cd6245eea5cb9b2f47a7ab
remote:            path: app/main.py:9
remote:
 ! [remote rejected] main -> main (push declined due to repository rule violations)

「おお、本当に弾かれた……」

たった1回の push でこれだけ分かりやすいブロックが入るのは、確かに効果的だと思いました。
「漏洩してから消す」のではなく「push の瞬間に止める」のが Push Protection の思想で、そこは体験してみると腑に落ちます。

ダミーキーを使ったら、スルーされた

次に面白い発見がありました。
テスト用として以下のような値を書いてみたところ、Secret Scanning は何も反応しませんでした。

DUMMY_OPENAI_API_KEY = "sk-SampleDemoKeyForGHAS000000000000000000000000000"

「あれ? 検知されない……」

理由は、Secret Scanning が「パターンマッチング+エントロピー計算」に基づいているからです。
000000000... のような繰り返し文字列は「低エントロピー」と判断され、テスト用の無害なデータとして除外されます。
また、文字列を分割して結合するようなコードも同様にスルーされます。

# これは検知される
KEY = "sk-proj-ABC123DEF456..."

# これは(通常)検知されない
PREFIX = "sk-proj-"
SECRET = "ABC123DEF456..."
KEY = PREFIX + SECRET

「ツールが反応しないからといって、そのコードが安全である証明にはならない」——この当たり前のことを、手を動かして初めて実感しました。

Code scanning(CodeQL):「意味」を追跡するスキャンの威力

Secret Scanning が「形」を見るのに対して、CodeQL は「意味」を見ます。
gh コマンドでスキャン結果を取得してみると、アラートが5件検出されていました。

gh api repos/apc-yfukui/GHAS_sample/code-scanning/alerts \
  --jq '[.[] | {number: .number, rule_id: .rule.id, severity: .rule.security_severity_level, message: .most_recent_instance.message.text}]'

UIではこのように出ていました。

アラート番号 Rule ID 深刻度 内容の要約
2 py/full-ssrf Critical ユーザー指定の URL にサーバーが直接アクセス(SSRF)
3, 4, 5 py/reflective-xss Medium ユーザー入力をそのまま画面に返す(XSS)
1 py/stack-trace-exposure Medium 例外メッセージをそのままレスポンスに返す

特に「SSRF が Critical」というのは見ていて納得感がありました。
「URL からドキュメントを取得して AI に読み込ませる」という機能は、バリデーションがなければ内部ネットワークへの探索に使われる可能性があります。
「便利だと思っていた機能が、実は致命的な脆弱性だった」という気づきは、GHASを回してみて初めて得られたものです。

Secret Scanning と CodeQL の違い

観点 Secret Scanning CodeQL
何を見るか 「形」(パターンマッチング) 「意味」(データフロー解析)
強み 既知フォーマットの認証情報を高速検知 ロジックの欠陥(XSS・SSRF・インジェクション)を確実に検知
弱点 分割・難読化・低エントロピーで回避される 設定・実行に時間がかかる

両者は「守備範囲が違う」ので、どちらか一方で十分ということにはなりません。
セットで使うことで、コードレベルのセキュリティ衛生を維持できるという構造です。

Dependabot:「何もしなくても PR が届く」体験

GHAS を有効にしておくと、依存ライブラリに脆弱性が登録された際、Dependabot が自動で修正 PR を作成してくれます。
今回のデモリポジトリでも、古いバージョンのライブラリに対して PR が届きました。

「何もしていないのに PR が来た……これは確かに便利だな」

ただ、Dependabot の PR は「このバージョンを上げてください」という通知であり、「自分のコードのどのパスで実際に影響が出るか」までは教えてくれません。
そこで有効なのが GitHub Copilot との組み合わせです。
Dependabot の PR の差分を GitHub Copilot CLI に読み込ませると、「この変更が自分のコードに本当に影響するか」「破壊的変更はないか」を対話的に確認できます。

gh pr view <PR番号> | gh copilot explain

gh pr view で PR の内容(タイトル・本文・差分サマリー)をテキストとして取得し、gh copilot explain に渡しています。
gh copilot explain は GitHub Copilot CLI のサブコマンドで、標準入力に渡したテキストを AI が自然言語で解説してくれます。特定の GHAS 機能というわけではなく、「GHAS が出力した情報を Copilot で読み解く」という AI 活用の組み合わせです。

以下のようにプロンプトにURLを渡してしまってもghコマンドで探しにいって調査結果を返してくれるので影響範囲の調査も容易になります。

「GHAS で検知し、Copilot で分析・検証する」——これが今のところ私が考えるモダンなセキュア開発の流れです。

GHAS が網羅できない領域:AISVS との連携

GHAS は非常に強力ですが、「コードとしての欠陥」を見つけるツールです。
AI システム特有の問題——たとえば「このモデルの学習データにバイアスがないか」「出力が意図せず機密情報を含んでいないか」——は、GHAS だけでは検証できません。

そこで、以下のような役割分担が見えてきました。

ツール 守備範囲 具体例
GHAS(Code scanning/Dependabot/Secret Scanning) コード・インフラ・依存関係の欠陥 XSS, SSRF, 脆弱なライブラリ, シークレット漏洩
OWASP AISVS スキル AI システムとしての欠陥 データポイズニング, モデルの出力の安全性, プロンプトインジェクション対策の妥当性

AISVS の詳細は OWASP AISVS GitHub リポジトリで公開されています。

AISVS は「GHAS(コードレベル)」と「AIシステムとしての振る舞い(モデルレベル)」の間を埋める基準です。
私はこのスキルを GitHub Copilot CLI のSkillsとして開発しており、GHAS の検知結果と突き合わせることで、「なぜこのコードが AISVS のどのコントロールに抵触するか」をマッピングする運用を試みています。
GHAS は自動スキャン、AISVS スキルはプロセス・検証の役割を担う——この多層防御の構造が、2026 年以降の AI ガバナンス要件に対応する現実的なアプローチだと考えています。

おわりに

「GHASは、コードの脆弱性を炙り出す鏡だった」

パブリックリポジトリなら全機能が無料で使えるという事実は、思った以上に価値が高いと感じました。
特に「意図的に脆弱なコードを書いて、ツールがどこまで検知するかを試す」という学習方法は、セキュリティを肌感覚で理解するのに非常に効果的でした。

Secret Scanning の限界(低エントロピーな文字列はスルー)を知らずに使っていると、「スキャンが通った=安全」という誤った安心感を持つかもしれません。
ツールの裏側にあるロジックを理解した上で使うことで、はじめて本当の意味での「多層防御」が組めると思います。
AIアプリのセキュリティが気になっている方は、ぜひパブリックリポジトリで一度試してみてください。


ACS 事業部のご紹介

私の所属する ACS 事業部では、開発者ポータル Backstage、Azure AI Service などを活用し、Platform Engineering + AI の推進・内製化を支援しています。

www.ap-com.co.jp www.ap-com.co.jp www.ap-com.co.jp

また、GitHub パートナーとしてお客様に GitHub ソリューションの導入支援を行っています。 GitHub Copilot などのトレーニングなども行っておりますので、ご興味を持っていただけましたらぜひお声がけいただけますと幸いです。

一緒に働いていただける仲間も募集中です! ご興味持っていただけましたらぜひお声がけください。 ※求人名の冒頭に【ACSD】と入っている求人が当事業部の求人です。

www.ap-com.co.jp www.ap-com.co.jp

本記事の投稿者: 福井
本記事は GitHub Copilot に伴走してもらいながら書き上げました。構成・表現の整理にAIを活用しつつ、体験談・検証・最終判断はすべて著者本人によるものです。