
新機能 AWS Continuum Code Vulnerabilitiesを使って最近の脆弱性を見つけられるのか試してみた
こんにちは、せーのです。
先週(日本時間 2026-10-23)、AWS Continuum for code vulnerabilities が 一般提供(GA) になりました。これはひとことで言うと、ソースコードに潜む脆弱性を探し、それが本当に悪用できるのかを判断して、直し方まで提案してくれるサービスです。
ちょうどこの 10 月は、PHP、Node.js、Python のまわりで大きめの脆弱性の発表が続きました。そこでこの記事では、最近話題になった脆弱性を Continuum で見つけられるのかを確かめてみようと思います。それらの脆弱性をわざと仕込んだ小さなアプリを用意してスキャンしてみました。果たしてどうなるのでしょうか?
結論
結論から言うと、次のような結果でした。
- Python のライブラリとして入れた脆弱性(Brotli と certifi)は、見つかりました
- PHP や Node.js の本体のバージョンに由来する脆弱性(PHP2Shell と Node2Shell の本体側)は、見つかりませんでした
- SQL インジェクションのような昔からある書き方の誤りは、PHP、Node.js、Python の 3 言語とも見つかりました
- 「悪用できる」という判定は、コードを読んだうえでの判断でした。実際に攻撃を試した記録は残っていません
細部の仕様は 公式ドキュメント を正として確認してください。
Continuum for code vulnerabilities とは(おさらい)
脆弱性スキャナーを使ったことがある方なら、「危ないかもしれない」という指摘が大量に出てきて、どれから直せばいいのか分からなくなった経験があると思います。指摘の中には、実際にはどこからも呼ばれていないコードや、テスト用のコードも混ざっていますよね。
Continuum は、その指摘を受け取ったあとの仕事をしてくれるサービスです。コードの流れや AWS 上の構成まで見て、「外から本当に届くのか」「届いたら何が起きるのか」を判断し、優先順位を付け、直し方のコード差分まで用意します。
家の点検にたとえると、従来のスキャナーは「この窓の鍵は古い型です」と全部の窓を書き出す点検票です。Continuum はそこから一歩進んで、「この窓は道路に面していて、外から手が届くので先に直しましょう。交換部品はこれです」と言ってくれる点検員、というイメージです。部品を交換するかどうかは、家の持ち主が決めます。
画面の上では、次の順に進みます。
① コードを渡す(GitHub か S3)
↓
② Findings … スキャナーが拾った「危ないかもしれない」という指摘
↓
③ Issues … 悪用できるかを判断し、優先度を付けた課題
↓
④ 修正案 … 直し方のコード差分(GitHub ならプルリクエスト、S3 ならファイル)
修正案を取り込むかどうかは、人が中身を見てから決めます。Continuum が勝手にコードを書き換えることはありません。
また公式の説明では、再現できるものは隔離した環境で実際に試し、その記録を PoC(本当に悪用できることを示す証拠)として残す、とされています。今回それが起きたかどうかは、後半で結果と照らし合わせます。
名前が似ている機能に注意
コンソールを開くと、Code vulnerabilities と Penetration testing が並んでいます。この記事で扱うのは左側です。
右側の Penetration testing は、Web アプリに対して AI が実際に攻撃のテストを行う機能です。こちらは、DevelopersIO 2026 Tokyo で浅野さんが検証用アプリを使って詳しく紹介しているので、気になる方はあわせて読んでみてください。

