AeyeScan blog 第14回 AI に EC サイトを作らせてセキュリティスキャンにかけたら「動くけど守れない」コードだった | ScanNetSecurity
2026.05.18(月)

AeyeScan blog 第14回 AI に EC サイトを作らせてセキュリティスキャンにかけたら「動くけど守れない」コードだった

 Claude に EC サイトをゼロから作らせて、完成したアプリを自社の AeyeScan でスキャンしてみたら、Critical も High もゼロ。ぱっと見は悪くない結果ですが、この数字の中身を掘っていくとバイブコーディングの「クセ」がはっきり見えてきました。

特集 コラム
(イメージ画像)
(イメージ画像) 全 4 枚 拡大写真

 こんにちは。株式会社エーアイセキュリティラボで、SaaS 型 Web アプリケーション脆弱性診断プラットフォーム「AeyeScan」の開発エンジニアをしている有馬です。

 バイブコーディング(AIに自然言語で指示してコードを書かせる開発スタイル)が当たり前になりつつある今、AIが生成したコードのセキュリティは実際どうなのか。推測ではなくデータで答えを出したくて、ひとつ検証をしてみました。Claude に EC サイトをゼロから作らせて、完成したアプリを自社の AeyeScan でスキャンする、というものです。

 先に結論だけ書きます。Critical・High の脆弱性は 0 件。でも、24 件の問題が見つかりました。その内訳を見ていくと、「AIはセキュリティを知らないのではなく、セキュリティを気にしない」という構造が見えてきました。

●[検証の概要]作ったもの

 EC サイト実装用のプロンプト自体も Sonnet 4.6 に生成させています。こちらから指定したのは Next.js・Express・shadcn/ui という大枠と、EC サイトとしての基本機能、ローカル環境で動かすことだけです。
セキュリティに関する指示は一切入れていません(実際に使用したプロンプトは転載元を参照)。

● AIが実際に生成したアプリの構成

 レイヤー/技術
 フロントエンド/Next.js 16 (App Router) + TypeScript + Tailwind CSS
 UIコンポーネント/shadcn/ui + lucide-react
 フォーム管理/react-hook-form + zod
 バックエンド/Express.js 4.18.3
 データベース/SQLite (better-sqlite3)
 認証/JWT + bcrypt

 会員登録・ログイン、商品一覧・検索、カート管理、注文確定、レビュー投稿、管理者ダッシュボードなど、EC サイトとして一通りの機能を持っています。こちらから指定したのはフレームワークと基本機能だけで、それ以外のライブラリ選定や具体的な実装はすべてAIに任せました。

● スキャン方法

 完成したアプリをローカル開発環境で起動し、AeyeScan のWebアプリケーションスキャンを実施しました。

 ・対象画面数: 40画面
 ・スキャンルールセット: Webアプリケーションスキャン(OWASP TOP 10 全カテゴリ対応)

AeyeScanとは?
 AeyeScanは、クラウド型のWebアプリケーション脆弱性診断ツールです。対象サイトをブラウザで自動巡回し、IPA「安全なウェブサイトの作り方」やOWASP TOP 10などの基準に沿った脆弱性検査を実施します。

● スキャン結果のサマリー

 全体評価: Medium

 深刻度:件数
 Critical:0件
 High:0件
 Medium:2件
 Low:4件
 Info:18件

AeyeScan のスキャンサマリー。Critical/High は0件だが、Medium 以下で 24 件の指摘が出ている

 Critical も High もゼロ。ぱっと見は悪くない結果に見えます。しかし、この数字の中身を掘っていくと、バイブコーディングの「クセ」がはっきり見えてきます。

● 特に注目すべき検出結果

 24件すべてを列挙するのではなく、「バイブコーディングの特徴」が顕著に表れているものに絞って紹介します。

クリックジャッキング(Medium / CVSS 5.3)
 会員登録フォーム(/register)が外部サイトにiframe(別のWebページの中にページを埋め込む仕組み)で埋め込める状態でした。

外部サイトに iframeで /register を埋め込んだところ、会員登録フォームがそのまま表示された(AeyeScanによる検証画面)

 攻撃者が罠サイト上に透明な iframe を重ねれば、ユーザーに気づかせないまま送信ボタンをクリックさせることができます。

 原因: Content-Security-Policy の frame-ancestors ディレクティブ(ブラウザに「このページは外部サイトに埋め込まないで」と伝えるセキュリティヘッダ)が設定されていませんでした。この設定は明示的に行う必要がありますが、AIはこれを行っていませんでした。

● セキュリティミドルウェアの「入れただけ」問題

 今回の検証で一番印象的だった発見です。

 スキャン結果にはセキュリティヘッダの不備(CSP、X-Content-Type-Options、Referrer-Policy等)が多数含まれていました。原因を探るためにソースコードを確認したところ、こうなっていました。

 // server.js の実際の内容 - helmet のインポートも適用もない
 app.use(cors({ origin: true, credentials: true }));
 app.use(pinoHttp({ logger }));
 app.use(express.json());
 // ← ここに app.use(helmet()) があるべきだった

 AIは Express のセキュリティミドルウェア「Helmet」(セキュリティ関連の HTTP ヘッダをまとめて付与してくれるライブラリ)を package.json にインストールしていたものの、app.use(helmet()) を書いていなかったのです。同様に、レート制限ミドルウェアの express-rate-limit も依存関係に追加されているのに、実際のコードでは一切使われていませんでした。

 「セキュリティに必要なパッケージを知っていて、インストールまではする。でも実際に適用するコードは書き忘れる」——これがバイブコーディングの典型的な落とし穴だと感じました。

