AI 코딩 도구가 개발 속도를 끌어올린다는 건 이제 반론하기 어렵다. 그런데 최근 두 가지 실제 사례를 나란히 읽고 나서, 속도가 만드는 구멍의 패턴이 꽤 일관되다는 걸 깨달았다. 에러 메시지가 사라진다. 로컬에서 잘 돌아간다. 그리고 진짜 문제는 훨씬 나중에, 훨씬 조용하게 드러난다.
CORS 에러를 "해결"한다는 것의 의미
dev.to에 올라온 한 글은 Cursor가 CORS 에러를 고치는 방식을 해부한다. 개발자가 프론트와 API 서버 간 CORS 에러를 Cursor에게 넘겼더니, 에러는 즉시 사라졌다. 문제는 그 해결 방식이었다. Cursor가 생성한 미들웨어는 요청의 Origin 헤더를 그대로 응답에 반사(reflection)하면서 Access-Control-Allow-Credentials: true를 함께 세팅했다. 브라우저 입장에서는 요청한 출처가 허용된 출처와 정확히 일치하니 통과시킨다. evil-site.com에서 보내도 마찬가지다.
이 패턴이 계속 재생산되는 이유가 흥미롭다. Origin reflection은 로컬 개발 환경에서 완벽하게 작동한다. localhost:3000이든 localhost:5173이든 Vercel 프리뷰 URL이든 전부 통과된다. 정확히 그 이유 때문에 Stack Overflow 답변과 boilerplate repo들이 이 패턴으로 수렴했고, AI 모델의 훈련 데이터에도 이 패턴이 가득하다. AI는 그 데이터를 충실히 재현할 뿐이다. 결국 이건 Cursor의 버그가 아니라 '에러를 없애라'는 요청에 가장 빠르게 응답하는 방식이 보안 취약점과 일치하는 구조적 문제다(CWE-942).
수정 방향은 단순하다. 요청에서 온 값을 응답에 쓰는 대신, 신뢰할 수 있는 출처 목록을 코드에 직접 박는다. 개발 환경과 프로덕션 환경을 환경변수로 분리해서 각각 명시적으로 관리한다. AI가 생성한 CORS 미들웨어에서 req.headers.origin이 응답 헤더에 그대로 흘러들어가는 패턴이 보인다면, 그건 곧바로 의심해야 할 시그널이다.
브라우저에서 AI 모델을 돌릴 때 조용히 잘리는 것들
같은 날 읽은 또 다른 글은 다른 종류의 구멍을 보여준다. 서버에 파일을 올리지 않고 브라우저에서만 AI 도구를 세 개 만들어 배포한 개발자의 실패 로그다. 이 글에서 특히 인상적인 실패는 '조용히 잘리는' 패턴이었다.
Whisper를 써서 음성을 텍스트로 변환하는 기능을 만들었는데, 5분짜리 음성을 넣으면 깔끔해 보이는 결과물이 나왔다. 문제는 그게 앞 30초에 해당하는 텍스트뿐이었다는 것이다. Whisper의 컨텍스트 윈도우가 30초이고 chunk_length_s를 설정하지 않으면 에러를 던지는 대신 조용히 첫 30초만 처리하고 완료 상태를 반환한다. 1시간짜리 강의를 넣은 사용자는 98%가 누락된 결과물을 받고도 알아채지 못할 수 있다.
WASM 힙 메모리 상한(약 1GB)을 초과할 때도 마찬가지였다. 긴 파일을 처리하다 메모리가 터지면 전체 작업이 사라졌는데, 증상은 "트랜스크립트가 음성보다 짧다"는 것뿐이었다. 이 두 실패의 공통점은 예외를 던지지 않는다는 것이다. 시스템은 정상적으로 완료 신호를 보내고, 사용자는 뭔가 빠졌다는 걸 전혀 눈치채지 못한다. 브라우저 ML 환경에서 메모리는 모델 품질보다 훨씬 먼저 실질적인 한계로 작동한다.
두 실패가 공유하는 구조
두 사례를 나란히 놓고 보면 패턴이 선명하게 드러난다. AI가 만든 구멍은 대부분 '잘못됐다'고 소리치지 않는다. Cursor가 생성한 CORS 코드는 에러를 없애기 때문에 배포된다. Whisper의 30초 컨텍스트 제한은 성공 응답을 돌려주기 때문에 통과된다. 두 경우 모두 로컬 테스트와 일반적인 QA 흐름으로는 잡히지 않는다.
이 맹점들의 공통 원인을 하나로 추리면 이렇다: AI는 '에러를 없애는 것'과 '문제를 해결하는 것'을 구분하지 않는다. 훈련 데이터는 동작하는 코드 스니펫을 긍정적 샘플로 학습했지, 그 코드가 특정 환경에서 어떤 부작용을 만드는지를 함께 학습하지 않았다. 결과적으로 AI는 표면적 증상 제거에 최적화된 코드를 생성하고, 개발자는 그 코드가 맥락 안에서 어떻게 작동하는지 직접 검증해야 한다.
실무에서 이 구멍들을 막는 방법
CORS 취약점에 대해서는 접근이 비교적 명확하다. AI가 생성한 모든 CORS 미들웨어를 배포 전에 코드 리뷰 체크리스트에 넣고, req.headers.origin이 응답 헤더에 직접 흘러가는 패턴을 semgrep 같은 정적 분석 도구로 걸러낸다. 허용할 출처 목록은 코드에 명시적으로 박고, 환경별로 분리한다. Cursor나 Claude Code에 SafeWeave 같은 MCP 서버를 붙여 생성 단계에서 플래그를 올리는 것도 하나의 옵션이다.
브라우저 ML 환경의 조용한 실패는 구조적 방어가 필요하다. 모델의 컨텍스트 제한과 메모리 특성을 먼저 파악하고, 긴 파일 처리 시 예상 출력 크기와 실제 출력 크기를 교차 검증하는 로직을 넣는다. WASM 힙 압박은 워커를 세그먼트마다 종료하고 재생성하는 방식으로 우회한다. 그리고 "물리적으로 불가능한 값"—예를 들어 원본 신호보다 큰 에너지를 가진 스템 출력—을 조기에 감지하는 검증을 파이프라인에 넣으면, 결함 있는 모델 파일과 잘못된 파이프라인을 빠르게 구분할 수 있다.
속도를 가져가면, 검증 설계는 개발자의 몫이다
AI 코딩 도구가 실제로 만드는 가장 위험한 구멍은 코드 품질의 문제가 아니다. '작동한다'는 신호가 '올바르다'는 신호와 동일시되는 착각이다. 에러 메시지가 사라지고 로컬 테스트가 통과하면, 개발자는 다음 기능으로 넘어간다. AI는 그 심리를 정확히 활용한다—의도하지 않더라도.
AI 워크플로우에서 속도를 진짜로 얻으려면, 그 속도가 만드는 맹점을 검증하는 구조를 팀이 직접 설계해야 한다. 생성된 코드의 보안 패턴을 정적으로 검사하는 훅, 모델 출력의 물리적 타당성을 검증하는 단계, 조용한 실패를 드러내는 경계값 테스트—이것들은 AI가 대신 만들어주지 않는다. 그리고 바로 그 지점이, AI 시대 개발자의 판단력이 가장 선명하게 드러나는 자리다.