
AWS Security AgentにGitHub PRレビューさせてみた
はじめに
みなさんこんにちは、クラウド事業本部コンサルティング部の浅野です。
AWS Security Agentは2026年3月31日にペネトレーションテスト機能がGAされましたが、コードレビューと設計レビューは2026年4月29日時点ではPreview扱いで料金ページにも記載がない状態です。
コードレビューは東京リージョンを含む利用可能リージョンで既に試せるため、個人のprivateリポジトリにつないで実際にPRをレビューさせてみました。本記事ではそのセットアップから動作確認までの手順を、スクショを貼りながらまとめます。
やってみた
エージェントスペースの作成
まずはエージェントスペースを作成します。コンソールで「AWS Security Agent」>「エージェントスペース」を開き、「セットアップアプリケーション」を押下します。

エージェントスペース名・説明・ユーザーアクセス方式を入力します。今回はSSOを使わないため IAM 専用アクセス を選択しました。
- エージェントスペース名:
demo-agent-space - 説明:
コードレビュー用スペース - ユーザーアクセス設定:
IAM 専用アクセス

サービスロールは利用可能な既存ロールがなかったため、自動生成された名前で新規作成しました。Encryptionも今回はAWS所有のキーをそのまま利用します。
- サービスロール名: 自動生成のまま
- Encryption: デフォルト(AWS所有のキー)

タグ画面は「Agent Space tags」と「Application tags」の2つに分かれています。Security Agentはコンソールから1回のセットアップで AWS::SecurityAgent::AgentSpace と AWS::SecurityAgent::Application という2つのリソースを同時に作成するため、それぞれに独立してタグを付与できる作りになっています。タグの効果は通常のAWSリソースタグと同じで、コスト配分・IAMポリシーの条件付与・リソース検索などに利用できます。今回はお試しなので何も設定せずに進めます。

「アプリケーションが正常に有効化されました」と表示されれば作成完了です。

GitHubリポジトリ設定
続いてGitHubリポジトリとの統合を作ります。「AWS Security Agent」>「統合」を開き、「統合を追加」を押下します。

統合タイプは GitHub を選択して次へ。
- 統合タイプ:
GitHub

接続画面はステップ1〜3の構成になっています。ステップ1の「GitHubでAWS Security Agentを開く」を押下し、GitHub Appsのインストール画面へ移動します。

GitHub App側で「設定する」を押下します。

対象リポジトリを選んでInstallします。今回は対象を絞って個別指定にしました。
- インストール先:
Only select repositories - 対象リポジトリ:
haruki-0408/demo-security-agent-review
※個人用の適当なプライベートリポジトリを選択しています。

AWSコンソールに戻り、ステップ2の「認証する」を押下します。

GitHubのAuthorize画面が開くので、AWS Security Agentのアクセスを許可します。

ステップ3で登録名とアカウントタイプを入力して接続を完了します。
- 登録名:
demo-security-agent-review-github - GitHubアカウントタイプ:
ユーザー

統合一覧に追加されていれば連携完了です。

コードレビューの有効化
エージェントスペース詳細画面に戻り、「コードレビュー」カードの「コードレビューを有効にする」を押下します。

先ほど作ったGitHub統合を選択して次へ。
- 統合の追加方法:
利用可能な登録 - 利用可能な登録:
demo-security-agent-review-github

レビュー対象のリポジトリを選択します。
- リポジトリ:
demo-security-agent-review

機能管理の画面でコードレビューが有効化済みになっていることを確認し、レビューモードを選びます。
- コードレビュー:
有効化済み - コードレビュー設定:
セキュリティ要件と脆弱性検出結果

公式ドキュメントによると、レビューモードは以下3種類から選べるようです。今回は組織のカスタム要件と一般的な脆弱性の両方を見てもらいたいので「セキュリティ要件と脆弱性検出結果」を選択しました。
| レビューモード | 適用範囲 |
|---|---|
| セキュリティ要件の検証 | コンソール側で有効化したカスタムのセキュリティ要件への準拠だけをチェック(要件が1つも有効化されていないとレビュー自体が実行されない) |
| セキュリティ脆弱性検出結果 | OWASP Top 10などの一般的な脆弱性パターンを検出 |
| セキュリティ要件と脆弱性検出結果 | 上記2つを併用したフルチェック |
以下のように統合リソースが追加され、コードレビューが有効化されました。

なお、左サイドバーの「セキュリティ要件」>「マネージドセキュリティ要件」を確認すると、AWSがあらかじめ用意した10件のマネージド要件が初期状態ですべて有効化されていました。詳細は公式ドキュメントを参照してください。
Audit Logging Best Practices: セキュリティ監視のための監査ログを担保Authentication Best Practices: 正当なユーザーのみがシステムにアクセスできるようにするAuthorization Best Practices: 認可のベストプラクティスに従うInformation Protection Best Practices: 機密データの機密性・完全性を保つLog Protection Best Practices: ログの完全性・機密性を保護するPrivileged Access Best Practices: 特権機能に対するガードレールを担保するSecret Protection Best Practices: 認証情報などのシークレットの機密性を保つSecure by Default Best Practices: システムのデフォルト設定をセキュアに保つTenant Isolation Best Practices: システムテナント間の分離を担保するTrusted Cryptography Best Practices: 信頼できる暗号実装のみを使う