● パスワード強度の不備

 7 文字のパスワード user123 で会員登録が成功してしまいました。実装を確認すると 6 文字以上のバリデーションは存在していたものの、OWASP(Webセキュリティの国際的な基準を策定する団体)の基準では最低 8 文字以上が推奨されており、さらによくあるパスワードを拒否する仕組みも必要です。基準が緩すぎる状態でした。

● デバッグ情報の露出

 Express側のエラーハンドラが、スタックトレースをそのままクライアントに返していました。

// server.js のエラーハンドラ
res.status(500).json({
error: err.message,
stack: err.stack, // ← サーバーのディレクトリ構造がそのまま返される
});

 攻撃者にアプリの内部構造を教えてしまう実装です。本番では NODE_ENV で出し分けるべきですが、その考慮もありませんでした。

● 未検出だった項目にも注目する

 検出された問題と同じくらい大事なのが、検出されなかった項目です。

 IPA「安全なウェブサイトの作り方」の11カテゴリ中、クリックジャッキング以外の10項目はすべて合格していました。

IPA「安全なウェブサイトの作り方」対応状況。11項目中10項目が「○」で、「×」はクリックジャッキングのみ

 SQLインジェクション、XSS、CSRF、ディレクトリ・トラバーサルといった致命的な脆弱性はすべて未検出でした。実際にソースコードを確認すると、データベースへのクエリはすべて better-sqlite3のprepared statement(SQL文にユーザー入力を安全に埋め込む仕組み)で記述されており、ユーザー入力が直接 SQL に結合される箇所はありませんでした。AIが意識的にセキュリティ対策を施したというよりも、フレームワークの標準的な書き方に従った結果、自然と防がれていたと考えられます。

● 結果から見えるバイブコーディングの構造的な特徴

 ここまでの結果を整理すると、ひとつの構造が浮かんできます。

 フレームワークが自動で守る領域(XSS、SQL インジェクション等)は問題なし。一方で、明示的に設定しなければ効かない防御(CSP、パスワードポリシー等)は軒並み抜けている。

 そして検出された問題には共通点があります。どれも「なくてもアプリは動く」ものばかりです。CSP ヘッダがなくてもサイトは表示されますし、パスワードが7文字でも登録は通りますし、Helmet が未適用でも Express は起動します。

 AIは「動くものを作る」ことには長けています。ただ、動作に影響しないセキュリティ設定は、こちらから頼まない限り後回しにされます。Helmet をインストールする判断力はあるのに、app.use(helmet()) の一行は書かない。「知っている」と「最後までやりきる」の間にギャップがあるのです。

● バイブコーディング時代のセキュリティ対策

 今回の検証から得た教訓を4つにまとめます。

 1. セキュリティ要件をプロンプトに含める。「EC サイトを作って」ではなく、「Helmet を適用して」「CSP の frame-ancestors を設定して」「パスワードは 8 文字以上で」と具体的に指示します。これだけで AIの出力は大きく変わります。

 2. 「インストール済み」と「適用済み」を区別する。 package.json にあるからといって使われているとは限りません。Helmet と express-rate-limit がまさにそうでした。セキュリティライブラリが実際にコード上で適用されているかを確認することが重要です。

 3. フレームワーク任せで安心しない。 Next.jsが XSS を防いでくれるのは事実ですが、それはフレームワークの守備範囲の話です。CSP ヘッダやパスワードポリシーなど、フレームワークの「外側」にあるセキュリティは明示的に実装する必要があります。

 4. スキャンツールで機械的にチェックする。 40 画面のアプリで 24 件。目視では拾いきれない数です。AIで速く作り、スキャンツールで網羅的に検査し、人間が最終判断する。この 3 段階のサイクルが現実的なやり方だと考えています。

● まとめ

 AIに EC サイトを作らせてスキャンした結果、見えたのは「AIは賢いが、気が利かない」ということでした。

 致命的な脆弱性はゼロ。フレームワークが守ってくれる領域は問題ありません。しかし Helmet は入れただけで適用し忘れていますし、パスワードは 7 文字で通ります。全部「動作には関係ないけど、セキュリティ上は問題」なものばかりです。

 「動くものを作る」と「安全なものを作る」の間にはギャップがあります。そのギャップを埋めるのは、今のところまだ人間の仕事です。

《株式会社エーアイセキュリティラボ 開発本部 有馬 玄規》

関連記事

この記事の写真

/

特集

PageTop

アクセスランキング

  1. あいおいニッセイ同和損害保険からの出向者がトヨタ自動車の内部情報を不適切に提供

    あいおいニッセイ同和損害保険からの出向者がトヨタ自動車の内部情報を不適切に提供

  2. マルタケの一部サーバでのシステム障害、不正アクセス(ランサムウェア)による影響の可能性も含め調査

    マルタケの一部サーバでのシステム障害、不正アクセス(ランサムウェア)による影響の可能性も含め調査

  3. TEIKOKU のシンガポール販売子会社の Microsoft365 アカウントに不正アクセス、セキュリティシステムに不審メール報告が集中し発覚

    TEIKOKU のシンガポール販売子会社の Microsoft365 アカウントに不正アクセス、セキュリティシステムに不審メール報告が集中し発覚

  4. 公益財団法人B&G財団にマルウェア攻撃、サーバでシステム障害が発生

    公益財団法人B&G財団にマルウェア攻撃、サーバでシステム障害が発生

  5. IPA、PSIRT の体制整備と運用支援を無償で実施

    IPA、PSIRT の体制整備と運用支援を無償で実施

ランキングをもっと見る
PageTop