본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 07. 21:54

AI 생성 코드에서 정책 게이트가 잡아내는 것과 놓치는 것

요약

오픈 소스 도구 vorsken을 활용하여 AI 생성 코드의 보안 정책 준수 여부를 테스트한 결과입니다. ChatGPT, Claude Code, Cursor 등 주요 AI 도구들이 생성한 코드의 보안 취약점을 분석하여, 전통적인 작업에서의 안정성과 프레임워크 사용 시 발생하는 잠재적 위험을 다룹니다.

핵심 포인트

  • 전통적인 CRUD 및 SQL 작업에서 AI 모델의 보안 성능은 양호함
  • LangChain 등 특정 프레임워크 사용 시 에이전트의 권한 범위 문제 발생 가능성
  • 보안 플러그인 및 환경 변수 활용이 코드 안전성에 기여함
  • AI 생성 코드에 대한 정적 분석 도구(Semgrep 등)의 실질적 효용성 확인

저는 vorsken이라는 오픈 소스 GitHub Action을 관리하고 있습니다. 이 도구는 한 가지 일만 수행합니다. Semgrep을 사용하여 Pull Request (PR)의 diff를 스캔하고, 고정된 정책을 적용한 뒤, BLOCK, FLAG 또는 PASS를 반환합니다. 대시보드도 없고, 시간이 지남에 따라 성능이 변하는 모델도 없습니다. ERROR/HIGH/CRITICAL 심각도(severity)의 규칙은 머지(merge)를 차단하고, WARNING/MEDIUM은 플래그(flag)를 지정하며, 나머지는 통과(pass)시킵니다. 동일한 diff에는 항상 동일한 판결이 내려집니다.

이러한 도구에 대한 일반적인 홍보 문구는 AI 어시스턴트가 작성한 SQL 인젝션 (SQL injection)을 잡아낸다는 것입니다. 저는 실제 어시스턴트의 출력물에 대해 이 도구가 실제로 무엇을 잡아내는지 확인하고 싶었습니다. 그래서 28개의 함수를 생성하여 테스트를 진행했습니다.

테스트

일곱 가지 백엔드 작업: FastAPI 업로드 엔드포인트, URL fetch 헬퍼, JWT 인증, SQL 필터, ImageMagick 서브프로세스 호출, LangChain 파일 에이전트, 그리고 LangChain RAG 파이프라인입니다. 저는 각 작업을 네 번씩 생성했습니다. ChatGPT (GPT-5.5 Instant), Claude Code (Opus 4.8), 보안 가이드 플러그인이 추가된 Claude Code, 그리고 Cursor (Composer 2.5)를 사용했습니다. 단발성(Single-shot)의 중립적인 프롬프트를 사용했으며, 보안 힌트는 주지 않았습니다. 그 후 동일한 규칙 세트로 28개 모두를 스캔했습니다.

저는 특정 모델이 코드를 안전하다고 생각하는지 여부가 아니라, 어떤 파일에서 어떤 규칙이 실행되었는지를 보고합니다. 그 부분은 직접 재현해 보실 수 있습니다.

작업ChatGPTClaude Code+ 플러그인Cursor판결
파일 업로드PASS
...
28개 함수 전체에서 7개 BLOCK, 3개 FLAG, 18개 PASS가 나왔습니다.

기본 사항은 괜찮았습니다

SQL 필터, ImageMagick, 파일 업로드: 모든 도구에서 깨끗하게 통과되었습니다. SQL은 매개변수화(parameterized)되었고, 서브프로세스(subprocess) 호출은 셸 문자열(shell strings) 대신 인자 리스트(argument lists)를 전달했으며, 업로드는 무모한 동작을 수행하지 않았습니다. 만약 여러분이 여전히 현재의 모델들이 단순한 CRUD 작업에서 SQL 인젝션을 마구 뿌려댈 것이라고 기대한다면, 그렇지 않습니다. 전통적인 작업에 대해서는 모델들이 제대로 수행합니다.

두 가지 플래그는 소프트(soft)합니다. JWT api8 히트(hits)는 SECRET_KEY = "CHANGE_ME" 플레이스홀더(placeholder)에서 발생했는데, 이를 오탐(false positive)으로 볼 수도 있고 게이트(gate)가 제 역할을 수행한 것으로 볼 수도 있습니다. 나머지 두 설정은 해당 과업을 통과했습니다. 하나는 플러그인이 생성 과정에서 비밀키를 제거했고, 다른 하나는 Cursor가 이를 환경 변수(environment variable)에서 읽어왔기 때문입니다. SSRF 플래그에 대해서는 나중에 다시 다루겠습니다.

이야기할 가치가 있는 두 가지 발견 사항은 모두 프레임워크 코드 내에 있었으며, 이는 두 가지 서로 다른 종류의 문제입니다.

발견 1: 파일 시스템을 마음대로 휘젓는 에이전트

파일 에이전트(file-agent) 작업은 LangChain의 FileManagementToolkit을 사용합니다. 여기에 root_dir과 짧은 selected_tools 리스트를 전달하면, 선택한 작업 범위 내에서 하나의 디렉토리에 고정됩니다. 이를 생략하면 에이전트는 삭제(delete)를 포함한 모든 작업에 대해 전체 파일 시스템(filesystem)에 접근할 수 있게 됩니다.

