치명적 CVE인가, LLM 슬롭인가 — SQLite 사례가 드러낸 취약점 신고의 신뢰 위기
치명적 CVE인가, LLM 슬롭인가 — SQLite 사례가 드러낸 취약점 신고의 신뢰 위기
CVSS 9.8이 붙은 여섯 건의 SQLite 취약점 보고서. 이것은 세상에서 가장 널리 배포된 오픈소스를 노린 치명적 공격면인가, 아니면 LLM이 그럴듯하게 지어낸 슬롭(slop)인가. JFrog가 하나씩 재현을 시도하자 드러난 것은 코드의 결함이 아니라, 취약점 신고 시스템 그 자체의 결함이었다.
도입
2026년 7월 30일, 소프트웨어 공급망 보안 기업 JFrog의 연구원 아페크 버거(Afek Berger)가 한 편의 리서치를 공개했다. 대상은 SQLite였다. SQLite는 모든 주요 브라우저, 거의 모든 스마트폰, 수많은 임베디드 기기 안에서 조용히 돌아가는, 지구상에서 가장 많이 배포된 소프트웨어 중 하나다. 그런 SQLite에 며칠 사이 여섯 건의 CVE가 등록됐고, 그중 둘은 CVSS 9.8 — 사실상 만점에 가까운 “치명적(Critical)” 등급이었다. 상식적으로라면 전 세계 보안팀이 즉시 패치에 돌입해야 할 사건이다.
그런데 JFrog가 여섯 건을 하나씩 손으로 재현해 보자, 재현되는 것이 하나도 없었다. 인용된 함수가 해당 버전에 존재하지 않았고, 취약하다는 코드 줄 번호가 파일 길이를 넘어갔으며, 개념 증명(PoC) 페이로드는 어떤 크래시도 일으키지 못했다. JFrog의 결론은 무겁다. 이것들은 SQLite의 버그가 아니라, 대량 생성 도구가 만들어 낸 그럴듯한 허구 — 이른바 LLM 슬롭일 가능성이 높다는 것이다. 이 글은 무엇이 사실로 확인됐고, 그것이 오픈소스 보안 생태계의 어떤 구조적 약점을 드러내는지를 나눠서 본다.
재현되지 않는 ‘치명적’ 취약점들
먼저 사실관계다. JFrog가 분석한 CVE는 여섯 건이다. CVE-2026-51302(CVSS 9.8 Critical), CVE-2026-51303(9.8 Critical), CVE-2026-51300(9.1 Critical), CVE-2026-51297(8.8 High), CVE-2026-51296(7.5 High), CVE-2026-51304(7.5 High). 점수만 보면 어느 하나 가볍게 넘길 수 없는 목록이다.
JFrog가 보고한 개별 검증 결과는 구체적이고, 그래서 반박하기 어렵다. CVE-2026-51302는 exprComputeOperands()라는 함수의 취약점을 주장했지만, JFrog에 따르면 이 함수는 2025년 중반에야 추가된 것으로 신고서가 지목한 3.41.0 버전에는 아예 존재하지 않는다. 시간 여행을 하지 않는 한 있을 수 없는 취약점인 셈이다. CVE-2026-51303은 특정 릴리스 사이의 코드 변경을 근거로 들었지만, JFrog가 3.51.2와 3.51.3 사이의 diff를 뜨자 문제의 src/expr.c에는 “변경이 전혀 없다(absolutely no changes)“고 보고했다. CVE-2026-51296은 취약한 위치로 3555번, 3575번 줄을 지목했는데, 정작 그 파일은 2706줄짜리였다. 존재하지 않는 줄에 존재하지 않는 버그가 있었던 것이다. CVE-2026-51304는 인용한 함수 시그니처 자체가 실제와 달랐다.
공통점도 뚜렷했다. JFrog는 여섯 건 중 어느 것도 SQLite의 공식 취약점 고지 페이지에 올라와 있지 않았다고 밝혔다. SQLite는 상대적으로 취약점 공개가 투명하고 유지보수 규율이 엄격한 프로젝트로, 실제 보안 이슈라면 상류(upstream)에 흔적이 남는다. 그런 흔적이 전혀 없었다. 더해서 JFrog가 AI 생성물 탐지 도구에 신고서 문장을 넣자, 해당 문서들이 “AI가 생성한 콘텐츠”로 분류됐다고 한다. 흥미롭게도 여섯 건이 완전히 방치된 것은 아니어서, Red Hat은 CVE-2026-51302를 9.8 Critical에서 7.6 High로 자체 하향 조정한 상태였다. 같은 취약점 하나를 두고 채점자마다 2점 이상 벌어진다는 사실은, 뒤에서 다룰 CVSS 신뢰 문제의 예고편이기도 하다.
추적을 이어가자 발원지가 드러났다. JFrog에 따르면 이 CVE들은 programmervuln/cveadvisory-라는 새로 만들어진 GitHub 저장소에서 흘러나왔고, 그 저장소에는 유사한 형태의 의심스러운 CVE가 50건 넘게 담겨 있었다. JFrog가 같은 출처의 어드바이저리 55건을 살펴본 결과, 54건이 “완전히 조작됐다(completely fabricated)“고 판단됐고, 나머지 한 건만이 합법적이되 검증되지 않은 정보를 담고 있었다. 요약하면, 한 곳에서 뿜어져 나온 취약점 신고의 98% 이상이 실체가 없었다는 이야기다.
하필 대상이 SQLite였다는 점이 이 사건의 무게를 키운다. 만약 이 여섯 건이 걸러지지 않고 자동화된 스캐너의 데이터베이스에 안착했다면, SQLite에 의존하는 무수한 제품의 의존성 목록에서 “치명적 취약점 발견” 경보가 동시에 울렸을 것이다. 실체가 없는 취약점이라도 일단 목록에 오르면, 그것이 거짓임을 증명하는 부담은 신고자가 아니라 전 세계의 사용자와 유지보수자에게 전가된다. 하나의 조작 저장소가 만들어 낼 수 있는 파급의 규모가, 바로 이 표적 선택에서 드러난다.
CVE는 왜 이렇게 쉽게 오염되는가
여기서부터는 분석이다. 개별 신고서가 엉터리라는 사실보다 더 중요한 질문은, 왜 이런 엉터리가 “CVE”라는 공식 식별자를 달고 CVSS 9.8까지 받아 유통될 수 있었는가다. 답은 취약점 식별 체계의 구조에 있다.
CVE 번호는 MITRE가 총괄하고, 실제 발번은 전 세계에 흩어진 CNA(CVE Numbering Authority)들이 나눠 맡는다. 번호는 보통 “예약(reservation)” 방식으로, 취약점이 완전히 검증되기 전에도 먼저 확보된다. 즉 식별자 발급 단계에는 “이 버그를 재현해 보였는가”라는 문턱이 사실상 없다. 재현 가능한 PoC 제출을 강제하는 절차가 파이프라인에 내장돼 있지 않은 것이다. 여기에 상세 분석과 점수를 붙여 정본으로 만들어 주던 미국 NVD(National Vulnerability Database)가 결정적인 타이밍에 멈춰 섰다. JFrog가 지적하듯 NIST는 2024년 2월 이후 심층 분석을 “사실상 일시 정지(hit pause)“했고, 그 결과 검증되지 않은 CVE가 재현 증명 요구 없이 순환할 수 있는 파편화된 시스템이 남았다. 문지기가 자리를 비운 문으로 대량 생성된 신고가 밀려들어 온 것이다.
오랫동안 이 취약한 발급 구조를 뒤에서 떠받쳐 준 것이 NVD의 심층 분석이었다. 번호는 먼저 나오더라도, 결국 NVD가 재검토하며 등급을 붙이고 영향 범위를 정리해 주었기에 생태계는 그 결과를 정본으로 신뢰할 수 있었다. 그 최종 심판자가 2024년 이후 사실상 손을 놓으면서, 발급 단계의 느슨함을 사후에 걸러 주던 안전망이 사라졌다. 지금의 CVE 목록은 문턱도 낮고 사후 감사도 얕은, 양쪽이 동시에 열린 상태다.
CVSS 점수의 신뢰도는 이 구조에서 특히 취약하다. CVSS는 벡터를 채우면 기계적으로 점수가 나오는 계산식이지만, 그 벡터를 어떻게 채울지는 신고자의 주장에 크게 의존한다. 근거가 허구라면 9.8이든 7.5든 숫자는 아무 의미가 없다. 앞서 본 Red Hat의 7.6 하향은 채점의 주관성을 보여주고, 원 신고의 9.8은 애초에 존재하지 않는 코드에 매겨진 값이다. 점수가 높을수록 자동화된 우선순위 큐에서 위로 올라가고, 위로 올라갈수록 더 많은 사람의 시간을 태운다. 슬롭에게는 CVSS가 높을수록 유리한 셈이다.
비대칭이 이 문제의 핵심이다. HN 토론에서는 이른바 브란돌리니(Brandolini) 법칙 — 헛소리를 만드는 비용이 그것을 반박하는 비용보다 훨씬 싸다는 원리 — 이 여러 차례 언급됐다. LLM은 그 비대칭을 산업 규모로 키운다. 그럴듯한 취약점 서술 50건을 만드는 데는 몇 분이면 충분하지만, JFrog처럼 하나하나 소스를 받아 diff를 뜨고 줄 번호를 세어 반증하는 데는 숙련된 연구원의 하루가 든다. HN 토론에서는 또한, LLM은 결국 확률적 텍스트 예측기라서 자신이 얼마나 확신하는지와 무관하게 그럴듯한 출력을 내놓으며, 코드의 주석을 실제 취약점으로 착각하는 식의 오류를 낸다는 지적이 나왔다. 그래서 “LLM이 사실로 제시하는 모든 것을 사람이 검증해야 한다 — 모든 것을”이라는 강경한 주장이 스레드 상단을 차지했다는 게 토론의 분위기였다. 물론 반론도 있었다. HN 토론에서는 “그냥 토큰 예측기일 뿐”이라는 폄하가 LLM이 실제로 낸 성과를 놓친다는 반박, 그리고 소프트웨어 엔지니어링에도 다른 공학 분야의 기술사(PE) 면허 같은 책임 체계가 필요하다는 제안도 함께 오갔다. 요컨대 논쟁의 축은 “도구가 나쁜가”가 아니라 “검증 없는 사용이 나쁜가”로 옮겨가 있었다.
자동화된 보안 리서치의 트레이드오프
이 사건이 실무자에게 던지는 함의는 세 갈래로 갈린다. 낙관 시나리오는, 이번처럼 신뢰받는 벤더가 슬롭을 조기에 적발해 공개하면 시장이 자정 능력을 갖추고 발원 저장소가 차단되며, 오히려 CVE 발급 파이프라인에 재현 증명이라는 문턱을 세우는 개혁으로 이어지는 그림이다. 비관 시나리오는 그 반대다. JFrog가 명시적으로 경계한 대목이 여기다 — “AI를 이용해 취약점 분류(triage)와 대응을 자동화하는 환경에서는 이 문제가 한층 더 우려스러워진다.” 조작된 CVE를 사람이 아니라 자동화 파이프라인이 소비하면, 존재하지 않는 취약점에 대응하느라 존재하지 않는 함수를 “패치”하는 무의미한 작업이 자동으로 생성되고, 그 결과가 다시 학습 데이터로 흘러 들어가는 오염 루프가 만들어진다. 슬롭이 슬롭을 먹고 자라는 구조다.
현실 시나리오는 그 사이 어딘가다. CVE 인플레이션은 이미 진행 중이고, NVD의 병목은 단기간에 해소되기 어렵다. 그렇다면 방어선은 개별 조직의 운영 규율로 내려온다. 실무적 시사점은 분명하다. 첫째, CVSS 점수 하나로 자동 대응을 트리거하지 말 것. 점수는 우선순위의 입력이지 진위의 증거가 아니다. 둘째, 대응 전에 출처(provenance)를 확인할 것 — 상류 프로젝트의 공식 고지에 대응되는 흔적이 있는가, 신고 저장소는 신뢰할 만한가, 재현 가능한 PoC가 붙어 있는가. SQLite 사례에서 이 세 질문 중 하나라도 던졌다면 여섯 건은 첫 관문에서 걸렀을 것이다. 셋째, 자동화의 마지막 단계에는 사람의 검증을 남겨 둘 것. 특히 “패치를 자동 생성”하는 파이프라인일수록, 존재하지 않는 취약점에 존재하지 않는 수정을 적용하는 사고를 막는 최소 안전장치가 필요하다.
유지보수자 번아웃도 조용히 진행되는 비용이다. 오픈소스 프로젝트의 메인테이너는 대개 소수이고, 잘못된 취약점 신고 하나에도 평판 방어와 사용자 문의 대응을 떠맡는다. curl 같은 프로젝트의 유지보수자들이 AI로 대량 생성된 저품질 신고에 시달려 왔다는 것은 이 바닥에서 이미 공유된 피로다. 신고 비용이 0에 수렴하는 시대에, 그 비용을 전부 떠안는 쪽은 언제나 검증하는 사람이다.
결론
리드의 질문으로 돌아가자. 여섯 건의 SQLite CVE는 치명적 취약점인가, LLM 슬롭인가. JFrog의 검증을 신뢰한다면 답은 명백히 후자다 — 존재하지 않는 함수, 파일 길이를 넘는 줄 번호, 재현되지 않는 PoC는 코드의 문제가 아니라 신고의 문제다. 그러나 이 사건의 진짜 교훈은 개별 신고의 진위가 아니다. CVSS 9.8을 달고도 아무런 재현 문턱을 통과하지 않은 채 공식 식별자로 유통될 수 있었다는 사실, 바로 그 구조가 문제다.
취약점 데이터베이스의 가치는 신뢰에 있다. “이 번호가 붙었으니 진짜다”라는 전제가 무너지면, 남는 것은 노이즈뿐인 목록과 그것을 하나씩 손으로 걸러야 하는 연구원들의 소진이다. 재현 우선(reproduction-first), 출처 검증, 그리고 자동화의 끝에 남겨 둔 사람의 눈 — 신뢰를 다시 세우는 재료는 화려하지 않다. 질문을 독자에게 넘긴다. 당신의 조직은 다음에 CVSS 9.8짜리 CVE를 마주쳤을 때, 패치부터 돌릴 것인가, 아니면 먼저 그 취약점이 정말 존재하는지 물을 것인가.
출처: