
【정리】 AI 생성 코드의 보안 리뷰 시 확인해야 할 포인트
요약
AI 생성 코드가 급증함에 따라 발생할 수 있는 보안 취약점을 방지하기 위한 실무적인 코드 리뷰 가이드를 제공합니다. AI가 작성한 코드의 올바름, 안전성, 운용성, 유지보수성을 중심으로 검토해야 할 핵심 포인트와 도구 활용법을 정리합니다.
핵심 포인트
- AI 생성 코드는 구문이 정확하더라도 보안 취약점이 포함될 수 있음
- 리뷰의 4대 핵심 요소: 올바름, 안전성, 운용성, 유지보수성
- PR 리뷰, 정적 분석, 의존성 체크, 시크릿 탐지 등의 조합 필요
- AI 리뷰는 인간의 리뷰를 대체하는 것이 아닌 보완하는 역할임
안녕하세요, miruky입니다.
지난 1년 정도, 바이브 코딩(Vibe Coding)으로 만들어진 앱의 취약성이 화제가 되는 장면이 매우 많아지고 있다는 인상을 받습니다. AI에게 구현을 맡기기 쉬워진 만큼, 생성된 코드를 어떻게 리뷰할지가 중요해지고 있습니다.
이 기사에서는 AI 생성 코드를 리뷰할 때 살펴봐야 할 보안 관점을 실무에서 사용할 수 있는 수준으로 정리합니다. 특히 2025년부터 2026년 상반기까지 뜨거웠던 이 주제에 대해 일단 정리해 보는 시도입니다.
이번에 가볍게 다루는 시큐어 프로그래밍(Secure Programming) 자체를 깊이 알고 싶은 분들을 위해, 이전에 어느 정도 자세히 정리해 둔 기사가 있습니다. SQL 인젝션(SQL Injection), XSS, CSRF, 인증(Authentication), 인가(Authorization), 로그(Log), 의존 관계(Dependency)까지 기초부터 확인하고 싶다면 이쪽도 참고해 주세요.
- AI 생성 코드를 다루는 전제
- 리뷰의 전체상
- 입력과 출력을 신뢰하지 않기
- 인증과 인가를 매번 확인하기
- 비밀 정보와 로그 재검토하기
- 의존 관계와 설정 파일 확인
- AI 에이전트가 다루는 권한 확인
- 에러 처리와 테스트로 고장 나는 방식 확인하기
- PR에 남기면 좋은 정보
- AI를 리뷰 측에 사용할 때의 주의점
- PR 리뷰에서 확인하는 10가지 항목
AI가 생성한 코드를 처음부터 나쁜 것으로 취급할 필요는 없습니다. 다만, 경험이 적은 개발자가 빠르게 작성한 코드를 읽는 것과 비슷하게 읽는 것이 적절합니다. 최신 AI를 사용하면 구문(Syntax)은 올바르게 작성해 줍니다. 명명(Naming)도 (어느 정도) 자연스럽습니다. 코멘트도 (때로는 장황할 때도 있지만) 친절합니다. 테스트 코드까지 곁들여 주는 경우도 있습니다. 여러 가지가 갖춰져 있기 때문에 읽는 쪽이 방심할 수도 있습니다. 살펴봐야 할 것은 코드가 자연스러운지 여부가 아니라, 대체로 다음 4가지 포인트로 집약됩니다.
$$
\displaylines{
\text{① 올바름: 요구사항대로 동작하는가} \
\text{② 안전성: 공격자에게 악용되지 않는가} \
\text{③ 운용성: 장애 시 추적이 가능한가} \
\text{④ 유지보수성: 나중에 안전하게 수정할 수 있는가}
}
$$
GitHub의 Copilot Code Review 공식 문서에서도 AI 리뷰는 인간의 리뷰를 대체하는 것이 아니라 보완하는 것이라고 명시되어 있습니다. 이는 실무 프로젝트(PJ)에서는 당연한 일입니다. 설령 개인 개발이라 하더라도 변하지 않는 사실이라고 생각합니다. 모처럼 멋진 아이디어로 개인 개발을 진행하더라도, 제대로 된 리뷰를 소홀히 하여 사용자의 개인정보나 API 키 등을 유출하게 되면 금전적으로나 명예적으로나 영원한 타격을 입게 됩니다. 매우 아까운 일입니다.
AI 생성 코드라고 해서 특수한 리뷰를 하는 것이라기보다, 일반적인 코드 리뷰에서 봐야 할 관점을 더 깊게 보는 이미지입니다. AI 코딩 툴은 지시 파일이나 프롬프트(Prompt)에 따라 거동이 상당히 달라집니다. 리뷰 품질을 높이려면 AI에게 맡기기 전의 규칙 정비도 중요합니다.
AI 생성 코드는 PR(Pull Request)에 올라온 시점에 모아서 읽는 것만으로는 부족합니다. 생성량이 늘어날수록 인간만이 세부 사항을 계속 잡아내는 것은 어려워집니다. 따라서 PR 리뷰, 정적 분석(Static Analysis), 의존 관계 체크, 시크릿 탐지(Secret Detection), 테스트를 조합합니다.
리뷰에서 중요한 것은 AI의 제안을 그대로 믿지 않는 것입니다. 실무에서는 다음과 같이 역할을 나누면 리뷰하기 쉬워집니다.
| 역할 | 담당 |
|---|---|
| 구문 및 전형적인 취약성 검출 | SAST, CodeQL, Semgrep 등 |
| ... |
AI 생성 코드의 리스크는 단일 파일에만 국한되지 않습니다. Wiz의 SDLC Security 2026에서도 리스크는 소스 코드 단체가 아니라 개발자 도구, ID, CI/CD, 클라우드 환경과의 관계로부터 확장된다고 정리되어 있습니다.
즉, 리뷰 대상은 '생성된 함수'만이 아닙니다. PR에서 변경된 설정, 의존 관계, CI/CD, IAM, Dockerfile, IaC까지 포함해서 봅니다.
AI 생성 코드에서 가장 먼저 보는 것은 외부에서 들어오는 값의 처리입니다. 사용자 입력, URL 파라미터, JSON body, Cookie, HTTP 헤더, 파일명, Webhook의 페이로드(Payload) 등은 모두 공격자가 조작할 가능성이 있습니다.
특히 살펴봐야 할 곳은 SQL, HTML, OS 커맨드, 파일 경로, URL에 입력값을 섞고 있는 곳입니다.
다음과 같이 문자열 결합으로 SQL을 만드는 코드는 위험합니다.
# 위험한 예
def find_user(conn, email):
sql = f"SELECT id, name FROM users WHERE email = '{email}'"
...
다시 검토한다면, 플레이스홀더 (Placeholder)를 사용하여 SQL과 값을 분리합니다.
# 수정 후
def find_user(conn, email):
sql = "SELECT id, name FROM users WHERE email = ?"
...
AI는 '간단한 샘플'로서 문자열 결합을 제시할 때가 있습니다. 동작하는 코드이기는 하지만, 공격자가 입력값을 조작할 수 있는 경우에는 SQL 인젝션 (SQL Injection)으로 이어집니다.
웹 화면에 사용자 입력을 출력할 때는, HTML로 이스케이프 (Escape)되는 곳에서 출력합니다.
# 위험한 예
return f"<p>{comment}</p>"
템플릿 엔진 (Template Engine)을 사용하는 경우에도, 자동 이스케이프 (Auto-escaping)가 활성화되어 있는지, 혹은 명시적으로 비활성화하지 않았는지 확인합니다.
<!-- 수정 후의 이미지 -->
<p>{{ comment }}</p>
AI가 생성한 코드에서는 겉보기의 샘플을 우선시하여, 이스케이프를 생략한 문자열 HTML을 내놓을 때가 있습니다. 리뷰에서는 HTML, JavaScript, URL, CSS 등 출력 대상의 문맥 (Context)에 따라 안전한 처리가 되어 있는지 확인합니다.
사용자 입력을 셸 커맨드 (Shell Command)로 전달하는 코드는 특히 주의해야 합니다.
# 위험한 예
import os
def convert(path):
...
가능하다면 셸 (Shell)을 사용하지 않고 라이브러리나 인자 배열 (Argument Array)을 사용합니다. 파일명을 받는 경우에는 허가된 디렉토리 내의 파일인지, 허가된 확장자인지, 출력 경로가 고정되어 있는지도 확인합니다.
# 수정 후
from pathlib import Path
import subprocess
...
파일 경로의 경우, ../를 사용한 패스 트래버설 (Path Traversal)에도 주의해야 합니다. 업로드된 파일명을 그대로 저장 경로로 사용하는 코드는 생성된 코드든 사람이 작성한 코드든 위험합니다. 실무에서는 확장자뿐만 아니라 MIME 타입이나 파일 실체 검사, 이미지 처리 라이브러리 측의 안전한 설정도 확인합니다.
MITRE의 2025 CWE Top 25에서는 XSS, SQL 인젝션 (SQL Injection), CSRF, 권한 부족 (Broken Access Control), 패스 트래버설 (Path Traversal), OS 커맨드 인젝션 (OS Command Injection) 등이 상위에 올라와 있습니다. AI 생성 코드를 볼 때도 이러한 고전적인 취약점을 놓쳐서는 안 됩니다.
AI 생성 코드에서 특히 간과하면 위험한 것이 권한 부여 (Authorization)입니다.
인증 (Authentication)은 '누구인지'를 확인하는 메커니즘입니다. 권한 부여 (Authorization)는 '그 사람이 해당 조작을 해도 되는지'를 확인하는 메커니즘입니다.
AI는 로그인 확인 로직을 넣어줄 때가 있습니다. 하지만 로그인이 되어 있다고 해서, 반드시 그 데이터를 봐도 된다는 뜻은 아닙니다.
예를 들어, 로그인한 사용자만 호출할 수 있는 API라 하더라도, 타인의 주문 ID를 지정하여 가져올 수 있다면 문제가 됩니다.
# 위험한 예
@app.get("/orders/{order_id}")
def get_order(order_id: int, current_user: User = Depends(get_current_user)):
...
이 코드는 로그인 확인은 하고 있지만, 해당 주문이 현재 사용자의 것인지는 확인하지 않습니다.
# 수정 후
@app.get("/orders/{order_id}")
def get_order(order_id: int, current_user: User = Depends(get_current_user)):
...
OWASP Top 10 2025에서는 권한 제어 미흡 (Broken Access Control)이 A01로 다뤄집니다. 관리자 (admin)만 볼 수 있어야 하는 화면을 일반 사용자가 URL이나 ID 지정만 바꿔서 볼 수 있는 것 등이 대표적인 사례입니다. AI가 생성한 API나 관리 화면에서는 라우팅 (Routing)마다 '누가', '어떤 조건으로', '무엇을 할 수 있는지'를 확인해야 합니다.
특히 다음과 같은 기능은 면밀히 살펴봅니다.
| 기능 | 확인 사항 |
|---|---|
| 관리자용 API | 일반 사용자가 호출할 수 없는가 |
| ... |
AI가 취약점을 찾아내는 측면에서 강해지고 있는 한편, AI 생성 코드 자체에도 권한 부여 (Authorization) 누락이 발생합니다. 권한 부여는 정적 분석 (Static Analysis)만으로는 모두 잡아내기 어려운 경우가 많으므로, 업무 규칙을 알고 있는 사람이 "이 조작이 정말로 이 사용자에게 허용되는가"를 확인해야 합니다.
AI 생성 코드는 샘플로서 API 키, 비밀번호, 토큰을 직접 작성(hard-coding)해 버리는 경우가 있습니다. 리뷰에서는 다음과 같은 값들이 코드, 설정 파일, 테스트, README, 로그 출력에 포함되어 있지 않은지 확인합니다.
| 종류 | 예 |
|---|---|
| API 키 | 외부 서비스의 액세스 토큰 (Access Token) |
| ... |
GitHub Copilot cloud agent의 설명에서는 생성된 코드에 대해 CodeQL, 의존성 확인, 시크릿 탐지 (Secret Detection)를 수행하는 것이 소개되어 있습니다. 사람의 리뷰에서도 동일한 관점을 가지면 확인 누락을 줄일 수 있습니다.
다음과 같은 코드는 즉시 재검토해야 합니다. 여담이지만, 실제로 API 키를 입력하지 않았더라도 「◯◯_API_KEY」와 같은 코드가 있는 것만으로도 해당 GitHub 리포지토리(Repository)에 대한 부자연스러운 접근이 증가할 수 있습니다. 십중팔구 API 키를 노리는 공격자라고 생각합니다.
# 위험한 예
OPENAI_API_KEY = "sk-xxxxxxxxxxxxxxxx"
DB_PASSWORD = "password123"
환경 변수(Environment Variable)나 Secrets Manager 등 운영 방식에 맞는 방법으로 변경합니다.
# 재검토 후
import os
openai_api_key = os.environ["OPENAI_API_KEY"]
...
단, 환경 변수에 둔다고 해서 끝이 아닙니다. CI/CD 로그에 표시되지 않는지, AI 에이전트가 읽을 수 있는 위치에 두지 않았는지, PR(Pull Request)의 차이점(Diff)에 나타나지 않는지도 확인합니다.
Claude Code나 Gemini CLI와 같이 파일 읽기/쓰기나 명령 실행이 가능한 AI 에이전트의 경우, 도구 측면의 권한 제어(Permission Control)도 중요합니다. AI 에이전트의 보안 설정은 다음 기사에서 개별적으로 정리하고 있습니다.
에러 조사를 위해 상세한 로그를 남기고 싶어지지만, 요청 헤더(Request Header), 쿠키(Cookie), Authorization 헤더, 신용카드 정보, 비밀번호 재설정 URL 등을 그대로 출력해서는 안 됩니다.
# 위험한 예
logger.info("request headers=%s body=%s", request.headers, request.body)
로그에 남기는 것은 조사에 필요한 ID, 처리 결과, 실패 이유, 요청 ID(Request ID) 등으로 한정합니다.
# 재검토 후
logger.info(
"order update failed request_id=%s user_id=%s reason=%s",
...
AI에게 "디버깅하기 쉬운 로그를 추가해줘"라고 요청하면, 요청 전체를 출력하는 코드가 생성될 수 있습니다. 리뷰에서는 로그 내용도 차이점(Diff)으로서 제대로 읽어야 합니다.
AI는 편리해 보이는 라이브러리를 추가할 때가 있습니다. 하지만 의존성(Dependency) 추가는 코드를 몇 줄 늘리는 것보다 영향이 더 클 수 있습니다. 유지보수 상태, 취약점(Vulnerability), 라이선스, 이행 의존성(Transitive Dependency), 빌드 시의 스크립트까지 영향을 미치기 때문입니다.
GitHub Dependabot alerts의 공식 문서에서는 취약한 의존성이 검출되면 Security and quality 탭이나 dependency graph에 알림이 표시된다고 설명합니다. 다만 모든 문제를 검출할 수 있는 것은 아니므로, manifest나 lock file을 최신 상태로 유지해야 합니다.
OWASP Top 10 2025에서도 Software Supply Chain Failures가 A03으로 추가되었습니다. 의존 라이브러리뿐만 아니라 빌드 시스템, 배포 경로, CI/CD, 외부 Action까지 포함하여 살펴볼 필요가 있습니다.
리뷰에서는 다음 파일들을 우선적으로 확인합니다.
| 파일 | 확인 사항 |
|---|---|
| package.json | 새로운 의존성, scripts 추가 |
| ... |
AI가 하나의 기능을 위해 거대한 의존성을 추가하는 경우, 그 의존성이 정말로 필요한지 확인합니다. 작은 처리라면 표준 라이브러리(Standard Library)로 충분할 수도 있습니다.
의존성은 취약점 유무뿐만 아니라 출처도 확인합니다. 외부 Action이 신뢰할 수 있는 제공처인지, 태그(Tag)뿐만 아니라 커밋 SHA로 고정해야 하는 상황은 아닌지, lock file의 차이점이 예상보다 크지는 않은지, postinstall
등의 스크립트가 추가되지 않았는지 확인합니다. GitHub Actions에서는 서드파티 Action을 전체 길이의 커밋 SHA (commit SHA)로 고정하는 것이, 변경되지 않는 릴리스로 취급하는 방법이라고 설명되어 있습니다.
릴리스 직후의 의존 관계를 즉시 도입하지 않는 설정도 확인합니다. npm에서는 min-release-age
, pnpm에서는 minimumReleaseAge
, Yarn에서는 npmMinimalAgeGate
와 같이, 일정 시간 이상 경과한 버전만을 해결(resolve) 및 설치하는 설정이 있습니다. Renovate의 minimumReleaseAge
와 같이, 의존 관계 업데이트 PR 생성을 일정 기간 늦추는 설정도 있습니다. 악성 패키지는 공개 직후에 탐지 및 삭제되는 경우가 있으므로, 업데이트를 조금 늦추는 것만으로도 공급망 공격 (Supply Chain Attack)의 직격을 피하기 쉬워집니다.
설치 스크립트 (install script)의 취급도 확인합니다. npm에는 ignore-scripts
가 있어, 패키지 설치 시 실행되는 스크립트를 중단할 수 있습니다. 다만, 일괄적으로 중단하면 정당한 빌드 처리까지 중단될 수 있습니다. 필요한 스크립트만 허용하고 싶은 경우에는 LavaMoat의 @lavamoat/allow-scripts
와 같이 패키지 단위로 허용 리스트를 만드는 외부 도구를 사용하는 방법이나, pnpm의 onlyBuiltDependencies
(pnpm 10 이후부터는 빌드 스크립트가 기본적으로 무효화됨)와 같이 빌드를 허용할 의존 대상을 명시하는 설정이 선택지가 됩니다.
SCA (Software Composition Analysis)는 애플리케이션이 이용하고 있는 OSS나 서드파티 의존 관계를 조사하여, 알려진 취약점 (known vulnerabilities), 라이선스, 오래된 의존 관계 등을 확인하기 위한 사고방식 및 도구군입니다. OWASP Dependency-Check도 의존 관계에 포함된 공개된 취약점을 검출하는 SCA 도구로서 설명되어 있습니다.
npm을 예로 들면, PR 시점에서 의존 관계 확인을 실행하는 것만으로도 상당히 차이가 납니다.
name: security-check
on:
pull_request:
...
이 예시에서는 npm audit
을 실행할 뿐이므로, GITHUB_TOKEN
에는 contents: read
만 부여하고 있습니다. SARIF를 Code Scanning으로 업로드하는 경우에는 security-events: write
가 필요하지만, 사용하지 않는 권한은 부여하지 않는 것이 안전합니다.
다만, npm audit
은 알려진 취약점 확인이 중심입니다. 공개 직후의 악성 패키지, 타이포스쿼팅 (typosquatting), 설치 스크립트의 악용, 유지보수 상황의 악화까지 모두 잡아낼 수 있는 것은 아닙니다. 실무에서는 lock file의 차이점, 릴리스 직후의 버전을 늦추는 설정, 설치 스크립트의 허용제, 의존 대상의 출처 확인도 함께 살펴봅니다.
더 자세한 GitHub와 npm의 방어 설정은 이전에 정리해 두었습니다. Dependabot, Dependency Review Action, npm audit, lock file 관리, ignore-scripts 등을 다루었습니다.
SCA 도구의 사용법을 영상으로 보고 싶다면, Kyohei 님의 영상을 매우 추천합니다. 과거 Shai-Hulud가 화제가 되었을 때, 감염 체크나 SCA 도구의 사용법을 해설해 주셨습니다.
영상 내에서는 Google의 OSV 사용법이나, 반대로 SCA 도구로는 제로데이 (zero-day) 및 미등록 악성 패키지를 검출할 수 없다는 점, pnpm의 minimumReleaseAge
(당시에는 아직 npm 측에 유사한 것이 없었음)와 같이 CVE나 OSV에 등록되기까지의 시간차를 이용하는 사고방식이 소개되어 있습니다. npm 주변에서는 Aikido Safe Chain과 같은 외부 도구나, ignore-scripts
를 통한 preinstall 계열 스크립트의 억제도 방어의 한 예로 다루어지고 있습니다.
(Kyohei 님의 영상은 개발자의 눈높이에서 이야기하므로 매우 이해하기 쉽고 쏙쏙 들어오기 때문에, 이 외의 영상들도 추천합니다)
AI 생성 코드 리뷰에서는 애플리케이션 코드뿐만 아니라, IaC와 CI/CD도 확인합니다.
예를 들어, 다음과 같은 변경 사항입니다.
| 변경 사항 | 확인 사항 |
|---|---|
| S3 버킷 | 퍼블릭 공개 여부, 암호화, 액세스 로그 |
| IAM 정책 | * 권한, 불필요한 관리 권한 |
| GitHub Actions | permissions, 외부 Action, secret 참조 |
| Dockerfile | root 실행, 불필요한 포트 공개 |
| Terraform | state에 비밀 정보가 포함되지 않는지 |
특히 공개 리포지토리(Public Repository)에서는 pull_request_target, 과도한 GITHUB_TOKEN 권한, PR 본문이나 Issue 본문을 그대로 run: 또는 AI 프롬프트(Prompt)로 전달하는 구성에 주의해야 합니다. CI/CD의 입력값도 사용자 입력과 마찬가지로 신뢰할 수 없는 값으로 취급합니다.
Wiz의 AI-DLC 기사에서도 AI 생성량에 맞춰 SAST, SCA, 시크릿(Secret), IaC 스캔을 PR이나 CI/CD에서 지속적으로 실행하는 중요성을 설명하고 있습니다.
AI가 생성한 IaC는 리소스를 생성할 수 있는지 여부뿐만 아니라, 생성된 리소스가 어떤 권한을 가지는지, 어디에 공개되는지, 어떤 데이터에 도달할 수 있는지까지 확인해야 합니다.
AI 생성 코드 리뷰에서는 코드 자체뿐만 아니라 AI 에이전트(AI Agent)에게 부여된 권한도 확인합니다. 이는 채팅형 코드 보완(Code Completion)만 사용한다면 그리 큰 문제가 되지 않지만, 최근의 AI 코딩 에이전트는 파일 편집, 명령 실행, Git 조작, MCP를 통한 외부 도구 호출까지 가능합니다.
AI 에이전트가 다음과 같은 조작을 할 수 있는 경우 특히 주의해야 합니다.
| 조작 | 리스크 |
|---|---|
git push | 의도하지 않은 변경 사항 반영 |
rm -rf | 파일 삭제 |
curl, wget | 외부 전송, 미지의 스크립트 취득 |
| DB 접속 | 데이터 유출, 데이터 파괴 |
| 클라우드 CLI | 운영(Production) 리소스 변경 |
AI 코딩 에이전트에게 위험한 명령을 실행하게 하는 흐름과 대책은 이전 별도 기사에서 정리하였습니다.
리뷰에서는 코드 차이(Diff)뿐만 아니라, 그 코드를 생성한 환경에서 어떤 권한이 사용되었는지도 신경 써야 합니다. 특히 운영 인증 정보를 읽을 수 있는 상태에서 AI 에이전트를 구동하고 있다면 매우 위험합니다.
MCP 서버를 사용하면 AI가 DB나 사내 도구를 호출할 수 있습니다. 편리하지만, 도구에 부여하는 권한을 잘못 설정하면 AI가 예상 이상의 조작을 할 수 있게 됩니다.
DB 검색용 MCP라면 읽기 전용으로 설정하기, SELECT만 허용하기, 접속 대상을 검증 환경으로 한정하기, 로그를 남기기 등의 설계가 필요합니다.
GitHub 문서에서도 GitHub Copilot agent mode나 MCP 호환 도구 중에서 secrets, 취약점, 안전하지 않은 의존성을 탐지하는 맥락이 설명되어 있습니다. AI 에이전트를 더 많이 사용할수록, 코드 생성 전후의 탐지를 개발 흐름(Workflow)에 포함하는 의미가 커집니다.
AI 에이전트에서는 코드 자체 외에도 리포지토리 내의 지시 파일, README, 외부 문서, Issue, PR 코멘트가 입력값이 됩니다. 여기에 악의적인 지시가 섞이면 AI가 본래의 개발 의도와 다른 명령을 실행하거나 비밀 정보를 읽어내려 할 가능성이 있습니다.
리뷰에서는 다음과 같은 변경 사항도 확인합니다.
| 대상 | 확인 사항 |
|---|---|
| AI용 지시 파일 | 위험한 명령 실행이나 비밀 정보 참조를 유도하고 있지 않은지 |
| ... |
프롬프트 인젝션(Prompt Injection)은 채팅 화면만의 문제가 아닙니다. AI가 읽을 수 있는 텍스트 전체가 입력값이 될 수 있으므로, AI에 전달하는 정보의 경계도 리뷰 대상에 포함해야 합니다. AI에 전달하는 외부 입력도 애플리케이션에서 다루는 외부 입력과 마찬가지로 신뢰 경계(Trust Boundary)로 취급합니다.
LLM 애플리케이션 맥락에서는 프롬프트 인젝션이나 과도한 권한을 가진 도구 연동도 주요 리스크로 다뤄지고 있습니다.
AI 생성 코드 리뷰는 코드만 읽는 작업이 아니라, "AI가 어떤 권한으로 무엇을 생성하고 어디에 반영하려고 하는가"를 보는 작업이 되어가고 있습니다.
AI 생성 코드는 정상 케이스(Happy Path)만 보면 깨끗해 보입니다.
하지만 보안 리뷰에서는 실패했을 때의 동작이 중요합니다.
예를 들어, 외부 API가 실패했을 때 인가(Authorization)를 건너뛰지는 않는지, DB 에러 시 상세한 SQL이나 내부 경로를 반환하지 않는지, 타임아웃 시 불완전한 상태가 남지 않는지 등을 확인합니다.
테스트에서는 정상 케이스뿐만 아니라 거부되어야 하는 케이스도 작성해야 합니다.
def test_other_user_cannot_read_order(client, user_a_token, user_b_order):
response = client.get(
f"/orders/{user_b_order.id}",
...
이 테스트는 타인의 주문을 읽을 수 없음을 확인하고 있습니다. AI에게 테스트를 작성하게 할 때도 '정상 케이스 (Happy Path)'뿐만 아니라, 거부되어야 하는 케이스를 명시해야 합니다.
이 API의 테스트를 작성해 주세요.
정상 케이스뿐만 아니라, 다른 사용자의 리소스에 접근했을 경우,
부정확한 입력을 전달했을 경우,
존재하지 않는 ID를 지정했을 경우를 포함해 주세요.
다음과 같은 케이스도 확인합니다.
| 케이스 | 확인할 내용 |
|---|---|
| DB 연결 실패 | 인가 (Authorization)를 스킵하지 않는가 |
| ... |
NIST SSDF에서는 소프트웨어를 안전하게 개발하기 위한 실천 사항을 SDLC (Software Development Life Cycle)에 통합하는 것을 권장하고 있습니다. AI 생성 코드에서도 리뷰와 테스트를 마지막 확인 단계가 아닌, 개발 흐름의 일부로 다루는 것이 현실적입니다.
AI 생성 코드가 포함된 PR (Pull Request)에서는 리뷰어가 '무엇을 AI에게 맡겼고, 무엇을 사람이 확인했는지'를 추적할 수 있으면 도움이 됩니다.
예를 들어, PR 본문에는 다음과 같은 정보를 남깁니다.
이 PR에서 AI에게 맡긴 범위
- API의 뼈대(Boilerplate) 생성
- 유효성 검사 (Validation) 처리의 초기 구현
...
AI 생성 코드 리뷰에서 중요한 것은 AI를 사용했다는 사실 자체를 숨기지 않는 것입니다. 출처를 남기고, 차분 (Diff)을 작게 유지하며, 테스트와 스캔 결과를 첨부하면 리뷰어가 코드의 의도를 파악하기 쉬워집니다.
개인적으로는 AI 생성 코드가 포함된 PR일수록 작게 나누어 올리는 것이 중요하다고 느낍니다. 생성량이 많으면 리뷰하는 입장에서 '무엇이 의도된 변경이고, 무엇이 부수적으로 변한 것인지' 파악하기 어려워지기 때문입니다.
PR에 남기는 정보가 거창한 감사 자료일 필요는 없습니다. 리뷰어가 판단에 사용할 수 있는 정보를 짧게 남길 수 있다면 충분합니다.
AI 생성 코드를 사람이 리뷰할 뿐만 아니라, AI에게 리뷰를 보조하게 하는 사례도 늘고 있습니다.
이는 편리하지만, AI 리뷰에도 한계가 있습니다. GitHub Copilot Code Review의 공식 문서에서는 간과, 오탐 (False Positive), 부정확하거나 안전하지 않은 코드 제안의 가능성을 설명하고 있습니다.
AI 리뷰를 사용할 경우에는 다음과 같이 역할을 나누는 것이 안전합니다.
AI는 리뷰의 입구로서 매우 편리합니다. 특히 차분이 큰 PR의 요약, 테스트 관점 도출, 전형적인 위험 패턴 지적에 적합합니다.
반면, '이 사용자가 이 작업을 수행해도 되는가', '이 로그는 운영상 필요한가', '이 의존성 (Dependency)을 채택해도 되는가'와 같은 판단은 시스템의 문맥을 알고 있는 사람이 확인해야 합니다.
마지막으로, AI 생성 코드가 포함된 PR에서 확인해야 할 항목을 정리합니다. 모든 항목을 매번 같은 깊이로 볼 필요는 없지만, 차분이 큰 PR일수록 이 순서대로 확인하면 누락을 줄이기 쉽습니다.
| 항목 | 확인할 내용 |
|---|---|
| 입력 (Input) | 사용자 입력, Webhook, URL 파라미터를 신뢰하고 있지는 않은가 |
| ... | permissions, 외부 Action, secrets, IaC 권한이 과도하지 않은가 |
| AI 에이전트 | 지시 파일, MCP, 외부 입력, 실행 권한을 확인했는가 |
| 테스트 | 정상 케이스뿐만 아니라, 거부되어야 하는 케이스를 작성했는가 |
AI가 생성한 코드는 겉모습의 자연스러움보다 '어디서 입력이 들어오고, 어떤 권한으로, 어떤 데이터에 도달하는가'를 추적하는 것이 더 중요합니다. PR의 차분을 읽을 때 이 흐름을 머릿속으로 따라가면 인가 누락(Authorization leak)이나 로그 누락을 발견하기 쉬워집니다.
여기까지 읽어주셔서 감사합니다.
AI 생성 코드의 보안 리뷰에서는 AI 특유의 특수한 실패만을 보는 것이 아니라, 평소에 발생하기 쉬운 취약성을 꼼꼼히 살펴보는 것이 중요합니다. AI가 작성한 코드든 사람이 작성한 코드든, 최종적으로 리뷰하는 대상은 결국 동일한 코드입니다.
AI는 개발 속도를 높여주지만, 머지 (Merge) 판단의 책임은 인간에게 남습니다. 그렇기에 AI를 사용할수록 리뷰의 형식을 갖추어 두는 것이 가치 있습니다. 관점을 알고 있는 것만으로도 큰 차이가 나니까요.
그럼 다음에 또 뵙겠습니다.
-
GitHub Copilot 코드 리뷰의 책임 있는 사용 - GitHub Docs
-
코드 스캔에서의 Copilot 자동 수정의 책임 있는 사용 - GitHub Docs
-
GitHub Copilot 클라우드 에이전트의 리스크 및 완화 방안 - GitHub Docs
-
AI 코딩 에이전트에서 GitHub Advanced Security 사용하기 - GitHub Docs
-
OWASP Top 10 for Large Language Model Applications - OWASP
-
OWASP Top 10 2025 - OWASP
-
A03 Software Supply Chain Failures - OWASP Top 10 2025
-
2025 CWE Top 25 Most Dangerous Software Weaknesses - MITRE
-
Secure Software Development Framework SP 800-218 - NIST
-
Dependabot 알림에 대하여 - GitHub Docs
-
보안이 확보된 사용에 관한 레퍼런스 - GitHub Docs
-
코드 스캔의 워크플로 구성 옵션 - GitHub Docs
-
Releases actions/checkout - GitHub
-
Releases actions/setup-node - GitHub
-
Node.js 릴리스 - Node.js
-
OWASP Dependency-Check - OWASP
-
GitHub Action - OSV-Scanner
-
Aikido Safe Chain - Aikido
-
Config - npm Docs
-
Mitigating supply chain attacks - pnpm
-
Settings .yarnrc.yml - Yarn
-
Security Presets - Renovate Docs
-
State of SDLC Security 2026 - Wiz
-
AI-DLC란 무엇인가 - Wiz
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기