PR & レビュー確認
セットアップが終わったので実際にPRをレビューさせます。検証用に以下2点の脆弱性を含むFlaskアプリを用意しました。
/previewエンドポイントでユーザー入力URLを検証なしでrequests.get()に渡している(SSRF / CWE-918)app.run(host="0.0.0.0", ...)で全ネットワークインターフェースに公開している
SSRFは内部リソースへの不正アクセスや認証情報の窃取に直結するため、おそらく先ほどの初期有効化されているマネージドセキュリティ要件(Information Protection Best Practices や Secure by Default Best Practices あたり)で検知される見込みです。
"""
URL preview API: 渡された URL のページタイトルを返す。
"""
import re
import requests
from flask import Flask, jsonify, request
app = Flask(__name__)
@app.route("/preview")
def preview():
url = request.args.get("url", "")
if not url:
return jsonify({"error": "url is required"}), 400
resp = requests.get(url, timeout=5)
title = re.search(r"<title>(.*?)</title>", resp.text, re.IGNORECASE | re.DOTALL)
return jsonify({
"title": title.group(1).strip() if title else None,
"snippet": resp.text[:500],
})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)
このコードを feature/url-preview ブランチに乗せて main 向けにPRを作成します。

PRを作成すると、aws-security-agent Botがすぐにレビュー開始のコメントを投稿してくれます。

数分ほど待つとレビュー結果が投稿されました。SSRFと0.0.0.0公開の2点を正しく検出してくれています。


レビュー本文の要約は以下です。
本PRにはマージ前に対応必須のセキュリティ脆弱性が2件含まれる。最も重大なのはURL fetchエンドポイントのSSRF。
1. SSRF (CWE-918)
url パラメータが検証なしで requests.get() に渡されている。
- http://169.254.169.254/latest/meta-data/iam/security-credentials/ を渡せばIMDSからLambda実行ロールの一時認証情報を取得できる
- スキーム検証がないため file:// 経由でローカルファイルを読み出せる
- リダイレクト追跡が既定で有効なためホスト名チェックをバイパスできる
- レスポンス先頭500バイトを snippet で返却しているため、Blindではなく完全に exfiltration 可能なSSRFになっている
推奨対策:
- URLスキームを https のみに制限
- ホスト名をIP解決し、RFC-1918・リンクローカル・ループバック等を拒否
- allow_redirects=False を設定
- 取得本文をそのまま返さない
2. 全ネットワークインターフェースへのバインド
app.run(host="0.0.0.0", ...) により公開ネットワークを含む全インターフェースに露出している。
開発時は 127.0.0.1 にバインドし、本番では特定IPへのバインドにファイアウォールと認証を併用する。
きちんと脆弱性が指摘されたので、レビュー内容に沿って以下の修正を行いました。
- URLスキームを
httpsのみに制限し、それ以外は400で弾く - ホスト名をIP解決し、プライベート/ループバック/リンクローカル/予約済みレンジを拒否
allow_redirects=Falseを設定してリダイレクト経由のホスト名チェックバイパスを防ぐ- レスポンス本文(
snippet)の返却を廃止し、タイトルのみ返すよう変更 app.runのバインド先を127.0.0.1に変更
"""
URL preview API: 渡された URL のページタイトルを返す。
"""
import ipaddress
import re
import socket
from urllib.parse import urlparse
import requests
from flask import Flask, jsonify, request
app = Flask(__name__)
def is_safe_url(url: str) -> bool:
parsed = urlparse(url)
if parsed.scheme != "https" or not parsed.hostname:
return False
try:
ip = ipaddress.ip_address(socket.gethostbyname(parsed.hostname))
except (socket.gaierror, ValueError):
return False
return not (ip.is_private or ip.is_loopback or ip.is_link_local or ip.is_reserved)
@app.route("/preview")
def preview():
url = request.args.get("url", "")
if not url:
return jsonify({"error": "url is required"}), 400
if not is_safe_url(url):
return jsonify({"error": "url is not allowed"}), 400
resp = requests.get(url, timeout=5, allow_redirects=False)
title = re.search(r"<title>(.*?)</title>", resp.text, re.IGNORECASE | re.DOTALL)
return jsonify({"title": title.group(1).strip() if title else None})
if __name__ == "__main__":
app.run(host="127.0.0.1", port=5000)
修正コミットを同じブランチにpushすると、Security Agentが自動で再レビューしてくれます。今回は指摘がすべて解消されたため No issues identified. と返ってきました。

最後に
GitHub Appsを入れてリポジトリを紐づけるだけで動き始めるので、思っていたより導入のハードルは低い印象でした。レビュー精度も今回の検証では文句なしで、SSRFの攻撃シナリオを具体的に書き出してくれた点はかなり実用的だなと感じています。
一方でPreview扱いの機能ということもあり、レビューをマージ条件として強制する仕組みや結果を別サービスへ流す手段はまだ揃っておらず、運用に組み込む場合は周辺ツールの作り込みが必要そうです。GA時点で改めて状況を追っていこうと思います。
今回は以上です。最後までお読みいただきありがとうございました。