| 名前 | 2026 年 10 月時点 | 何をするか | 料金のイメージ |
|---|---|---|---|
| Code vulnerabilities(この記事) | 一般提供 | コードを読んで、悪用できるかを判断し、直し方を出す | 保護するコードの量 + 推論の量 |
| Penetration testing(旧 AWS Security Agent) | 一般提供(CI/CD 連携はプレビュー) | 動いているアプリに、実際に攻撃のテストをする | 作業時間(無料枠あり) |
| Code review(旧 Security Agent のコードレビュー) | プレビュー | リポジトリ全体やプルリクエストをレビューする | プレビュー中は追加料金なし |
違いを整理すると、Code vulnerabilities は「図面を読んで危ない場所と直し方を出す」もの、Penetration testing は「実際に建物に入ってみる」もの、というイメージです。
なお、提供リージョンは 米国東部(バージニア北部)と米国西部(オレゴン) だけです。東京リージョンでは使えません。
試した「最近の脆弱性」
今回仕込んだのは、2026 年 10 月に発表された次の 3 つです。どれも PHP、Node.js、Python のどれかに関係しています。
| 名前 | 発表 | 影響を受けるもの | 仕込み方 |
|---|---|---|---|
| PHP2Shell | 2026-10-21 修正 | PHP 本体 | PHP アプリの土台に、修正前の PHP を使う |
| Node2Shell | 2026-10-21 公表 | Node.js 本体と、同じ部品を持つ Python ライブラリ | Node.js アプリの土台に修正前の Node.js を使う。Python アプリに修正前の Brotli を入れる |
| eMudhra の中間証明書の危殆化 | 2026-10-20 確認 | Python の certifi | Python アプリに修正前の certifi を入れる |
ひとつずつ、どんな脆弱性なのかを簡単に紹介します。
PHP2Shell(PHP 本体)
PHP 本体に見つかった脆弱性で、識別番号は CVE-2026-109618 と CVE-2026-109619 です。深刻度を表す CVSS は 9.2 で、外部からサーバ上でプログラムを実行される恐れがあります。PHP 8.3 系では、2026-10-21 に出た 8.3.36 で修正されています。
アプリのコードではなく、アプリが動く土台の PHP のバージョン に問題があるタイプです。今回は、コンテナの土台(Dockerfile の FROM 行)を修正前の php:8.3.35-apache にしました。
Node2Shell(Node.js 本体と、Python の Brotli)
Node.js に組み込まれている、データの圧縮と展開に使う部品「Brotli」に見つかった脆弱性です。識別番号は CVE-2026-111497 で、CVSS は 9.2 です。展開の処理で結果のチェックが抜けていて、本来書き込んではいけないメモリの領域に書き込んでしまいます。圧縮されたデータを外部から受け取るだけで処理が走るので、ログインしていない相手からも狙われます。
やっかいなのは、同じ Brotli の部品が Python のライブラリにも入っていることです。Python の Brotli 1.2.0 以前と brotlicffi 1.2.0.2 以前が該当します。
今回は 2 か所に仕込みました。
- Node.js アプリの土台を、修正前の
node:24.22.0-bookwormにした - Python アプリの依存関係に、
Brotli==1.2.0とbrotlicffi==1.2.0.2を入れた
eMudhra の中間証明書の危殆化(Python の certifi)
インドの認証局 eMudhra が発行した中間証明書のうち 8 枚が、弱い秘密鍵で作られていたことが分かりました。2026-10-20 に Google と Mozilla が確認しています。
証明書は、通信相手が本物かどうかを確かめるために使います。秘密鍵が弱いと、攻撃者がその証明書を使って本物のサイトになりすませてしまいます。たとえば、通信の途中に割り込める攻撃者が、pypi.org のふりをする、といったことが起こり得ます。
Python では、信頼する証明書の一覧を certifi というライブラリで持つことが多く、古い certifi はこの中間証明書をまだ信頼しています。識別番号は GHSA-6q48-6c7w-9gw2 で、certifi 2026.10.18 以降で修正されています。今回は修正前の certifi==2026.7.22 を入れました。
比較用に、昔からある書き方の誤りも入れた
最近の脆弱性だけだと、見つからなかったときに「その脆弱性だから見つからなかった」のか、「その言語自体を読めていない」のかが区別できません。そこで、昔からよく知られている書き方の誤りを、3 言語それぞれに同じ種類だけ入れました。
| 種類 | どんな誤りか |
|---|---|
| SQL インジェクション | 利用者の入力を、そのままデータベースへの命令文につなげる |
| コマンドインジェクション | 利用者の入力を、そのまま OS のコマンドにつなげる |
| SSRF | 利用者が指定した URL に、サーバがそのままアクセスしに行く |
| パストラバーサル | 利用者が指定したファイル名から、本来読めないファイルまで読めてしまう |
| 安全でないデシリアライズ | 外から受け取ったデータを、そのままプログラムの部品として復元する |
| IDOR | 他人の注文番号を指定すると、他人の注文が見えてしまう |
あわせて、本当は悪用できない「ひっかけ」 も入れています。どこからも呼ばれていない関数、テストコードの中だけにある危険な書き方、コメントアウトした危険なコード、の 3 種類です。これらを指摘してこなければ、余計な指摘をちゃんと減らせている、と言えます。
入れなかったもの:npm のワーム ChainDrop
2026 年 8 月には、npm の keyv@6.0.0 を起点に 444 のパッケージが汚染された、と報じられている ChainDrop という事件もありました。インストールするだけで認証情報を盗み、さらに自分を広げていくタイプのマルウェアです。
これは実際にインストールすると本当に被害が出るので、今回は入れていません。
試し方
用意したアプリ
PHP、Node.js、Python のアプリを 1 つのリポジトリにまとめました。行数は合計 2,325 行(PHP 883 行、Node.js 738 行、Python 704 行)です。公式ドキュメントには対応言語の一覧が見当たらないので、3 言語を同居させて、どの言語を読めるかも一緒に確かめます。
攻撃に使える手順はリポジトリに置いていません。パスワードや鍵も、サンプル用のダミーだけです。
コードの渡し方は S3 にした
コードの渡し方は、GitHub と Amazon S3 の 2 通りがあります。GitHub はブラウザでの認可が必要になるので、今回はリポジトリを zip にして、バージニア北部(us-east-1)の S3 に置く方法にしました。GitHub 連携は別の記事で試します。
アプリそのものは AWS 上に置いていません。AWS の構成情報を Continuum に渡す Collector という仕組みも、今回は使っていません。
Environment を作ると、すぐにスキャンが始まる
Continuum では、スキャンの単位を Environment と呼びます。continuum-cv-sample という名前で作りました。スキャンの頻度は「Manual only(手動だけ)」にしています。

ひとつ注意したいのは、手動にしていても、Environment を作った直後に 1 回目のスキャンが自動で始まることです。今回も、作成の 1 秒後にスキャンが始まりました。試すだけのつもりでも、作った時点でスキャンが走ると思っておいた方がよさそうです。
設定タブでは、コードの置き場所が Amazon S3 であること、GitHub の連携が無いこと、修正案の自動作成が On であること、Collector が 0 件であることが確認できます。S3 のバケット名にはアカウント ID が含まれるので、画像では隠しています。

ライブラリの取得先を許可しておく
Continuum はスキャンの前にアプリをビルドするので、その途中で npm や PyPI などからライブラリを取りに行きます。そのため、アクセスしてよいドメインを許可しておく必要があります。
許可は 2 種類に分かれていました。
- Always allowed by Continuum:最初から許可されているドメイン。github.com や nodejs.org など 9 件
- Additional allowed domains:自分で追加したドメイン。PHP の packagist、npm、PyPI、Debian、Docker Hub など 13 件


自分では github.com と api.github.com も追加したつもりでしたが、この 2 つは最初から許可されている側に表示されていました。
スキャンは約 30 分で終わった
1 回目のスキャンは 3分で終わりました。課題の判断と修正案の作成まで含めると、30分程度ですべて完了しています。2 回目は、後で説明する修正を入れてから手動で実行しました。

