한 팀은 애플리케이션 코드 생성에 AI에 크게 의존했습니다. 이 관행은 이제 "바이브 코딩(vibe coding)"이라고 불립니다. 배포 후 일주일 만에 서버가 침해당했습니다. 이 사건을 공유한 개발자는 취약점이 예측 가능했기 때문에 즉시 공격 벡터를 짐작할 수 있었습니다. 이 글에서는 무엇이 잘못되었는지, AI 생성 코드가 보안 익스플로잇에 유독 취약한 이유, 그리고 AI 기반 프로젝트를 프로덕션에 배포하기 전에 보안을 강화하기 위한 구체적인 체크리스트를 설명합니다.
발생한 사건: 무슨 일이 있었나
이 이야기는 2026년 1월 Reddit의 r/webdev 커뮤니티에 올라왔고, 빠르게 400개 이상의 좋아요를 받으며 뜨거운 논쟁을 불러일으켰습니다. 한 개발자는 두 동료가 최소한의 수동 검토만으로 ChatGPT, Claude, Cursor와 같은 AI 코드 생성 도구를 사용하여 애플리케이션을 빠르게 구축하는 "바이브 코딩(vibe coding)" 관행을 받아들였을 때 회사에서 일어난 일을 공유했습니다.
팀은 들떠 있었습니다. 그들은 빠르게 배포했습니다. AI는 데이터베이스 쿼리부터 인증 흐름에 이르기까지 모든 것을 처리했습니다. 배포 시간이 다가오자 AI는 첫 릴리스를 위한 버전 번호로 "16.0.0"을 제안하기까지 했는데, 이는 나중에 어둡게 아이러니하게 들릴 세부 사항이었습니다.
배포 후 일주일 만에, 서버가 해킹당했습니다.
이야기를 공유한 개발자는 놀라지 않았습니다. 코드베이스를 살펴보니, AI가 도입한 여러 보안 취약점을 즉시 식별할 수 있었습니다. 공격자들도 그것들을 찾아냈습니다.
이는 고립된 사건이 아닙니다. 보안 연구원들은 언어 모델이 학습되는 방식과 코딩 작업을 처리하는 방식 때문에 AI 생성 코드에서 거의 독점적으로 나타나는 보안 결함인 "합성 취약점(synthetic vulnerabilities)"에 대해 경고해 왔습니다.
AI 생성 코드가 취약한 이유
AI 코딩 비서는 방대한 공개 코드 저장소로 훈련됩니다. 이는 몇 가지 보안 사각지대를 만듭니다.
1. 훈련 데이터에 취약한 코드가 포함되어 있음
GitHub, Stack Overflow 및 튜토리얼 웹사이트에는 수백만 줄의 안전하지 않은 코드가 포함되어 있습니다. 학습 목적으로 작성된 예제는 종종 보안 고려 사항을 건너뜁니다. 더 이상 사용되지 않는 패턴도 훈련 데이터에 남아 있습니다. AI는 이 모든 것을 똑같이 학습합니다.
AI에게 인증 코드를 작성해 달라고 요청하면, CSRF 보호 기능이 없던 2018년 튜토리얼의 패턴을 재현하거나, 단순함을 위해 비밀번호를 평문으로 저장한 Stack Overflow 답변을 재현할 수 있습니다.
2. AI는 "보안"이 아닌 "작동"에 최적화됨
언어 모델은 프롬프트를 만족시키는 코드를 생성합니다. 로그인 엔드포인트를 요청하면 AI는 사용자를 로그인시키는 무언가를 만듭니다. 해당 구현이 SQL 인젝션을 막는지, 비밀번호를 올바르게 해싱하는지, 또는 세션 토큰을 유효성 검사하는지는 주요 목표에 비해 부차적입니다.
이는 숙련된 개발자가 생각하는 방식과는 근본적으로 다릅니다. 보안을 의식하는 개발자는 각 단계에서 "이것이 어떻게 악용될 수 있을까?"라고 묻습니다. AI 비서는 이러한 적대적인 사고방식을 자연스럽게 적용하지 않습니다.
3. 컨텍스트 창 제한으로 인한 전체론적 보안 방해
보안 취약점은 종종 구성 요소 간의 상호 작용에서 발생합니다. 인증 확인은 한 파일에 존재할 수 있고, 다른 파일의 데이터베이스 쿼리는 이미 인증이 완료되었다고 가정할 수 있습니다. AI가 파일 단위 또는 함수 단위로 코드를 생성하면 항상 이러한 보안 컨텍스트를 유지할 수 없습니다.
4. 개발자들이 AI 결과물을 너무 많이 신뢰함
이것은 인간적인 요소입니다. AI가 자신감 있고 유능해 보이는 코드를 생성하면, 개발자들은 종종 주니어 팀원의 코드에 적용했을 신중한 검토를 건너뜁니다. "바이브 코딩(vibe coding)" 접근 방식은 이를 명시적으로 수용합니다: 빠르게 생성하고, 빠르게 배포하고, 나중에 수정합니다.
문제는 공격자가 보안 취약점을 먼저 발견하면 "나중에 수정"할 수 없는 경우가 많다는 것입니다.
AI 생성 API에서 가장 흔한 7가지 보안 허점
AI 생성 코드 저장소 및 보안 감사 분석을 기반으로, 다음 취약점들이 가장 빈번하게 나타납니다.
1. 누락되거나 취약한 입력 유효성 검사
AI 생성 엔드포인트는 종종 사용자 입력을 새니타이징 없이 직접 받습니다.
// AI-generated: Vulnerable to injection
app.post('/search', (req, res) => {
const query = req.body.searchTerm;
db.query(`SELECT * FROM products WHERE name LIKE '%${query}%'`);
});
해결책은 매개변수화된 쿼리, 입력 길이 제한 및 문자 유효성 검사를 요구하는데, AI는 이러한 단계를 자주 생략합니다.
2. 깨진 인증 흐름
일반적인 문제점은 다음과 같습니다.
- httpOnly 쿠키 대신 localStorage에 저장된 토큰
- 토큰 만료 누락
- 취약하거나 예측 가능한 세션 ID
- 로그인 시도에 대한 속도 제한 없음
- 만료되지 않는 비밀번호 재설정 토큰
3. 과도한 데이터 노출
AI는 특정 필드를 선택하기보다는 전체 데이터베이스 객체를 반환하는 경향이 있습니다.
// AI-generated: Returns sensitive fields
app.get('/user/:id', async (req, res) => {
const user = await User.findById(req.params.id);
res.json(user); // Includes passwordHash, internalNotes, etc.
});
4. 누락된 권한 부여 확인
AI는 작동하는 엔드포인트를 생성하지만, 요청하는 사용자가 권한을 가지고 있는지 확인하는 것을 잊습니다.
// AI-generated: No ownership verification
app.delete('/posts/:id', async (req, res) => {
await Post.deleteOne({ _id: req.params.id });
res.json({ success: true });
});
// 어떤 인증된 사용자라도 어떤 게시물이든 삭제할 수 있음
5. 안전하지 않은 종속성
AI는 알려진 취약점을 확인하지 않고 인기 있는 패키지를 제안하는 경우가 많습니다.
// AI suggests outdated package with CVEs
const jwt = require('jsonwebtoken'); // Version not specified
명시적인 버전 고정(pinning)과 취약점 스캐닝 없이는 프로젝트는 첫날부터 보안 부채를 상속받습니다.
6. 하드코딩된 비밀과 자격 증명
이는 AI 생성 코드에서 놀랍도록 자주 나타납니다.
// AI-generated: Secret in source code
const stripe = require('stripe')('sk_live_abc123...');
AI는 설명을 위해 하드코딩된 키가 흔히 사용되는 튜토리얼과 예제로부터 학습합니다.
7. 누락된 보안 헤더
AI가 생성한 Express, Flask 또는 Rails 앱에는 일반적으로 다음이 부족합니다.
- CORS 설정 (또는 과도하게 허용적인 CORS)
- Content-Security-Policy 헤더
- X-Frame-Options
- 속도 제한 미들웨어
- HTTPS 적용
AI 기반 프로젝트를 위한 보안 테스트 체크리스트
AI 생성 코드가 포함된 프로젝트를 배포하기 전에 다음 체크리스트를 확인하십시오.
인증 및 권한 부여
- [ ] 모든 엔드포인트는 적절한 경우 인증을 요구합니다
- [ ] 권한 부여 확인은 사용자가 요청된 리소스를 소유하거나 접근할 수 있는지 검증합니다
- [ ] 비밀번호는 bcrypt, Argon2 또는 유사한 방식으로 해싱됩니다 (비용 요소 ≥10)
- [ ] 세션 토큰은 암호학적으로 무작위이며 만료됩니다
- [ ] 실패한 로그인 시도는 속도 제한됩니다
- [ ] 비밀번호 재설정 토큰은 일회성이며 시간 제한이 있습니다
- [ ] JWT에는 만료가 포함되어 있으며 서버 측에서 유효성 검사가 이루어집니다
입력 유효성 검사
- [ ] 모든 사용자 입력은 유형, 길이 및 형식에 대해 유효성 검사가 이루어집니다
- [ ] 데이터베이스 쿼리는 매개변수화된 문을 사용합니다
- [ ] 파일 업로드는 유형, 크기를 유효성 검사하고 악성 코드를 스캔합니다
- [ ] URL 및 리다이렉션은 허용 목록에 대해 유효성 검사가 이루어집니다
- [ ] JSON/XML 파서는 크기 제한이 구성되어 있습니다
데이터 보호
- [ ] API 응답은 필요한 필드만 반환합니다
- [ ] 민감한 데이터는 저장 시 암호화됩니다
- [ ] 데이터베이스 자격 증명은 코드가 아닌 환경 변수를 사용합니다
- [ ] 비밀은 적절한 비밀 관리 시스템에 저장됩니다
- [ ] 로그에는 비밀번호, 토큰 또는 PII가 포함되지 않습니다
전송 보안
- [ ] 프로덕션 환경에서 HTTPS가 강제 적용됩니다
- [ ] HSTS 헤더가 구성되어 있습니다
- [ ] TLS 1.2+가 필요합니다
- [ ] 보안 쿠키는 Secure 및 HttpOnly 플래그를 가집니다
API별 보안
- [ ] 속도 제한으로 남용을 방지합니다
- [ ] CORS는 `*` 대신 특정 출처(origin)에 대해 구성됩니다
- [ ] API 버전 관리는 안전하지 않은 엔드포인트의 사용 중단을 허용합니다
- [ ] 오류 메시지는 내부 세부 정보를 유출하지 않습니다
- [ ] GraphQL에는 쿼리 깊이/복잡도 제한이 있습니다
종속성
- [ ] 모든 패키지에는 특정 버전 고정(pin)이 있습니다
- [ ] `npm audit` / `pip check` / 유사 도구에서 심각한 취약점이 발견되지 않습니다
- [ ] 자동 종속성 업데이트가 구성되어 있습니다
- [ ] 버려지거나 유지보수되지 않는 패키지가 없습니다
배포 전 API 보안을 테스트하는 방법
수동 검토만으로는 충분하지 않습니다. AI가 도입하고 검토 과정에서 놓쳤을 수 있는 취약점을 잡아내는 체계적인 테스트가 필요합니다.
1단계: 자동화된 보안 스캐닝
일반적인 취약점을 찾는 데 설계된 도구를 사용하십시오.
# For Node.js projects
npm audit --audit-level=high
# For Python projects
pip-audit
# For container images
trivy image your-app:latest
2단계: API 보안 테스트
바로 이 지점에서 Apidog이 필수적인 도구가 됩니다. 각 엔드포인트를 수동으로 테스트하는 대신 다음을 수행할 수 있습니다.
- API 사양 (OpenAPI/Swagger)을 가져오거나 Apidog이 엔드포인트를 검색하도록 합니다.

2. 다음을 확인하는 보안 테스트 시나리오를 만듭니다.
- 인증 누락 시 401 반환
- 잘못된 사용자가 리소스에 접근 시 403 반환
- 유효하지 않은 입력 시 안전한 오류 메시지와 함께 400 반환
- SQL 인젝션 시도가 차단됨
- 각 배포 전에 **자동화된 테스트 스위트를 실행합니다.**
- 회귀를 감지하기 위해 **CI/CD와 통합합니다.**
Apidog의 시각적 테스트 빌더를 사용하면 보안 테스트를 처음부터 작성할 필요가 없습니다. "응답에 'password'가 포함되어서는 안 됩니다" 또는 "인증 토큰 없는 요청은 401을 반환해야 합니다"와 같은 어설션(assertion)을 정의하고 전체 API 표면에서 실행할 수 있습니다.
3단계: 침투 테스트 시뮬레이션
공격자가 하는 것처럼 API를 테스트하십시오.
- **엔드포인트를 열거합니다** - 숨겨지거나 문서화되지 않은 경로가 있습니까?
- **인증 우회를 테스트합니다** - 유효한 토큰 없이 보호된 경로에 접근할 수 있습니까?
- **인젝션 공격을 시도합니다** - 모든 입력 필드에 SQL, NoSQL, 명령 인젝션을 시도합니다.
- **IDOR을 확인합니다** - 사용자 A가 ID를 변경하여 사용자 B의 데이터에 접근할 수 있습니까?
- **속도 제한을 남용합니다** - 초당 1000개의 요청을 보내면 어떤 일이 발생합니까?
Apidog의 테스트 시나리오를 사용하면 이러한 공격을 체계적으로 시뮬레이션하고, 배포 간 비교를 위해 결과를 저장할 수 있습니다.
4단계: 보안 헤더 감사
응답 헤더를 확인하십시오.
curl -I https://your-api.com/endpoint
다음을 확인하십시오.
- `Strict-Transport-Security`
- `X-Content-Type-Options: nosniff`
- `X-Frame-Options: DENY`
- `Content-Security-Policy`
AI 도구를 사용한 보안 우선 워크플로우 구축
AI 코딩 비서는 사라지지 않을 것이며, 점점 더 강력해지고 있습니다. 해결책은 이들을 피하는 것이 아니라 워크플로우에 보안을 구축하는 것입니다.
보안을 위한 프롬프트 엔지니어링
AI를 사용하여 코드를 생성할 때, 보안 고려 사항을 명시적으로 요청하십시오.
대신:
"사용자 등록 엔드포인트를 만드세요"
다음과 같이 요청하세요:
"입력 유효성 검사, 비용 요소 12를 사용하는 bcrypt를 이용한 비밀번호 해싱, 타이밍 공격 방어, 속도 제한, 그리고 이메일 존재 여부 정보를 유출하지 않는 적절한 오류 처리를 포함하는 사용자 등록 엔드포인트를 만드세요"
필수 검토 단계
AI 생성 코드가 다음을 통과해야 하는 워크플로우를 구축하십시오.
- **인간 검토** - 이 코드가 우리가 의도한 대로 작동합니까?
- **자동화된 린팅** - 보안 플러그인이 있는 ESLint, Pylint
- **보안 스캐닝** - Snyk, npm audit, OWASP 종속성 검사
- **API 테스트** - 보안 요구 사항을 검증하는 Apidog 테스트 스위트
- **스테이징 배포** - 실제 환경에서 통합 테스트를 실행합니다
AI 코드를 신뢰할 수 없는 입력처럼 취급하세요
이것이 핵심적인 사고방식 전환입니다. AI의 코드는 알 수 없는 기여자의 코드와 동일한 회의적인 시각으로 다루어져야 합니다. 임의의 풀 리퀘스트 코드를 검토 없이 배포하시겠습니까? AI 생성 코드에도 동일한 기준을 적용하십시오.
결론
배포 후 일주일 만에 발생한 서버 해킹은 정교한 공격자나 제로데이 익스플로잇 때문이 아니었습니다. 이는 AI 도구가 일상적으로 도입하고 "바이브 코딩(vibe coding)" 관행이 일상적으로 놓치는 일반적인 취약점 때문에 발생했습니다.
AI 코드 생성은 강력합니다. 개발 속도를 높이고 복잡한 작업을 접근 가능하게 만듭니다. 그러나 체계적인 보안 테스트 없이는 그 속도가 오히려 부담으로 작용합니다.
Apidog과 같은 도구는 API 전체에 걸쳐 보안 요구 사항을 정의하고 자동화할 수 있게 하여 보안 테스트를 실용적으로 만듭니다. 목표는 AI 기반 개발 속도를 늦추는 것이 아니라, AI 생성 코드가 요구하는 검증 계층을 구축하는 것입니다.
당신의 서버는 코드가 인간이 작성했는지 AI가 작성했는지 신경 쓰지 않습니다. 단지 그 코드가 안전한지 여부에만 관심이 있습니다.
