AI가 생성한 requirements.txt와 취약한 패키지들
요약
AI 코딩 어시스턴트가 생성하는 requirements.txt가 학습 데이터의 시점 차이로 인해 취약한 패키지 버전을 포함할 위험을 경고합니다. 이는 설치나 임포트에는 문제가 없으나 보안 감사 전까지 발견하기 어려운 '취약한 버전 문제'를 야기합니다.
핵심 포인트
- AI는 실시간 PyPI 데이터가 아닌 학습 데이터 기반의 구버전 패키지를 권장함
- 권장된 버전은 설치와 임포트가 정상 작동하여 보안 위협을 식별하기 어려움
- 슬롭스쿼팅(Slopsquatting)과 달리 취약한 버전 문제는 감사가 실행되기 전까지 눈에 띄지 않음
- cryptography, Pillow 등 보안 패치가 빈번한 패키지에서 위험성이 높음
AI 코딩 어시스턴트(AI coding assistants)는 실시간 PyPI 인덱스가 아닌 학습 데이터로부터 requirements.txt 항목을 작성합니다. 이들이 고정하는 버전은 학습 코퍼스(training corpus)에서 가장 흔했던 버전이며, 이는 일반적으로 모델의 학습 중단 시점(training cutoff)으로부터 12~24개월 전의 버전입니다. 여러분의 팀이 해당 의존성(dependencies)을 설치할 때쯤이면, 일부는 문서화된 취약점(vulnerabilities)을 포함하고 있을 수 있습니다. 패키지 이름은 정확합니다. 설치도 성공합니다. 감사가 실행되기 전까지는 아무것도 이를 감지하지 못합니다.
이는 AI가 PyPI에 존재하지 않는 패키지 이름을 환각(hallucinates)하거나, 공격자가 등록한 타이포스쿼팅(typosquat) 패키지 이름을 만들어내는 슬롭스쿼팅(slopsquatting)과는 구별되는 문제입니다. 슬롭스쿼팅은 설치가 실패하는 즉시 눈에 띕니다. 반면, 취약한 버전 문제(vulnerable-version problem)는 기본적으로 눈에 보이지 않은 상태로 유지됩니다.
AI가 패키지 버전을 선택하는 방식
AI 코딩 어시스턴트는 실시간 PyPI 인덱스가 아닌 학습 데이터로부터 requirements.txt 항목을 생성합니다. 즉, 학습 과정에서 가장 흔하게 보았던 버전을 작성하는데, 이는 종종 모델의 학습 중단 시점으로부터 12~24개월 전에 유행했던 버전인 경우가 많으며, 그 이후에 문서화된 알려진 취약점(known vulnerabilities)을 가지고 있을 수 있습니다. BrassCoders의 AI 패턴 스캐너(AI-pattern scanner)는 PyPI에 존재하지 않는 패키지인 팬텀 임포트(phantom imports)는 잡아내지만, 취약한 버전의 실제 패키지는 깔끔하게 설치되며 모든 임포트(import) 검사를 통과합니다.
모델들은 고정된 중단 날짜를 가진 코드 스냅샷(code snapshots)을 바탕으로 학습됩니다. 여러분이 Flask 앱의 스캐폴딩(scaffold)을 요청하면, AI는 오늘 아침 PyPI에 쿼리(query)를 날렸기 때문이 아니라, 학습 윈도우(training window) 내의 수천 개 GitHub 저장소에 해당 버전이 등장했기 때문에 Flask==2.3.2라고 작성합니다. 동일한 패턴이 requests, cryptography, Pillow에도 적용됩니다. 활발한 CVE 이력이 있는 모든 의존성은 잠재적인 대상이 됩니다.
이 격차는 빈번한 보안 패치를 제공하는 패키지에서 가장 중요하게 작용합니다. cryptography는 연간 여러 차례 CVE를 공개합니다. Pillow는 릴리스 이력 전반에 걸쳐 20개 이상의 CVE가 누적되었습니다. 만약 AI가 cryptography==41.0.3을 권장하고 현재 릴리스가 그 사이 여러 보안 수정 사항이 포함된 43.x 버전이라면, 여러분의 환경은 첫날부터 알려진 취약점이 있는 코드를 실행하게 됩니다.
설치는 실패하지 않습니다. 임포트 (import)도 작동합니다. 테스트도 통과합니다. 바로 이 점 때문에 이 범주의 위험을 놓치기가 매우 쉽습니다.
실제 패키지, 취약한 버전: 별개의 위협
BrassCoders의 AI 패턴 스캐너는 존재하지 않는 패키지인 팬텀 임포트 (phantom imports)를 잡아내지만, 취약한 버전의 실제 패키지는 모든 임포트 체크를 통과하며 깔끔하게 설치됩니다. 취약점은 명시적인 의존성 감사 (dependency audit)를 실행하기 전까지는 보이지 않습니다.
슬롭스쿼팅 (Slopsquatting)은 극적인 요소 때문에 가장 많은 관심을 받습니다. AI가 패키지 이름을 지어내면, 공격자가 해당 이름을 악성 코드가 담긴 채 PyPI에 등록하고, AI의 지침을 따르는 다음 개발자가 공격 페이로드 (payload)를 실행하게 되는 방식입니다. 이러한 공급망 (supply-chain) 관점은 보안 뉴스에서 다루기에 매우 매력적인 소재입니다.
취약한 버전 패턴은 더 조용하지만 훨씬 더 광범위한 클래스의 패키지에 영향을 미칩니다. CVE 이력이 있는 모든 패키지가 대상이 될 수 있습니다. 패키지는 깨끗한 평판을 가진 채 PyPI에 존재하며, AI가 고정한 버전은 AI가 학습되었을 당시에는 안전했을 수 있지만, 표준 개발 워크플로우의 그 어떤 것도 이 격차를 드러내지 않습니다.
Python Packaging Authority에서 관리하는 PyPI Advisory Database는 특정 패키지 버전에 대한 알려진 취약점을 추적합니다. pip-audit는 단 몇 초 만에 이를 조회합니다. 여러분의 AI 어시스턴트는 자신의 학습 중단 시점 (training cutoff) 이후에 발표된 CVE에 대해서는 들어본 적이 없습니다.
AI가 틀리는 체크 프로세스 자동화
PyPA의 공식 의존성 감사 도구인 pip-audit는 몇 초 만에 requirements.txt를 PyPI Advisory Database 및 GitHub Advisory Database와 대조합니다. 이는 AI 어시스턴트가 놓치는 부분을 실시간 취약점 인덱스(vulnerability index)를 기반으로 실행함으로써 잡아냅니다. BrassCoders와 pip-audit는 서로 다른 계층을 다루며, 둘 다 CI(지속적 통합)에 포함되어야 합니다.
pip-audit은 설치 및 실행이 간단합니다:
pip install pip-audit
pip-audit
pip install -r requirements.txt를 실행한 후에 이를 실행하여 실제로 설치된 항목을 스캔하도록 하세요. 인증은 필요하지 않습니다. API 키도 필요 없습니다. pip-audit는 취약점이 발견되면 종료 코드(exit code) 1로 종료되므로, CI 빌드를 실패하도록 구성하는 것이 매우 쉽습니다. 실패 시 CVE ID, 영향을 받는 버전, 수정된 버전, 그리고 심각도 점수(severity score)가 나타나며, 이는 발견된 문제를 1분 이내에 분류(triage)하는 데 필요한 모든 정보를 제공합니다.
pip-audit가 다루지 못하는 한 가지가 있습니다. 바로 팀이 직접 작성한 코드 내의 보안 버그입니다. 하드코딩된 자격 증명(hardcoded credentials), 안전하지 않은 서브프로세스 호출(unsafe subprocess calls), SQL 인젝션(SQL injection) 패턴 등은 여러분의 자체 모듈 내에 존재하는 코드 계층(code-layer)의 리스크입니다. 바로 이 지점에서 BrassCoders가 역할을 이어받습니다.
의존성 감사 스택에서 BrassCoders의 위치
BrassCoders는 CI에서 실행되며 여러분이 작성한 패키지 내의 코드 계층 보안 버그(SQL 인젝션, 하드코딩된 자격 증명, 안전하지 않은 서브프로세스 호출 등)를 잡아냅니다. pip-audit는 의존성 매니페스트(dependency manifest)를 대상으로 실행되어 가져온(import) 패키지 내의 알려진 취약점을 잡아냅니다. 두 도구 모두 동일한 CI 파이프라인에 포함되어야 합니다.
BrassCoders는 소스 코드에 대해 12개의 정적 분석 스캐너(static-analysis scanners)를 실행합니다: Bandit, Pylint, Pyre/Pysa, Semgrep, ast-grep, detect-secrets, 그리고 6개의 커스텀 탐지기(custom detectors)입니다. AI-coder 버그 벤치마크에 따르면, 재현 가능한 코퍼스(corpus) 내에서 Bandit이 12개 중 6개의 AI 생성 버그를 잡아낸 것에 비해, BrassCoders는 12개 중 11개를 잡아냈습니다. 이러한 커버리지는 의존성 매니페스트가 아닌 여러분의 코드를 대상으로 합니다.
6개의 커스텀 탐지기(custom detectors)는 비밀 패턴(secret patterns), 개인정보(PII)/프라이버시 리스크, AI가 생성한 유령 임포트(phantom imports), 성능 안티 패턴(performance anti-patterns), 콘텐츠 모더레이션(content-moderation) 리스크, 그리고 JavaScript/TypeScript에 대한 커버리지를 추가합니다. 이들은 상위 스캐너(upstream scanners)와 동일한 로컬 머신에서 실행되며, 오픈 소스(OSS) 코어에서는 외부 네트워크 호출을 수행하지 않습니다.
OSS 코어는 무료(Apache 2.0)이며 다음과 같이 설치할 수 있습니다:
pip install brasscoders
brasscoders scan .
개발자당 월 12달러인 BrassCoders Paid 버전은 탐지 결과의 중복을 제거하고 프로젝트별 관련성에 따라 순위를 매기는 AI 기반 강화 패스(AI-powered enrichment pass)를 추가합니다. 이 버전은 이미 비식별화(redacted)된 탐지 결과와 프로젝트 시그니처(project signature)만을 게이트웨이로 전송하며, 원본 소스 코드는 절대 전송하지 않습니다.
두 도구를 동일한 CI 작업(CI job)에서 함께 사용하십시오. pip-audit는 AI가 고정한 오래되고 취약한 의존성(dependency)을 잡아냅니다. BrassCoders는 AI가 라우트 핸들러(route handler)에 작성한 SQL 인젝션(SQL injection)을 잡아냅니다. 어느 하나가 다른 하나를 대체하는 것이 아닙니다.
pip install brasscoders를 실행하십시오. 그 직후 pip install -r requirements.txt 다음에 pip-audit를 추가하십시오. 이 두 도구를 통해 코드 계층의 버그와 의존성 계층의 CVE(Common Vulnerabilities and Exposures)를 모두 커버할 수 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기