| 1 回目 | 2 回目(修正後) | |
|---|---|---|
| 始まり方 | 自動(Environment の作成時) | 手動 |
| 時間(日本時間) | 13:00 〜 13:33 | 17:52 〜 18:21 |
| 結果 | 成功 | 成功 |
結果:最近の脆弱性は見つかったか
先に、仕込んだ脆弱性ごとの結果をまとめます。Continuum は重要度を Critical、High、Medium、Low の 4 段階で付けます。表の「判断前」は Findings での重要度、「判断後」は Issues での重要度です。
| 仕込んだもの | 見つかったか | 判断前 → 判断後 |
|---|---|---|
| PHP2Shell(PHP 本体) | 見つからなかった | ― |
| Node2Shell(Node.js 本体) | 見つからなかった | ― |
| Node2Shell(Python の Brotli) | 見つかった | High → Low |
| eMudhra(Python の certifi) | 見つかった | Medium → Low |
| 昔からある書き方の誤り | 3 言語とも見つかった | 後述 |
| ひっかけ(呼ばれない関数、テスト、コメント) | 指摘されなかった | ― |
PHP2Shell と Node2Shell の本体側は、見つからなかった
コンテナの土台に修正前の PHP と Node.js を使っていましたが、どちらも指摘はありませんでした。Python の土台(修正前の pip を含む python:3.14.8-slim)も同じく指摘なしです。
おもしろいのは、PHP の設定ファイル(php.ini)を直す修正案が、Dockerfile にも手を入れていたことです。それでも、土台の PHP のバージョンは 8.3.35 のまま変わっていませんでした。
つまり今回のスキャンでは、アプリが動く土台のバージョンまでは見ていないということになります。土台の脆弱性は、Amazon Inspector のようなコンテナイメージのスキャンと組み合わせる必要がありそうです。
Node2Shell は、Python 側だけ見つかった
一方で、Python の依存関係に入れた Brotli は見つかりました。指摘のタイトルは、次のとおりです。
requirements.txt pins Brotli 1.2.0 / brotlicffi 1.2.0.2 (CVE-2026-111497 decoder OOB write) reachable through the unauthenticated URL-fetch endpoint
「CVE-2026-111497 の脆弱性がある Brotli が入っていて、ログイン不要の URL 取得機能から届く」という意味です。単に「古いライブラリが入っています」と言うだけでなく、アプリのどの機能からその脆弱性に届くのかまでつなげて説明しているのが特徴です。
同じ Node2Shell でも、Node.js 本体の方は見つからず、Python のライブラリの方は見つかった、という結果です。ライブラリとして依存関係のファイルに書かれていれば拾える、ということだと推測できます。
certifi も見つかった
eMudhra の件で入れた certifi も指摘されました。
requirements.txt pins certifi 2026.7.22, a CA bundle still trusting a distrusted intermediate, as the TLS trust anchor for all outbound requests
「信頼を取り消された中間証明書をまだ信頼している certifi が、外部への通信すべての信頼の基準になっている」という意味です。発表から 1 週間ほどの脆弱性ですが、きちんと拾えていました。
ただ、重要度は判断後に Low まで下がっています。Brotli も同じく、判断前の High から Low に下がりました。今回はアプリを AWS 上に置いていないので、外から届くかどうかを確かめる材料が少なかった可能性があります。
昔からある書き方の誤りは、3 言語とも見つかった
比較用に入れた書き方の誤りは、PHP、Node.js、Python のすべてで見つかりました。SQL インジェクション、コマンドインジェクション、SSRF、パストラバーサル、安全でないデシリアライズ、IDOR のどれも、3 言語とも指摘されています。対応言語の一覧は無くても、この 3 言語は読めていると言ってよさそうです。

1 回目のスキャンで出た指摘(Findings)は、言語ごとに次のとおりでした。
| 言語 | Critical | High | Medium | Low | 合計 |
|---|---|---|---|---|---|
| PHP | 11 | 11 | 6 | 3 | 31 |
| Node.js | 10 | 6 | 3 | 3 | 22 |
| Python | 9 | 5 | 5 | 0 | 19 |
| 合計 | 30 | 22 | 14 | 6 | 72 |
これが判断を経た課題(Issues)になると、71 件になり、Critical は 30 件から 1 件 まで絞られました。内訳は Critical 1 件、High 14 件、Medium 23 件、Low 33 件です。

