Claude CodeにStackHawkのスキルを入れてHawkScanを回す手順
StackHawkの4スキル(hawkscan・stackhawk-api・hawkscan-ci・stackhawk-data-seed)の役割、HAWK_API_KEYの用意、wingmanでの導入、自動スキャンが動く条件を解説します。
StackHawkのエージェントスキルを入れると、Claude Codeが自分で書いたコードを実行中のアプリに対してDAST(動的アプリケーションセキュリティテスト)にかけ、見つかった脆弱性を直して再スキャンするところまで回します。導入は2コマンド、前提はhawkCLI v6.0.0以降とAPIキーです。
スキルは4つあり、役割が分かれています。hawkscanが走査と修正、stackhawk-apiが報告、hawkscan-ciがCI組み込み、stackhawk-data-seedが走査用データの用意です。ただしREADMEとdocsで導入先やスキルの数え方が食い違う箇所があります。挙動はスキルごとのSKILL.mdに定義されていて、READMEやdocsとは食い違う箇所があります。該当箇所は後ろの節で並べます。
4つのスキルは何を担当するか
StackHawk側の説明では、4つで1本の流れになります。コードを変えたらhawkscanで走査して直し、状況はstackhawk-apiで見て、問題なければhawkscan-ciでCIへ上げます。走査が空振りするときだけstackhawk-data-seedを挟みます。
4つのスキルの持ち場
hawkscan
stackhawk.ymlの生成、検証、スキャン実行、結果の解析、修正、再スキャンまでを担当します。実装を終えた直後に自律で動く唯一のスキルです。stackhawk-api
StackHawkのプラットフォームに問い合わせて、アプリ横断の状況や直近のスキャンの差分を報告します。読み取り専用です。
hawkscan-ci
ローカルで動くスキャンをCIのワークフローファイルに移します。CIプロバイダーを検出し、ファイルを書くか追記するところで止まります。
stackhawk-data-seed
hawk perch seedを使い、スキャンが奥まで届くための初期データ(SQL・HTTP・gRPCなど)を生成します。
もう1つ、stackhawk-optimizeというスキルが存在します。READMEの見出しは「Four Skills」でhawkscan-ciを数え、optimizeは数えません。一方docsはhawkscan・stackhawk-api・data-seed・optimizeの4つを一覧にし、hawkscan-ciを載せていません。どちらも「4つ」ですが中身が違うので、導入時にどれが入るかを後述の手順で確かめてください。
導入前に用意するもの
要るのは次の3つです。
- StackHawkのアカウント。READMEは14日間の無料体験(カード不要)を案内しています。docsの前提には、プランとしてSecure・Scale・Wingmanが挙がっています
hawkCLI v6.0.0以降。単一バイナリで、以前は別物だったhawkopはhawk opとして同梱され、Javaは不要です- スキャン対象のアプリがローカルで起動していて、
hawkから届くこと。ソースコードも同じ作業ツリーに必要です
hawkscanスキルは最初にhawk versionでバージョンを確かめ、hawk config --helpが通らなければ「v6.0.0以降へ上げてください」と止まる作りです。古いhawkのままだと、スキルを入れても何も進みません。
HAWK_API_KEYを用意する
認証は2通りあります。
- 手元の対話環境なら
hawk init --browserを実行します。ブラウザで承認すると、APIキーが作られて~/.hawk/hawk.propertiesに保存されます。コピー&ペーストは要りません - 自分でキーを管理するなら、app.stackhawk.comにログインしてSettings → API Keysでキーを作り、環境変数に入れます
# 手元の対話環境(ブラウザで承認)
hawk init --browser
# キーを自分で管理する場合(キーの形は hawk.<id>.<secret>)
export HAWK_API_KEY=hawk.xxxxxxxxxxxx.xxxxxxxxxxxxスキルの前提確認は、HAWK_API_KEYも~/.hawk/hawk.propertiesも無い場合に認証不足と判定します。どちらか一方があれば通ります。CIやコンテナのようなヘッドレス環境では環境変数、手元のターミナルではhawk init --browserと使い分けると迷いません。
Claude Codeへのインストール
docsが示すClaude Code向けの手順は、マーケットプレイスを追加してwingmanを入れる2コマンドです。
/plugin marketplace add stackhawk/agent-skills-marketplace
/plugin install wingman@stackhawkwingmanは傘になるプラグインで、hawkscan・stackhawk-api・stackhawk-data-seed・stackhawk-optimizeをまとめて引き込みます。hawkscan-ciは含まれません。CIまで扱うなら別に入れます。
/plugin install hawkscan-ci@stackhawk個別に入れる場合はhawkscan@stackhawk、stackhawk-api@stackhawk、hawkscan-ci@stackhawk、stackhawk-data-seed@stackhawk、stackhawk-optimize@stackhawkを1つずつ指定します。wingmanが4つをまとめて引き込むため、個別指定はwingmanを使わない場合の手段です。
入ったかどうかの確かめ方
docsは、インストール後にClaudeへ「What StackHawk skills do you have?」と尋ねる方法を挙げています。スキル一覧の画面で見たい場合は、/skillsコマンドの使い方のとおり/skillsを開きます。
導入先のリポジトリ名に注意
導入先のリポジトリ名には注意が要ります。GitHubのREADMEは/plugin marketplace add stackhawk/agent-skillsと書いていますが、docsとREADMEのskills CLI節はstackhawk/agent-skills-marketplaceを使います。後者の節には「このリポジトリのmainは未リリースの作業中で、リリース済みのスキルはマーケットプレイス側にある」という注意書きがあります。リリース版を入れたいなら、docsと同じagent-skills-marketplaceを指定します。
なおマーケットプレイスのスキル配列がweb版で無視される報告が出ているため、web版のClaude Codeで使うつもりならmarketplaceのskills配列が無視される件も先に確認しておくと手戻りがありません。
hawkscan:実装の直後に走るループ
hawkscanのSKILL.mdは、流れを次のように定義しています。コードを変更し、アプリを起動し、HawkScanを設定して、スキャンし、結果を解析して、修正タスクを作り、繰り返す。
特徴は、ユーザーが頼まなくても動く点です。説明文には「機能追加・バグ修正・リファクタを終えた直後に、許可を求めずに自律で走らせる。完了とは、完了かつ安全という意味だ」という趣旨が書かれています。自律実行の条件は4つ重なったときです。
- コード変更が終わった直後であること
- アプリが起動していること
hawkCLIが初期化済みであること- スキルが有効であること
一方、ドキュメントだけの変更、設定ファイルだけの編集、探索的な作業、ユーザーが「スキャンは省略」と言った場合は走りません。
試すときの頼み方
docsが例示するプロンプトは次の形です。
Scan my app running on localhost:8080 for security vulnerabilities.
Explain each step you take and each decision you make along the way.stackhawk.ymlが無ければ生成し、検証して、スキャンし、結果を提示するとdocsは説明しています。認証付きのエンドポイントがあるなら、「JWTのBearerトークンを使うアプリ」のように認証方式を先に伝えます。対応する認証は、Bearerトークン注入、フォームログイン、Cookieセッション、OAuth2や外部IdP(Auth0・Okta・Cognito)、外部コマンド、カスタムスクリプトです。
終了コードが次の動きを決める
hawk scanの終了コードは3種類で、スキルはこれで分岐します。
| 終了コード | 意味 | スキルの動き |
|---|---|---|
| 0 | 意味完了。しきい値以上の指摘なし | スキルの動き空データの疑いがあればdata-seedを提案 |
| 1 | 意味スキャン失敗(設定・到達不能・認証) | スキルの動き修正タスクを作らず、まず原因を診断 |
| 42 | 意味完了。failureThreshold以上の指摘あり | スキルの動き修正タスクを作り、直して再スキャン |
終了コード42は意図的なシグナルで、ビルド失敗として扱うようスキルは求めています。再スキャンはhawk rescan --scan-id <SCAN_ID>で、最初のフルスキャンのIDに対して行います。再スキャンのIDを親にはできません。
「0件だから安全」とは言わない品質ゲート
スキャンのたびに、結果を解析する前に品質ゲートが走ります。確かめるのは、想定したルートに届いたか、認証の壁で止まっていないか、全部4xxになっていないか、といった点です。ゲートが開いたままのときは「完了かつ安全」と言わず、何を走査し何を走査しなかったかを理由付きで報告する決まりです。設定を直して再スキャンする回数には上限があり、対話モードで2回、自律モードで1回です。
全部直す、ただし判断は人に残す
指摘は「今回の変更に関係するものだけ」ではなく、スキャンが報告したすべてを直す方針です。DASTは稼働中のアプリ全体を見るので、昔からあるSQLインジェクションも今日入れたものと同じく悪用できる、というのが理由です。
トリアージの権限は線引きされています。
- 明らかな誤検知は、理由のメモ付きで
FALSE_POSITIVEにできる RISK_ACCEPTEDとASSIGNEDは人の判断なので、エージェントは付けない- コード側で指摘を隠す変更はしない
WRITE_TRIAGE権限が無いときはメモを残すだけにとどめ、権限者に反映を頼む
メモの末尾には[triaged by ${HAWK_AGENT:-agent}]を付ける決まりで、後から誰が付けた判定か追えます。
stackhawk-api:読むだけの報告役
stackhawk-apiは、プラットフォーム上のデータを問い合わせて表にするスキルです。「セキュリティの状況は」「どのアプリが古いか」「前回から何が変わったか」といった質問が対象で、スキャンの実行や修正は範囲外です。
組織全体の概況は、hawk op app listとhawk op scan listを組み合わせ、アプリごとにHigh・Medium・Lowの件数を表にします。最後のスキャンから30日以上たったアプリは「最近のスキャンなし」と印が付きます。1アプリの詳細は次の1コマンドで足ります。
# 直近スキャンの概要とアラート表
hawk op scan get --app "<APP_NAME>"
# HTTPの証拠と修正ガイダンスまで含める(エージェントの推論向け)
hawk op scan get --app "<APP_NAME>" --detail full --format json--detail fullが取得するプラグインごとの詳細は、1回に最大10件です。アラートの種類がそれより多いスキャンは、--plugin-idで残りを掘るか、スキャナーのhawk scan --json-outputの出力を読みます。
トリアージの書き込みはこのスキルの範囲外です。状態がNEWの指摘はプラットフォームのUIへ誘導する作りになっています。誤検知のマークを付けるのは前節のhawkscan側という役割分担です。
hawkscan-ci:CIには明示して足す
hawkscan-ciは、ローカルで動いたスキャンをCI/CDのパイプラインに移すスキルです。説明文に「明示的に頼まれたときだけ。コード変更をきっかけにした自律実行はしない」とあり、hawkscanとは逆の性格です。
触るのはパイプラインのファイルだけで、stackhawk.ymlは生成しません。ファイルが無い、または検証が通らないときは、先にhawkscanへ引き継ぎます。計画の段階で3つ尋ねます。
- いつ走らせるか(既定はPRとmainへのpush)
- 指摘でパイプラインを落とすか、警告にとどめるか(既定は落とす)
- ビルド後に同じジョブで起動して走査するか、別ジョブか(既定はビルド後に同一ジョブ)
APIキーはスキルが設定しない
HAWK_API_KEYをどこから渡すかは、ユーザーに尋ねて、置き場所と手順を表示するだけです。スキル自身がシークレットを設定することはありません。GitHub Actionsならgh secret set HAWK_API_KEYです。GitLabだけは例外で、キーがhawk.<id>.<secret>の形でドットを含み、マスク機能が扱えないため、HAWK_API_IDとHAWK_API_SECRETに分けて登録し、ジョブ内で組み立て直します。
実行方式は3段階
| 順位 | 方式 | 使いどころ |
|---|---|---|
| 1 | 方式stackhawk/hawkscan-action@v2 | 使いどころGitHub Actionsのみ |
| 2 | 方式Dockerイメージstackhawk/hawkscan:latest | 使いどころDockerが使えるCI全般 |
| 3 | 方式自己完結バイナリのダウンロード | 使いどころDockerもsudoも使えないランナー |
スキャナーは最新の安定版を使う方針で、イメージはlatest、アクションはメジャー固定です。ビルドを完全に再現したいときだけバージョンを固定します。
警告のみにする場合も、終了コード42だけを警告に下げます。1(設定ミス・到達不能・認証失敗)は握りつぶしません。
set +e
hawk scan
HAWK_EXIT=$?
case $HAWK_EXIT in
0) ;;
42) echo "::warning::HawkScan found findings" ;;
*) exit $HAWK_EXIT ;;
esacワークフローを書いたら、スキルは差分をチャットに見せて止まります。パイプラインの起動、ブランチのpush、PRの作成は行いません。ブランチ保護で必須チェックにする設定も、利用者が画面で行う作業として一覧に出ます。
stackhawk-data-seed:走査が空振りするとき
認証は通ったのに、一覧APIが[]を返し、詳細が404になる。バックエンドにデータが無いと、スキャンは奥まで届きません。hawkscanはこの状況でstackhawk-data-seedを提案しますが、自動では起動しません。
hawk perch seed --events jsonを走らせると、リポジトリを静的に調べた結果がdoneイベントのoutcomeで返ります。
| outcome | 意味 | スキルの動き |
|---|---|---|
nothing_to_seed | 意味ローカルのデータストアも上流も無い | スキルの動き何もせず終了 |
no_local_storage | 意味エンティティが上流サービスにある | スキルの動き解決できた上流ごとに同じ手順を実行(1段まで) |
needs_synthesis | 意味ローカルのデータストアがある | スキルの動きマニフェストを設計して先へ進む |
マニフェストはhawk perch seed validateで検証し、3回失敗したら止まります。通ったらfinalizeでdata-seed/配下に成果物を書き、同時に.data-seed-credentials.envを出力します。このファイルは.gitignore対象で、コミットしてはいけません。hawkscanが認証の設定に自動で取り込みます。
READMEとdocsとSKILL.mdで食い違うところ
導入前に知っておくと混乱しない点を挙げます。
README・docs・SKILL.mdで記述が違う点
導入先のリポジトリ
READMEのClaude Code節は
stackhawk/agent-skillsを追加すると書き、docsはstackhawk/agent-skills-marketplaceを使います。後者のほうがリリース済みの版です。wingmanに入るもの
docsは
hawkscan・stackhawk-api・data-seed・optimizeと説明し、hawkscan-ciは別枠です。READMEの「Four Skills」見出しはoptimizeを数えていません。stackhawk-apiの実装
READMEの仕組みの節は「curlとjqでREST APIを呼ぶ」と書きます。
SKILL.mdはhawk opを使うとし、生のRESTへ戻る手段は無いと明記しています。スキル名の表示
Copilotでは、個別インストールだと
stackhawk-apiがapiと表示されます。名前の変更は次のメジャーリリースに延期されています。
挙動の根拠には各スキルのSKILL.mdを、導入手順にはdocsを使うのが確実です。READMEの仕組みの節だけで判断すると、stackhawk-apiがcurlを要求すると誤解します。
Claude Code側で決めておく運用
ここからはStackHawkの仕様ではなく、運用の組み方の一例です。
CLAUDE.mdに範囲を書く
hawkscanは許可を求めずに走る設計なので、どのアプリのどの環境を対象にするかは、プロジェクトの指示ファイルに書いておくと迷いません。次はあくまで書き方の例です。
## セキュリティスキャン(StackHawk)
- スキャン対象はローカルで起動した開発環境(localhost:8080)のみ。本番・ステージングは対象外
- HAWK_API_KEYは環境変数から読む。stackhawk.ymlにも.envにも値を書かない
- RISK_ACCEPTEDとASSIGNEDは付けない。誤検知のメモには理由を書く許可ルールで呼び出しを絞る
スキャンと検証は頻繁に呼ばれるので、読み取り系は許可に入れ、トリアージの書き込みは確認を挟む構成が扱いやすくなります。これも設定の一例です。
{
"permissions": {
"allow": [
"Bash(hawk version)",
"Bash(hawk validate *)",
"Bash(hawk scan *)",
"Bash(hawk rescan *)",
"Bash(hawk op scan get *)",
"Bash(hawk op scan list *)",
"Bash(hawk op app list *)"
],
"ask": [
"Bash(hawk op scan triage *)",
"Bash(hawk perch seed finalize *)"
]
}
}導入後にスキルを書き換えた場合の反映方法は/reload-skillsの記事にあります。バンドルスキルとの違いが気になる場合はバンドルスキルと組み込みコマンドの違いを参照してください。
つまずきやすい点
スキャンが動かないときの切り分け
- Qhawk versionが6.0.0以降を返すか答えがいいえのとき答えがはい
hawkをアップグレードしてから再実行します。6.0.0未満ではスキルが止まります。 - QHAWK_API_KEYが空でない、または~/.hawk/hawk.propertiesがあるか答えがいいえのとき答えがはい
hawk init --browserを実行するか、環境変数にキーを入れます。 - Q対象アプリが起動していて、hawkから届くか答えがいいえのとき答えがはい
先にアプリを起動します。未起動だと接続エラーで終了コード1になります。
終了コードで原因を読む
終了コード1ならhawk validate config stackhawk.ymlで設定を確かめます。42なら指摘があるので、修正タスクの段階です。
ほかに、公式が「よくある間違い」として挙げている点を拾っておきます。
- スキャン対象のホストに
https://${HOST}/apiのような途中の文字列補間は使えません。host: ${FULL_HOST_URL}の形でURL全体を渡します profilesを使う設定では--profile-scan-mode=primary-fullが要ります。付けないと、約30秒で0件になる罠に当たります。これは安全ではなく未走査です- スキャナーの名称にZAPは使いません。製品はHawkScanで、エンジンはHSTEです
- スキャンを
&やnohupで裏に回しません。1つのアプリ・環境に対して同時に複数走らせないのも決まりです
skills CLIで入れるとフックが動かない
npx skills add stackhawk/agent-skills-marketplace --allは、各エージェントに対応する形でスキルを入れる方法です。ただしこの経路はSKILL.mdとreferences/だけを入れ、プラグインのフックは入れません。READMEは、コード変更後の自動スキャンが発火しなくなると明記しています。自動ループを使いたいClaude Codeでは、/plugin installで入れる側が適しています。
まとめ
導入そのものは2コマンドで済みます。差が出るのは入れた後です。hawkscanは許可を求めずに走るので、対象環境と鍵の扱いを指示ファイルに書いておくこと。hawkscan-ciはwingmanに入っていないので、CIまで回すなら別に入れること。この2点を押さえておけば、READMEとdocsの食い違いで迷うことは少なくなります。