AIが生成したAPIはワイルドカードCORSを出荷し続ける。ここで直す方法。

Dev.to / 2026/4/6

💬 オピニオンDeveloper Stack & InfrastructureTools & Practical Usage

要点

  • この記事では、AIが生成したExpressやFastAPIプロジェクトで、文脈に応じた保護策を欠いたままCORSミドルウェアがデフォルト設定(例:`Access-Control-Allow-Origin: *`)で含まれてしまうことが多い、と警告している。
  • ワイルドカードCORSは、Cookieベースの認証と組み合わさると特に危険になることを説明しており、インターネット上の事実上あらゆるWebサイトからのクロスオリジン要求を許可してしまう。
  • 脆弱な設定パターンとして、共通の欠陥(CWE-942)が「vibe-coded」なリポジトリに繰り返し現れ、よくあるチュートリアルのデフォルトにも反映されている点を挙げている。
  • 提案する修正は、ワイルドカードを明示的なオリジン許可リストに置き換え、認証付きのクロスオリジン要求を信頼できるフロントエンドのみに制限すること。実装はすぐにできる(約2分)とも述べている。

TL;DR

  • Cursor、Claude Code、Copilotはいずれも、新しいExpressおよびFastAPIプロジェクトで Access-Control-Allow-Origin: * を一貫して生成する
  • ワイルドカードのCORSとCookie認証の組み合わせにより、インターネット上の任意のWebサイトからAPIがクロスオリジン攻撃にさらされる
  • 修正:ワイルドカードを明示的なオリジン許可リストに置き換える -- だいたい2分

先週、友人のサイドプロジェクトをレビューしていました。Node/Expressのバックエンドで、Cursorが生成したようで見た目はきれいでした。ところが、ミドルウェア設定の中に埋もれているのを見つけました:

app.use(cors());

オプションなし。デフォルトのワイルドカードです。この1行が意味するのは、訪問者のブラウザから、どのWebサイトでも彼のAPIにリクエストできるということです。彼は翌週にユーザーアカウントを追加する予定でした。

これは単発ではありません。私は何十もの「雰囲気コード(vibe-coded)」のリポジトリを見てきました。このパターンは常に出てきます。AIは学習データの基準に照らせば間違ってはいません -- 引数なしでの cors() は、2019年のExpressチュートリアルのどれでも最初の結果です。AIは、そのコードが書かれた文脈を学ばずにパターンだけを学習してしまったのです。

脆弱なパターン(CWE-942)

Cursorに「ExpressアプリにCORSサポートを追加して」と頼むと、返ってくるのはだいたいこれです:

const cors = require('cors');
app.use(cors()); // Access-Control-Allow-Origin: *

FastAPIでも同様の扱いです:

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

allow_credentials=Trueallow_origins=["*"] の組み合わせがごちゃごちゃしています。CORSの仕様では、資格情報が関係する場合に * を反映することは実際に禁止されています -- ブラウザはそれをブロックします。しかし、いくつかのCORSライブラリは、代わりに要求されたOriginヘッダを反映して応答することで、その保護を完全にすり抜けます。開発者が後からCORS設定を見直さずにセッションクッキーを追加すると、ワイルドカードは開発中は「まあ大丈夫」でしたが、そうではなくなります。

なぜこのパターンが残り続けるのか

学習コーパスには cors() とオプションなしがびっしりです。Stack Overflowの回答、公式のクイックスタートドキュメント、「10分でREST APIを作る」系の投稿。すべてがlocalhost向けに書かれており、ワイルドカードは無害です。

AIは「これは開発用であって本番用ではない」という注釈を学習していません。CORSサポートを追加するようプロンプトすると、AIは知っている中で最も一般的な例にそれを当てはめます。フロントエンドが特定のドメインで動いていることは知りません。認証をつなぐ予定だということも知りません。

修正は簡単です。問題は、プロンプトの中で誰もそれを求めないことです。

修正

Expressの場合は、ワイルドカードを明示的なリストに置き換えます:

const allowedOrigins = [
  'https://yourapp.com',
  'https://staging.yourapp.com',
  process.env.NODE_ENV === 'development' ? 'http://localhost:3000' : null
].filter(Boolean);

app.use(cors({
  origin: (origin, callback) => {
    if (!origin || allowedOrigins.includes(origin)) {
      callback(null, true);
    } else {
      callback(new Error('Not allowed by CORS'));
    }
  },
  credentials: true
}));

FastAPIの場合:

origins = [
    "https://yourapp.com",
    "https://staging.yourapp.com",
]

返却形式: {"translated": "翻訳されたHTML"}app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["GET", "POST", "PUT", "DELETE"],
    allow_headers=["Authorization", "Content-Type"],
)

環境変数から origins を取得します。1つの ALLOWED_ORIGINS 環境変数を、カンマ区切りで指定し、起動時に解析します。ステージングと本番は、コードに触れずに別々のままにできます。

もう2つ確認しておいてください。プリフライトの取り扱いと Access-Control-Allow-Methods です。AIが生成したコードは、カスタムミドルウェアでもそれを * に設定してしまいがちです。メソッドの明示的なリスト化には30秒かかります。

認証がない「本当に公開された」API(オープンなデータエンドポイント、公的なWebhookなど)を運用しているなら、ワイルドカードは問題なく正しい選択です。問題になるのは、ワイルドカードがユーザー固有のデータと認証と組み合わさったときに限られます。

私はこのために SafeWeave を使っています。これは Cursor と Claude Code に MCP サーバーとして組み込み、先に進む前に CORS の誤設定を指摘してくれます。とはいえ、semgrep と CORS ルールのある基本的な pre-commit hook でも、この投稿にあるほとんどは見つかるはずです。重要なのは、どんなツールを使うにせよ早い段階で見つけることです。