「危ないかもしれない」が 30 件あっても、先に直すべきものは 1 件、というところまで絞ってくれるのは、忙しい開発チームにはありがたいですね。
なお、画面の件数表示はどちらも「100+」になっています。画面に読み込んだ分だけを数える表示なので、72 件や 71 件という数字は、API で全件を取得して数えたものです。
ひっかけは指摘されなかった
どこからも呼ばれていない関数、テストコードの中の危険な書き方、コメントアウトしたコードは、どれも指摘されませんでした。実際には悪用できないものを、きちんと外せています。
「悪用できる」は、コードを読んだうえでの判断だった
課題を 1 件開いて、中身を見てみます。開いたのは、ログインせずに送ったデータが PHP の unserialize にそのまま渡る、という課題です(再スキャン後にできた、Critical の 1 件)。

少し下にスクロールすると、Risk assessment(リスクの評価)が表示されます。

英語の項目が多いので、主なものを訳しておきます。
| 画面の表示 | 意味 | この課題の値 |
|---|---|---|
| Exploitability | 悪用できるか | Exploitable(悪用できる) |
| Evidence level | どこまで確かめたか | Static proven(コードを読んで確かめた) |
| Inferred effect | 起きると考えられる影響 | Data leaked(データが漏れる) |
| Reachable from attacker | 攻撃者から届くか | Yes |
| Required access | 必要な権限 | No authentication(ログイン不要) |
| Can be automated | 確認を自動で繰り返せるか | No |
注目したいのは Evidence level です。「Static proven」は、コードを読んで確かめた、という意味です。その下の Proof(根拠)を見ると、先頭に「SOURCE_ONLY」「Nothing is built or run」と書かれていました。ビルドも実行もしていない、ということです。

点検員のたとえで言うと、「図面を見る限り、この窓には外から手が届きます」という報告書はあるけれど、実際に窓を開けてみた記録は無い、という状態です。1 回目のスキャンの 71 件すべてが、この「コードを読んで確かめた」段階でした。
公式の説明にある「隔離した環境で実際に試して PoC を残す」は、今回の条件では起きていません。アプリを AWS 上に置かず、Collector も使っていないことが影響していると推測できます。「Reachable from attacker」が Yes になっているのも、ネットワークを実際に調べた結果ではなく、コードから判断した結果です。
直し方は、S3 に差分として届いた
課題の詳細画面で「View patch」を押すと、直し方のコード差分が表示されます。今回は S3 で連携しているので、修正案はプルリクエストではなく、S3 に置かれた差分ファイルとして届いていました。

