요약
- AI 어시스턴트는 세 가지 뚜렷한 방향으로 의존성 버전을 잘못 선택합니다: 학습 차단 시점 이후 공개된 모든 취약점을 포함하는 구식 버전, 아직 누구도 검증하지 못한 너무 최신인 최첨단(bleeding-edge) 릴리스, 그리고 아예 출판되지 않은 버전입니다.
- Sonatype의 연구에 따르면 약 37,000개의 의존성 업그레이드 권장 사항에서 27.76%의 환각률이 발견되었으며, 그중 10,000개 이상은 어떤 레지스트리에도 존재하지 않는 패키지 버전을 가리켰습니다.
AGENTS.md나 IDE 규칙 파일에 의존성 규칙을 작성하는 것은 수동으로 유지 관리해야 하는 문서가 되며, 이 문서는 조용히 구식이 되고 실제로 에이전트(agent)가 이를 따랐는지 확인할 방법도 제공하지 않습니다.
- AI 생성 코드는 풀 리퀘스트당 검토 시간보다 빠르게 증가하고 있으며, 버전 문자열은 diff에서 건너뛰기 가장 쉬운 세부 정보 중 하나입니다.
- 신뢰할 수 있는 강제 적용(enforcement)은 두 번 실행되어야 합니다: 첫째는 풀 리퀘스트 단계에서의 품질 게이트(quality gate)로서, 그리고 둘째는 병합 후 공개된 취약점에 대해 모든 저장소를 재점검하는 야간 스케줄링에서입니다.
AI 코딩 어시스턴트 의존성 버전 선택 위험이란 GitHub Copilot, Cursor, Claude Code와 같은 도구들이 라이브러리 버전을 구식으로, 며칠 내에 출판된 것으로, 또는 완전히 허구적인 것으로 선택하는 패턴을 의미합니다.
소프트웨어 역사 대부분 동안, 의존성 버전을 선택하는 것은 판단력이 필요한 결정이었습니다. 개발자는 팀이 표준화한 내부 라이브러리 버전이 무엇인지 알고 있었고, 마지막 업그레이드 시도가 왜 롤백되었는지 기억했으며, 보안 패치와 깨지는 변경(breaking change)의 위험을 저울질할 수 있었습니다.
그러한 맥락은 누군가의 머릿속에 존재했거나, 기껏해야 아무도 꾸준히 읽지 않는 위키 페이지에 존재했습니다. AI 코딩 어시스턴트가 점차 의존성 선택 결정을 신중한 인간의 선택보다는 권장 사항으로 내리면서, 그 결과는 예전에는 수반되던 판단력 없이 여러분의 의존성 매니페스트(dependency manifest)에 놓이게 됩니다.
이제 어떤 종속성(dependency) 버전이 코드베이스에 포함될지 누가 결정할까요?
과거에는 개발자가 팀의 내부 표준과 업그레이드 위험을 저울질하며 의도적으로 종속성 버전을 선택했습니다.
하지만 AI 코딩 어시스턴트가 이제 그 버전을 제안하고, 개발자는 코드가 컴파일되고 기능이 작동하기 때문에 보통 두 번 생각하지 않고 이를 수용합니다.
모델의 제안이라는 이 단 한 번의 대체(substitution)는 아래 설명된 모든 위험의 근원이 되며, 어시스턴트가 import 구문을 작성하는 순간 무엇을 최적화하고 있느냐에 따라 세 가지 뚜렷한 실패 모드로 나타납니다.
AI 코딩 어시스턴트는 왜 구식 종속성 버전(stale dependency versions)을 기본값으로 사용할까요?
AI 코딩 어시스턴트가 구식 버전을 기본값으로 사용하는 이유는 학습 데이터가 현재 버전이나 가장 안전한 버전보다는 모델이 훈련될 당시 가장 광범위하게 문서화된 라이브러리 버전에 치우쳐 있기 때문입니다.
대규모 언어 모델(Large language models)은 기본적으로 실시간 레지스트리 데이터를 가져오지 않습니다. 대신, 학습한 코드와 문서에서 가장 자주 나타난 버전 문자열을 생성하는데, 이는 거의 항상 더 오래 존재하여 튜토리얼, Stack Overflow 답변, GitHub 예제 등이 더 많이 축적된 구형 릴리스이기 때문입니다.
구식 버전은 깨끗하게 설치되고 빌드를 통과하며 컴파일러가 중요하다고 여기는 모든 면에서 올바르게 보일 수 있습니다. 하지만 이 버전은 또한 해당 릴리스가 출시된 날부터 공개된 취약점을 유지할 수도 있으며, 이는 자체 전이적 종속성(transitive dependencies)을 통해 상속받는 위험을 포함합니다.
만약 모델의 학습 차단 시점(training cutoff)이 중요한 CVE(Common Vulnerabilities and Exposures)보다 앞선다면, 어시스턴트는 방금 추천한 버전이 이미 플래그가 지정되었다는 것을 알 방법이 없으며, 확인하지 않고 제안을 수락한 개발자 역시 마찬가지입니다.
만약 AI 어시스턴트가 대신 최신 버전(newest release)으로 기울어지면 어떻게 될까요?
오래된 의존성 수정 요청을 받으면, AI 코딩 어시스턴트는 과도하게 교정하여 가장 최근에 게시된 버전(때로는 며칠밖에 안 된)으로 바로 건너뛰는 경향이 있습니다. 해당 버전은 실제 사용, 버그 보고서, 생태계 검토를 할 시간이 부족합니다.
여기서 위험은 현실적입니다. 공격자가 인기 있는 패키지를 손상시킬 때, 악성 버전은 포착되어 제거되기까지 일반적으로 짧은 시간만 살아남습니다.
최근 널리 사용되는 axios 라이브러리의 손상된 릴리스와 관련된 사건에서, Huntress의 연구원들은 해당 악성 axios 버전이 게시된 지 약 3시간 이내에 제거되었으며, 그 짧은 시간 동안에도 공격자 인프라로 연결하려는 100개 이상의 엔드포인트를 기록했다고 보고했습니다.
본능적으로 가장 최신 버전을 선택하는 어시스턴트는 프로젝트를 해당 노출 창(exposure window)으로 직접 안내할 수 있으며, 생태계가 문제가 있다는 것을 알아차릴 기회도 없이 버전을 설치하게 만듭니다.
AI 코딩 어시스턴트가 존재하지 않는 버전을 추천할 수 있을까요?
네, 그리고 이는 너무 자주 발생하여 이름이 붙었습니다. 바로 '패키지 환각(package hallucination)'입니다. 여기서 어시스턴트는 레지스트리에 한 번도 게시된 적 없는 버전 번호를 생성합니다. 이것은 구식화나 성급함과는 다릅니다. 단순히 존재하지 않는 버전이며, 모델이 훈련 중에 학습한 실제 버전 문자열 패턴과 유사하기 때문에 만들어낸 것입니다.
Sonatype의 '2026년 소프트웨어 공급망 현황(State of the Software Supply Chain)' 연구에 따르면, Sonatype은 36,870개의 실제 의존성 업그레이드 권장 사항을 분석했으며, 이 중 [27.76%가 존재하지 않는 버전을 참조]하는 것을 발견했고, 여기에는 10,000개 이상의 환각 패키지 릴리스가 포함되었습니다.
환각된 버전은 누군가 설치를 시도하는 순간 빌드를 망가뜨리지만, 더 위험한 시나리오는 공격자가 그 패턴을 감지하고 AI 어시스턴트가 환각할 가능성이 높은 정확한 이름과 버전으로 사전에 패키지를 게시하여, 단순한 빌드 실패를 공급망 위협(supply chain compromise)으로 변질시키는 경우입니다.
AGENTS.md 파일에 규칙을 작성하는 것이 왜 이 문제를 해결하지 못할까요?
AGENTS.md나 IDE 규칙 파일은 의도만 문서화할 뿐이므로, 어시스턴트가 그 규칙을 따랐는지 여부를 검증해주지 못하며, 심지어 해당 문서 자체가 구식이 되었음을 알리는 기능도 할 수 없습니다.
코드를 생성하기 전에 어시스턴트가 읽는 파일에 조직의 규칙을 작성하여 이 문제를 해결하려는 본능은 합리적이지만, 이는 단지 하나의 사각지대를 다른 사각지대로 대체할 뿐입니다.
어시스턴트의 훈련 데이터가 아무리 좋아도 알 수 없는 것부터 시작해야 합니다. 바로 귀사 조직 자체의 라이브러리에 대한 내부 결정 사항들입니다. 현재 승인된 내부 인증(auth) 라이브러리의 버전은 무엇이며, 지난 분기 어떤 사고로 인해 폐기되었는지에 대한 정보는 공개 훈련 데이터 어디에도 존재하지 않으며, 인터넷에서 스캐너가 추론해낼 수 있는 것도 없습니다.
팀들은 이 격차를 메우기 위해 "내부 인증 라이브러리 버전 4를 사용하라"와 같이 규칙을 직접 문서화하고, 매 세션마다 어시스턴트에게 해당 파일을 참조하도록 지시합니다.
문제는 이 파일이 원래 대체하려 했던 위키 페이지와 정확히 같은 방식으로 작동한다는 것입니다. 만약 버전 4가 3월에 보안 패치를 배포했고 버전 3이 공식적으로 폐기되었다면, 지침 파일은 누군가 업데이트할 것을 기억해야만 그 변화를 반영하며, 시스템의 어떤 부분도 이 정보가 잘못되었음을 경고해주지 않습니다.
이것을 동일한 규칙 파일을 가진 스무 개의 저장소에 곱하면, 하나의 공유된 진실 공급원(shared source of truth) 대신 스무 개의 독립적인 실패 지점을 갖게 됩니다.
34,000개 이상의 저장소에 대한 조사를 통해 이러한 패턴이 확인되었습니다. 4개 중 1개의 조직에서 AI 에이전트 설정 파일에 공백(gap)이 발견되었습니다. 더욱 심각한 것은, 완벽하게 최신화된 규칙 파일조차도 규정 준수(compliance)를 보장하지 못한다는 점입니다. 어시스턴트는 지침을 읽고도 이를 무시하는 코드를 생성할 수 있는데, 이는 정책을 실행하는 결정론적 시스템이 아니라 통계적 패턴을 따르는 확률적 시스템이기 때문입니다.
확률적 규정 준수는 곧 규정 준수가 아니며, 규제 기관이나 보안 담당자가 모든 커밋에서 해당 규칙이 실제로 지켜졌는지 물었을 때 감사(audit)할 수 없습니다.
지침은 어시스턴트가 할 가능성이 높은 것을 형성합니다. 하지만 그것이 반드시 해야 하는 것을 강제하지는 못하며, 이 구분이 바로 이미 신중한 규칙 파일을 작성한 팀에서도 이러한 위험 범주가 살아남는 전체 이유입니다.
왜 위험한 의존성 버전이 풀 리퀘스트 검토를 통과하는가?
위험한 의존성 버전은 각 풀 리퀘스트에 도착하는 AI 생성 코드의 양이 검토자들이 평가하는 시간보다 빠르게 증가했기 때문에 검토 단계를 통과합니다. Stack Overflow의 2025년 개발자 설문조사에 따르면, [개발자의 66%가 거의 맞았지만 수정해야 하는] AI 생성 코드를 고치는 데 더 많은 시간을 할애하고 있는 것으로 나타났습니다.
패키지 매니페스트(package manifest)에 숨겨진 버전 증가는 디프(diff)에서 가장 쉽게 건너뛰어 지나칠 수 있는 줄 중 하나이며, 특히 주변 코드가 깔끔해 보이고 빌드까지 통과하면 더욱 그렇습니다.
이는 AI 지원 개발이 악화시킨 작업 부하 불균형을 반영하는 것이며, 엔지니어링 팀 전반에 걸쳐 코드 검토의 압박이 실제로 어떻게 작용하고 있는지 이해하려면 이 역동성을 더 깊이 이해할 가치가 있습니다.
이번 주 저장소에서 무엇을 확인해야 하는가?
이를 어떻게 해결할지 결정하기 전에, 현재 여러분의 저장소가 얼마나 노출되어 있는지 아는 것이 도움이 됩니다. 짧은 내부 감사(internal audit)만으로 이 질문에 답할 수 있으며 새로운 도구링(tooling)이 필요하지 않습니다.
- 지난달에 병합된 의존성 버전 변경 사항은 몇 건이며, 그중 기능 활성화가 아닌 버전 선택 자체에 대한 인간의 코멘트를 포함한 것은 몇 건입니까?
- 지난 90일 동안 추가된 의존성 중 현재 릴리스보다 두 개 이상의 메이저 버전 뒤처진 것은 몇 건입니까?
- 병합된 의존성 중 현재 알려진 취약점이 있는 것이 무엇인지 알고 계십니까, 아니면 누군가 스캔을 실행해야 알 수 있습니까?
- 취약한 의존성이 오늘 실제로 풀 리퀘스트(pull request)를 실패시킬 수 있습니까, 아니면 아무도 조치할 필요가 없는 경고만 발생시키나요?
- 그 게이트(gate)는 모든 리포지토리(repository)에 동일하게 구성되어 있습니까, 아니면 우연히 신중하게 설정한 소수의 경우에만 그렇습니까?
의존성 버전 확인은 실제로 어느 단계에서 이루어져야 하는가?
의존성 버전 확인은 두 번 실행되어야 합니다. 변경 사항이 제안될 때 한 번, 그리고 병합된 후 주기적인 일정으로 다시 한번 실행되어야 하는데, 이는 추가된 당일에는 깨끗해 보였던 버전이라도 몇 주 후에 취약점이 공개될 수 있기 때문입니다. 어느 한쪽 확인에만 의존하는 것은 앞서 설명한 오래된 버전(stale-version) 문제와 직접적으로 연결되는 공백을 남깁니다.
풀 리퀘스트 단계에서 Codacy는 의존성 매니페스트 파일(dependency manifest files)을 스캔하고 취약한 의존성을 보안 문제(security issues)로 표시합니다.
이러한 문제는 품질 게이트(quality gate)에 반영되므로, 하나를 도입하는 풀 리퀘스트는 기준을 충족하지 못한다고 표시되며, Codacy는 이 상태를 Git 제공업체(Git provider)로 보고하고, 여기서 브랜치 보호(branch protection) 기능이 실패한 게이트를 병합 차단(blocked merge)으로 만듭니다.
게이트가 먼저 실패하고 플랫폼이 나중에 블록을 강제함으로써, 이 순서가 통제를 단순한 조언(advisory)이 아닌 실제적인 제어(real)로 만듭니다.
| 확인 지점 | 탐지하는 것 | 단독으로 놓치는 것 |
|---|
| 풀 리퀘스트 스캔 | 새로운 변경 사항에 도입된 알려진 취약 버전 | 병합 후 공개되는 취약점 |
| 야간 선제적 스캔 | 이미 병합된 의존성에 대한 새로 공개된 CVEs | 아직 병합되지 않은 코드에서 도입된 새로운 위험 |
Codacy의 선제적 소프트웨어 구성 분석(Software Composition Analysis) 스캔은 조직 내 모든 리포지토리를 매일 밤 실행하며, 가장 최근 커밋이 의존성 파일에 전혀 영향을 미치지 않았더라도 취약한 의존성을 플래그 지정합니다.
이 두 번째 확인 절차가 풀 리퀘스트(pull request) 스캔이 할 수 없는 간극을 메웁니다. 어시스턴트가 선택한 버전은 그날 알려진 취약점이 없었기 때문에 검토를 깨끗하게 통과할 수 있지만, 이후 3주 뒤에 아무도 열어보지 않은 리포지토리에 대해 취약점이 공개될 수 있습니다. 또한 야간 스캔은 대부분의 팀이 잊고 지내는 리포지토리, 레거시 서비스(legacy services), 그리고 새로운 풀 리퀘스트를 거의 받지 않지만 여전히 프로덕션 환경에서 실행되는 내부 라이브러리까지도 다룹니다.
발견된 결과는 취약점 우선순위가 가장 최근 탐지된 순서로 정렬되는 보안 및 위험 관리(Security and Risk Management) 대시보드에 표시되며, 심각한 문제 발생 시에는 Slack 알림이 전송됩니다. 만약 품질 게이트(quality gate) 자체가 리포지토리마다 다르게 구성되어 있다면 이 모든 것이 작동하지 않으므로, 체크 자체만큼이나 조직 전체의 일관성이 중요합니다.