小さな Web プロジェクトをリリースするたびに、セキュリティのチェックリストはいつも同じです。SSL テストを走らせる。ヘッダーを確認する。本番サイトに対して nuclei を実行する。忘れられたサブドメインを見つけるために subfinder を実行する。ソースに対して semgrep、trivy、gitleaks を実行する。ターミナルのタブを 7 枚開き、ブラウザのタブを 12 枚開き、結果を貼り付ける Markdown ファイルを 1 つ用意する。3 か月後、また同じことを繰り返し、何をすでに直したかを思い出そうとする。
ツールそのものは優れています。混乱しているのは、その周りのワークフローのほうです。だから secscan を書きました。一連のツールを代わりに走らせ、3 つの形式でひとつのレポートを生成し、任意で LLM を使って各検出を実際に手を動かせる助言に変える、Python のラッパーです。MIT ライセンスで PyPI にあります。
この記事は、設計上の選択と、意図的にやっていないことについてのものです。すでに Snyk や Tenable のような有料製品を使っているなら、これは必要ないと思います。小さな VPS で個人プロジェクトを動かしている個人開発者や小さなチームで、ある程度マシなセキュリティ基盤がほしいなら、続きを読んでください。
課題
Web セキュリティの検査は分断されています。優れたオープンソースのツールはそれぞれが一部しかカバーしません:
nuclei— テンプレート型の脆弱性チェックnmap— ポートとサービスの調査subfinderとhttpx— サブドメイン列挙とライブホスト検出sslyze— TLS 設定- OWASP ZAP — スパイダーとアクティブスキャン
semgrep— ソースコードのパターンtrivy— コンテナと依存関係の CVEgitleaks— Git 履歴に漏れているシークレット
それぞれに独自の CLI、出力形式、クセがあります。完全な像を得るためにはすべてを実行し、出力をドキュメントに貼り付けてトリアージすることになります。共通スキーマがないため、ツール間での重複排除はあなたの責任です。
もうひとつの失敗パターンが、修正提案のギャップです。Strict-Transport-Security ヘッダーがない という検出を得ても、付いてくるのは「Strict-Transport-Security ヘッダーを追加してください」という汎用的なアドバイス。HSTS を以前に設定したことがあれば役に立ちます。設定したことがなく、サイトが Cloudflare、Vercel、Astro の _headers ファイル、nginx の設定、あるいはそのすべての背後にあるかどうかを把握していないのなら、役には立ちません。
ひとつのコマンドで一連の検査を走らせ、統合レポートを生成し、修正をどこに置くべきかを示してくれるものがほしかったのです。
secscan とは
secscan は Click 製の CLI と、小さな FastAPI 製ダッシュボードです。上記のツールを取りまとめ(置き換えるのではなく)、検出を共通の形に正規化し、HTML、Markdown、JSON の統合レポートをレンダリングします。
pip install secscan-tool
secscan scan https://example.com
これで、安全なスキャンが実行されます — ヘッダー、TLS、サブドメイン列挙、ライブホスト検出、ポートスキャン、nuclei テンプレート。--repo でリポジトリを指定すれば、semgrep、trivy、gitleaks がソースコードに対して走ります。各スキャナーには safe、low、medium、high のリスクレーティングが付いています。medium 以上は --i-accept-risk なしでは実行されず、実行前にこれから何をするかを表示します。意図はツールを煩わせるためではありません。攻撃的な nmap や ZAP のフルアクティブスキャンを本番サイトに誤って撃ち込むことを難しくしつつ、行儀の良いほうは簡単に走らせられるようにすることです。
ダッシュボードはブラウザ越しに同じことができます。ターゲットを選び、スキャナーを選び、実行をクリック。進捗を見て、レポートをその場で読みます。
レポートは ./reports/<target>-<timestamp>/ に report.html、report.md、report.json として書き出されます。HTML は読むため。Markdown はリポジトリにコミットしたり、PR に貼ったりするため。JSON は CI で自由に処理するためのものです。
仕組み
コードベースは 4 つのパートで構成されています。
scanners/ にはスキャナーごとに 1 ファイルあります。各クラスは BaseScanner を継承し、リスクレベルと必要な外部ツールを宣言し、_run() を実装して Finding オブジェクトを結果に追加します。プラグインシステムのような魔法はありません。新しいスキャナーは scanners/__init__.py に明示的に登録します。追加には大体 50 行 — サブクラス化、リスクの設定、ツールへのシェルアウト、出力のパース、Findings の追加。
runner.py はスキャナーを統括し、リスクゲートを適用し、安全な範囲で並列化し、結果を集約します。リスクゲートはここで適用されるので、CLI ではなく、ダッシュボードと GitHub Action は同じチェックを共有します。
reports/ には HTML(Jinja2 テンプレート)、Markdown、JSON のレンダラーが分離されています。同じ検出データに対する 3 つのビュー。これらを分離しているおかげで、JSON スキーマを変えても HTML に手を入れる必要はありません。CI が JSON に依存し始めたとき、これは効いてきます。
remediation/ は検出に修正アドバイスを付加します。次にこの話をします。
CI には GitHub Actions のワークフローを同梱しています。.github/workflows/ に置き、ターゲットをリポジトリ変数として設定すれば、週次のスキャンとオンデマンド実行が手に入ります。レポートはアーティファクトとしてアップロードされます。新しい High または Critical の検出が出たら、Issue が立ちます。
修正提案レイヤー
このパートが、いちばん楽しかったところです。
スキャナーが検出を返すと、「Missing Content-Security-Policy」のような短いタイトルが返ってきます。汎用的なアドバイスは、検出のシグネチャをキーとした手書きのデータベース(remediation/static_db.py)に置かれています。静的 DB は HSTS、CSP、欠けているセキュリティヘッダー、非推奨の TLS、Redis・MongoDB・SMB などのサービス露出、デフォルトの認証情報、漏れたシークレットなどをカバーします。キュレーションされており、生成されたものではありません。このレイヤーは API キーなしで無料で使えます。
2 つ目のレイヤーは任意です。ANTHROPIC_API_KEY を設定すると、secscan は各検出を関連する文脈と一緒に Claude に送ります。コードに関する検出(semgrep、trivy、gitleaks)では、該当箇所周辺の行を含めます。ヘッダーに関する検出では、見つかれば _headers、vercel.json、astro.config.* ファイルを含めます。モデルは汎用的な修正の代わりに、文脈に即した修正を返します。
実際の違い:「Strict-Transport-Security ヘッダーを追加してください」ではなく、追加すべき行そのもの、入れるべきファイル、すでに動作している CSP を持ちワイルドカードのサブドメインを配信しているサイトに適切な max-age とディレクティブが返ってきます。モデルが間違うこともあります。間違えたときには、静的 DB のフォールバックがすぐ後ろに控えています。
コストは Sonnet で 1 スキャンあたり数セントに収まります。検出はハッシュでキャッシュされるため、同じターゲットを再スキャンしても以前の修正提案が再利用されます。プライバシーについて:デフォルトでは、コード片と設定ファイルはマシンを離れます。--no-code フラグはこれをローカルに留め、検出のメタデータだけを送ります。--no-ai フラグは API を完全にスキップし、静的 DB にフォールバックします。リポジトリに何か機微なものを向ける前に、考えておく価値があります。
試し方
合うものを選んでください。
ローカルインストール:
pip install secscan-tool
secscan scan https://example.com
Docker。nuclei、nmap、subfinder、httpx、trivy、semgrep、gitleaks を同梱しています:
git clone https://github.com/Jitesh17/secscan.git
cd secscan
export ANTHROPIC_API_KEY=sk-ant-... # 任意
docker compose up -d
# http://localhost:8765 を開く
GitHub Actions:
cp .github/workflows/security-scan.yml YOUR_REPO/.github/workflows/
ターゲット URL をリポジトリ変数として設定します。週次のスキャンと workflow_dispatch トリガーが手に入ります。
何ではないか、次に何をするか
secscan が何ではないかを明確にしておく価値があります。
OWASP ZAP や Burp Suite の代替ではありません。これらはプロキシ、傍受、ファズワークフローを備えたインタラクティブな Web アプリのペンテストツールです。ZAP の自動スキャンはここで包んでいますが、Burp が提供する手動ワークフローは別物です。
SAST 製品ではありません。Semgrep は素晴らしく、secscan も実行しますが、自分のスタックに合わせてチューニングされたルールで PR ブロックする SAST が必要なら、Snyk、Sonar、または Semgrep のホスティング製品を見てください。
脆弱性管理プラットフォームでもありません。何十ものサービスにわたって何百もの検出を持つようになったら、所有者の追跡、ツール間の重複排除、バックログの消化を行うために、DefectDojo のようなものか、マネージド製品が欲しくなります。secscan はレポートを生成します。そのライフサイクルは管理しません。
荒削りな点もあります。認証付きスキャンのサポートはまだありません。クッキーとベアラートークンはリストに載っています。AI による補強は、よく知られた検出カテゴリには有効ですが、新しい、または複合的な検出には汎用的な助言が返ります。重大度の自動付与はベストエフォートで、人がトリアージする必要があります。ダッシュボードはシングルテナントで認証なし。ローカルか、自分のリバースプロキシの背後で実行してください。少数の個人プロジェクトでテストしただけなので、驚きはあるはずです。
次に追加したいもの:
- ソースコード系スキャナーのための pre-commit フック
- GitHub Action が検出を人の目に届くところに投稿するための、Slack と Teams への Webhook
- 認証付きスキャンのサポート、まずはクッキーベース認証から
- ダッシュボードがあなたの入力した URL だけでなく、より広いアタックサーフェスを把握できるよう、
dnsxとkatanaの任意統合
試してみて何か壊れたら、Issue を立ててください。secscan 自体にセキュリティバグを見つけたら、公開前に修正できるよう、まず gosar95@gmail.com までメールしてください。
ホスト版
CLI は無料・オープンソースのまま続けます。自分でホストするより、スケジュールされたスキャン、メールで届くレポート、セットアップなしで使いたい方向けに、週次スキャンのホスト版も準備中です。secscan.jinovasystems.com でウェイトリストに登録できます。