네 가지 설정 중 세 가지는 범위를 제한(scoped)했습니다. 하지만 Claude Code는 제한하지 않았고, 게이트의 overpermissioned-agent-tool 규칙이 이를 차단했습니다. 이는 네 가지 도구 중 하나일 뿐이므로, 이것이 "에이전트 방식의 코드(agentic code)가 위험하다"는 증거는 아니며, 저 또한 그런 식으로 주장하지는 않을 것입니다. 하지만 범위를 제한한 버전은 인자(argument)를 하나 더 추가해야 하는 비용이 발생하는 반면, 제한되지 않은 버전은 기본값(default)으로 제공됩니다. 이러한 비대칭성이 바로 게이트를 설치해야 하는 이유입니다.

발견 2: 피할 수 없는 위험한 플래그

RAG 작업은 로컬 FAISS 인덱스(index)를 로드합니다. 네 가지 설정 모두 allow_dangerous_deserialization=True를 작성했으며, 네 가지 모두 차단되었습니다.

이는 에이전트 사례와는 다릅니다. 이 플래그는 실수가 아닙니다. FAISS는 이 플래그 없이는 로컬 인덱스를 로드할 수 없으며, 내부적으로 pickle을 사용하기 때문에 역직렬화(deserialization)는 실제로 안전하지 않습니다. 게이트는 해당 인덱스가 사용자가 직접 만든 빌드 산출물(build artifact)인지, 아니면 공격자가 디렉토리에 떨어뜨려 놓은 것인지 구분할 수 없습니다. 따라서 게이트는 머지(merge) 단계에서 중단하여 누군가가 그 질문에 답하도록 강제합니다. 즉, 인덱스를 신뢰하기 때문에 유지할 것인지, 아니면 코드 실행 경로(code-execution path)가 아닌 다른 포맷으로 옮길 것인지 결정하게 만듭니다. 게이트가 결정을 내리는 것이 아닙니다. 게이트는 당신이 그 결정을 공개적으로 내리도록 만듭니다.

놓치는 부분

이제 SSRF (Server-Side Request Forgery) 플래그를 보겠습니다. 세 가지 설정은 requests를 사용했고, ssrf-via-requests 규칙이 이를 잡아냈습니다. Cursor는 해당 규칙이 다루지 않는 httpx를 사용했기 때문에 통과되었습니다. Cursor의 코드가 더 안전한 것은 아닙니다. 검증되지 않은 URL에 대해 follow_redirects=True를 설정하고 있으며, 이는 다른 코드들과 동일한 노출 위험을 가집니다. 단지 규칙에 구멍이 있을 뿐입니다. 이 게이트를 통과했다는 것은 어떤 규칙도 일치하지 않았음을 의미하며, 이것이 곧 안전함을 의미하는 것은 아닙니다.

업로드 작업도 비슷합니다. 아직 경로 탐색 (Path-traversal) 규칙이 없기 때문에, 해당 PASS (통과)는 부분적으로 게이트가 확인하지 않았기 때문입니다. 그리고 SSRF가 실제로 탐지될 때도, 정밀한 탐지라기보다는 투박한 구문적 (Syntactic) 플래그에 가깝습니다. 이것이 순수 구문 기반 게이트의 한계이며, 해당 리포지토리 (Repo)에 명시되어 있습니다.

이것이 이러한 게이트가 감수하는 트레이드오프 (Trade-off)입니다. 이 게이트는 영리하지 않으며 영리해지려고 노력하지도 않습니다. 모든 PR (Pull Request)에서 실행되며, 어떤 도구가 코드를 작성했는지 또는 당시 린터 (Linter)가 실행 중이었는지 여부는 상관하지 않습니다. 플러그인 설정이 게이트가 확인하기 전에 하드코딩된 비밀 값을 수정했는데, 이는 괜찮지만 해당 플러그인이 모든 리포지토리나 모든 머신에 있는 것은 아니며 기록도 남기지 않습니다. 세션 내 도구 (In-session tools)는 1차 검사입니다. 머지 게이트 (Merge gate)는 항상 그 자리에 있으며 모두에게 동일하게 적용되는 부분입니다.

내가 얻은 교훈

모델들은 직접적인 작업에서 보안 능력이 나쁘지 않습니다. 문제는 한 단계 위에서 나타났습니다. 즉, 프레임워크의 기본값 (Defaults)과 코드 스스로는 내릴 수 없는 신뢰 결정 (Trust decision)에서 문제가 발생했습니다. 이러한 것들이 바로 차이점 (Diff)을 누가 또는 무엇이 작성했든 상관없이, 머지 단계에서 결정론적으로 (Deterministically) 차단할 가치가 있는 것들입니다.

vorsken은 MIT 라이선스이며 규칙들은 리포지토리에 포함되어 있으므로, 여러분의 출력물에 대해서도 동일한 스캔을 실행할 수 있습니다.

vorsken on GitHub

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0