Cursor가 CORS를 * 로 설정하는 이유 (그리고 해결 방법)

발행: (2026년 4월 8일 AM 03:14 GMT+9)
6 분 소요
원문: Dev.to

Source: Dev.to

TL;DR

  • 대부분의 AI‑생성 Express 백엔드에서 와일드카드 CORS(Access-Control-Allow-Origin: *)가 나타납니다.
  • Cursor는 많은 학습 데이터 예제에서 origin 화이트리스트를 생략하기 때문에 이를 기본값으로 사용합니다.
  • 해결 방법: origin: '*'를 런타임 허용 목록 함수로 교체하십시오 – 몇 분이면 작업이 끝나고 추가 의존성이 전혀 없습니다.

Source:

문제

Cursor로 생성된 사이드 프로젝트를 검토하던 중, 모든 라우트가 어떤 도메인에서도 접근 가능하도록 열려 있음을 발견했습니다:

app.use(cors({ origin: '*' }));

이 패턴은 제가 살펴본 대부분의 AI‑생성 Express 백엔드에서 나타납니다. 이는 특정 Cursor 버그가 아니라 훈련 데이터 문제입니다. 많은 StackOverflow 답변이 개발자들에게 CORS를 가르칠 때 origin: '*'를 사용했으며, 이는 “브라우저 요청을 작동하게 만들기”는 즉각적인 문제를 해결하지만 보안을 무시합니다.

“내 Express API에 CORS를 추가해 주세요”라고 요청했을 때 Cursor가 생성하는 전형적인 코드 조각은 다음과 같습니다:

import cors from 'cors';

// CWE-346: Origin Validation Error
app.use(cors({
  origin: '*',
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  credentials: true
}));

origin: '*'credentials: true를 함께 사용하면 대부분의 브라우저에서 거부되어 개발자는 CORS 오류를 겪고 수정 요청을 합니다. 일반적인 “수정” 방법은 '*'를 특정 문자열로 바꾸는 것이지만, AI가 여전히 '*'를 쓰거나 allowedHeaders: '*'를 제안하는 경우가 있어 근본적인 문제가 해결되지 않습니다.

자격 증명이 없더라도 인증된 API에 와일드카드 CORS를 적용하면 어떤 웹사이트든 피해자의 브라우저에서 요청을 보내고 응답을 읽을 수 있습니다. 사용자가 로그인된 상태라면 세션 토큰이 요청에 함께 전송되어 실제 공격 표면이 생깁니다.

왜 계속 발생하는가

  1. CORS 오류는 고통스럽다 – 개발자는 빠른 해결책을 원한다.
  2. 와일드카드 CORS는 동작한다 – 요청이 성공하고 오류나 경고가 없으므로 개발자는 그대로 진행한다.
  3. 위험이 눈에 보이지 않는다 – 스택 트레이스, 모니터링 알림, 테스트 실패가 없으며, 누군가 코드를 감사할 때까지 남아 있다.

보안 수정

정적 문자열을 요청의 Origin을 허용 목록과 비교하는 검증 함수로 교체합니다:

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

app.use(
  cors({
    origin: (origin, callback) => {
      // Allow non‑browser requests (no Origin header)
      if (!origin) return callback(null, true);
      if (ALLOWED_ORIGINS.includes(origin)) return callback(null, true);
      callback(new Error(`CORS blocked: ${origin}`));
    },
    credentials: true,
    methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
    allowedHeaders: ['Content-Type', 'Authorization'],
  })
);

핵심 포인트

  • !origin 경우는 의도적으로 통과합니다 – 서버‑대‑서버 요청 및 CLI 도구는 Origin 헤더를 보내지 않으며, 이는 정상입니다.
  • credentials: true'*'가 명시적인 검증 함수로 대체되었기 때문에 안전합니다.

자동화 테스트

권한이 없는 출처가 차단되는지 확인하는 통합 테스트를 추가합니다:

it('blocks requests from unauthorized origins', async () => {
  const res = await request(app)
    .get('/api/user/me')
    .set('Origin', 'https://malicious.example.com');
  expect(res.headers['access-control-allow-origin']).toBeUndefined();
});

이 테스트를 CI 파이프라인에 포함시켜, 향후 AI가 생성한 변경 사항이 허용적인 CORS 설정으로 되돌아가는 경우 자동으로 감지하도록 합니다.

Beyond Express

동일한 문제가 다른 프레임워크에서도 나타납니다:

  • Next.jsnext.config.js에서 cors 설정
  • FastAPIallow_origins와 함께 사용하는 CORSMiddleware
  • DjangoCORS_ALLOWED_ORIGINS 설정
  • Railsorigins와 함께 사용하는 rack-cors

모든 프레임워크에 비슷한 설정이 있으며, AI 편집기는 종종 허용적인 옵션을 기본값으로 선택합니다.

문제 조기 감지

저는 SafeWeave를 사용하고 있습니다. 이 도구는 Cursor와 Claude Code에 MCP 서버로 연결되어 이러한 패턴을 표시합니다. semgrep이나 gitleaks와 같은 도구를 이용한 기본적인 pre‑commit 훅만으로도 여기서 설명한 대부분의 문제 설정을 잡아낼 수 있습니다. 중요한 점은 어떤 도구를 선택하든 개발 워크플로우 초기에 검사를 통합하는 것입니다.

0 조회
Back to Blog

관련 글

더 보기 »

MERN 퀴즈 앱 프로젝트 완료!

Features - 📝 다중 선택 퀴즈 풀기 - 📊 즉시 결과 보기 - 🎨 깨끗하고 반응형 UI - ✅ 데이터베이스에 퀴즈 저장 - 🔄 새 퀴즈를 쉽게 추가...