この課題では 2 つのファイルが対象で、21 行の追加と 4 行の削除です。受け取ったデータをそのまま画面に出していた部分が、JSON として安全に返す形に書き換えられています。
1 回目のスキャンでは、71 件の課題すべてに修正案が付き、S3 の continuum-patches/ というフォルダに届いていました。
Brotli を直して、もう一度スキャンした
修正案を全部取り込むと、検証用に仕込んだ脆弱性がすべて消えてしまいます。そこで、次の 2 つだけを直して再スキャンしました。
- Node2Shell の Python 側:
requirements.txtから Brotli と brotlicffi を外した - PHP のデバッグ表示:設定が無いときはデバッグ表示がオフになるようにした
結果、この 2 つは再スキャンで指摘されませんでした。直したものは、きちんと指摘から消えます。
ただし、全体の件数は単純には減りません。
| 1 回目 | 2 回目 | |
|---|---|---|
| 指摘(Findings) | 72 | 71 |
| 新しい課題(Issues) | 71 | 70 |
| Critical の課題 | 1 | 4 |
2 つ直したのに指摘は 1 件しか減らず、Critical の課題は 1 件から 4 件に増えています。2 回目では、1 回目には無かった指摘(Node.js のアプリにセキュリティ用のヘッダが無い、など)も出てきました。
健康診断を 2 回受けたら、1 回目に指摘された項目は治ったけれど、2 回目は別の先生が診たので別の項目も指摘された、という感じです。スキャンのたびに判断が少しずつ変わるので、件数の増減だけで「何件直った」とは判断できません。直したものが消えたかどうかを、項目ごとに確かめるのがよさそうです。
料金について
料金は2つに分かれています。詳細は 料金ページ が正です。
| 項目 | 単価 | 何に対してかかるか |
|---|---|---|
| 保護するコードの量 | 100 万行あたり月 $200 | 読ませたコードの行数 |
| 推論(CIU) | 1 CIU あたり $10 | 脆弱性の判断や、修正案の作成 |
料金ページの小さい例は、「100 万行 + 脆弱性 100 件 × 1 CIU」で月 $1,200 です。内訳は、コードの量 $200 と、推論 $1,000 です。1 件を 1 CIU と置いた場合の例です。
今回のアプリは 2,325 行です。料金表を先に見たときは、コードの量(100 万行あたり $200)が主な費用になる、と読んでいました。行数が少なくても、表の単位が 100 万行なので、試す前に目が行くのはこの行です。
請求を見ると、金額を動かしていたのは脆弱性の側でした。脆弱性が 100 件あると、およそ $800 かかっています。コードの行数の行より、見つけた件数の行の方が大きく出ていました。
スキャンの前に件数は分かりません。Continuum が何件見つけるかは、やってみないと出ません。今回も、自分で仕込んだ数より多くの指摘が出ています。なので見積は、脆弱性 100 件、おおよそ $1,000 から置いておくとよいと思います。そこに、コードの量の料金が乗ります。公式の例も、100 件で推論 $1,000 です。今回の請求はその近くで、およそ $800 でした。
試す前に、予算のアラートを先に設定しておくと安心です。
まとめ
「最近の脆弱性を Continuum で見つけられるのか」への答えは、ライブラリとして入っているものは見つかる。アプリが動く土台のバージョンに由来するものは見つからない、でした。
- Python のライブラリに入れた Node2Shell(Brotli)と eMudhra(certifi)は、発表から 1 週間ほどでも見つかった。しかも「どの機能から届くか」までつなげて説明してくれる
- PHP2Shell と Node2Shell の本体側は、コンテナの土台のバージョンなので見つからなかった。土台はコンテナイメージのスキャンと組み合わせたい
- 昔からある書き方の誤りは、PHP、Node.js、Python の 3 言語とも見つかった。ひっかけは指摘されなかった
- Critical の指摘 30 件が、判断のあとには 1 件に絞られた
- 「悪用できる」は、コードを読んだうえでの判断だった。実際に攻撃を試した記録は残っていなかった
- 直し方は、S3 に差分ファイルとして届いた。直したものは再スキャンで指摘から消えるが、全体の件数はスキャンのたびに変わる
- 料金はコードの量(100 万行あたり月 $200)と、見つけた脆弱性の側に分かれる。今回は 100 件でおよそ $800。件数はスキャンしてみないと分からないので、見積は 100 件、おおよそ $1,000 から置いておくとよい
指摘の多さに困っているチームにとって、「本当に危ないものから順に並べて、直し方まで出してくれる」のは心強い機能です。一方で、実際に攻撃を試す部分は、アプリを AWS 上に置いた状態でどう変わるかを見てみたいところです。GitHub 連携とあわせて、別の記事で試してみます。
参考資料
- AWS Continuum for code vulnerabilities is now generally available
- AWS Continuum – Pricing
- What is AWS Continuum?(User Guide)
- Code vulnerabilities(User Guide)
- Getting started with code vulnerabilities
- AWS Continuum FAQs
- Introducing AWS Continuum: Security at machine speed
- 【登壇レポート】「AWS Continuum for Penetration Testing にDeep Diveしてみる」というタイトルで登壇しました #devio2026(Penetration testing 側の記事。この記事の機能とは別物です)












