LLM 취약점 감사자는 정적 분석의 안전 보장을 검증 없이 믿는다

Trusting the Tool: Asymmetric Deference of LLM Vulnerability Auditors to Static-Analysis Evidence

arXiv2610.32876v1

ZhiHong Liu2026-10-23

무엇인가

LLM에게 정적 분석기의 출력을 증거로 먹여 취약점을 판정하게 하는 파이프라인이 늘고 있다. 문제는 그 증거가 틀렸을 때 모델이 알아채는지, 그리고 알아채는 정도가 증거가 주장하는 방향에 따라 달라지는지가 측정된 적이 없다는 점이다. 정적 분석기는 놓치는 버그도 많지만 없는 방어 코드가 있다고 잘못 보고하기도 한다. 기존 연구는 코드 밖의 맥락(이전 판정, PR 메타데이터, 주석)이 판정을 흔든다는 것까지만 보였고, 같은 연산에 대한 참 증거와 거짓 증거를 짝지어 비교하지는 않았다.

어떻게 동작하나

저자들은 tree-sitter 위에 C/C++ 함수 단위 분석기를 직접 구현해 '증명 의무(proof obligation)'를 만든다. 각 민감한 연산(배열 인덱싱, 포인터 오프셋, 역참조, free, 나눗셈, 복사·할당 크기 등)마다 두 가지를 적는다. 모든 경로에서 성립하는 조건('holds here')과, 함수가 보장하지 않는 것('concern', 예컨대 인덱스 상한 검사 누락이나 free 이후 사용)이다. 이 의무 목록을 PrimeVul의 취약 버전·패치 버전 함수 쌍에 붙이되, 오직 노트만 바꾼 여섯 조건으로 감사한다. 노트 없음, 참 노트 전체, 패치가 건드린 연산에 대한 참 노트, 다른 연산에 대한 참 노트, '빠진 검사가 존재한다'는 조작된 보장, '패치가 추가한 검사가 없다'는 조작된 경고다. 거짓 조건은 모두 같은 연산에 대한 참 노트와 비교되므로 판정 차이를 증거의 진위로 돌릴 수 있다. 규모는 4개 벤더의 11개 모델 구성, 916쌍, 16,572회 감사이며 어떤 모델도 학습이나 파인튜닝을 하지 않았다. 데이터는 서로 겹치지 않는 네 집합으로 나뉜다. 연구 집합은 60개 프로젝트에서 고른 187쌍(374개 함수, 최대 150줄), 개발 집합 237쌍, 테스트 집합 300쌍(시드 7), 별도 홀드아웃 복제 집합 192쌍이다.

무엇과 다른가

결과의 핵심은 비대칭이다. 참 증거는 정확도를 거의 올리지 못했다(+0.02, 95% CI -0.03~+0.07). 반면 '검사가 존재한다'는 조작된 보장은 실제 취약점 탐지를 최대 19포인트 떨어뜨렸다. deepseek-chat에서 -0.11(p=0.012), 추가로 시험한 7개 모델 중 4개에서 -0.13~-0.19였다. 반대로 '검사가 없다'는 조작된 경고는 정확도를 유의하게 떨어뜨린 적이 없고 오히려 올리는 경우가 많았다. 모델이 빠진 방어 코드를 찾으러 가서 실제로 찾아내기 때문이다. 저자들은 이 비대칭을 방향 인지 지표로 정의해, 지표를 도출하는 데 쓰지 않은 7개 모델에 사전 등록된 복제 실험을 돌려 평균 비대칭 +0.16(95% CI +0.10~+0.24, p<0.001)으로 재확인했다. 응답 텍스트에서 모델이 거짓 경고에 이의를 제기하는 빈도가 거짓 보장보다 훨씬 높았다.

어떻게 쓰나

완화책에서는 프롬프트 지시가 실패하고 절차 분리가 통했다. 연구 집합에서 가장 좋았던 지시 전략은 '보장을 검증할 주장으로 재구성하기'로 +0.18을 냈지만, 66개 홀드아웃 함수에서는 이득이 8포인트로 줄고 유의하지 않아 복제에 실패했다. 대신 각 노트를 코드와 대조하는 호출을 따로 돌리고 반박된 노트를 감사 프롬프트에 보여주는 verify-show 방식은, 300개 미학습 쌍에 대한 사전 지정 검정에서 거짓 보장 조건의 정확도를 12포인트 회복했고(p=0.002) 참 증거 조건에서는 손실이 없었다. 다만 두 번째 모델 qwen-plus에서는 이득이 절반 수준이고 유의하지 않았다. 반박된 노트를 아예 빼는 것보다 '코드가 이 주장과 모순된다'고 명시해 보여주는 쪽이 효과적이었다.

전제와 한계

이 설계의 배경에는 사전 실험이 있다. 저자들은 모델이 프로그램 구조를 거의 잘못 읽지 않는다는 것을 먼저 확인했다. CRUXEval 50개, REval 85개 표본에서 단계별 추론 시 정확도가 0.98과 1.00이었고(직답은 0.88, 0.89), 1,257개 라벨링된 주장 중 정적 주장 337개는 하나도 틀리지 않았다. 오류는 실행 시점 값(CRUXEval 동적 주장의 3.0%, REval의 0.4%)에 몰려 있었다. 30쌍 감사에서도 분석 사실을 체크리스트로 주면 오히려 SAFE 판정이 늘었다. 즉 실패는 읽기 실패가 아니라 판단과 생략, 그리고 도구 출력에 대한 과도한 의존이다.

개발자에게 주는 결론은 분명하다. LLM 파이프라인에서 가장 검증이 필요한 입력은 분석기의 경고가 아니라 보장이다. '이 값은 범위가 제한된다', '이 포인터는 검사된다', '이 경로는 도달 불가능하다' 같은 보장은 모델이 의심 없이 받아들이는 방향이므로, 불완전한 분석이나 오래된 결과, 공격자가 만든 잘못된 보장이 그대로 판정에 전파된다. 보장은 감사 프롬프트 안의 지시가 아니라 별도 호출로 먼저 검증하고, 반박 결과를 감사에 넘겨야 한다. 또한 모델의 판정 성향(거의 다 취약하다고 하는 모델)이 증거에 흔들릴 여지를 좌우하므로, 정확도만으로 파이프라인을 평가하지 말고 증거 방향별 이동량을 짝지어 보고해야 한다. 참 증거를 쓸모 있게 만든 유일한 전략은 노트를 보기 전에 모델이 먼저 판정하는 commit-first였지만, 이는 개발 집합에서만 확인되고 테스트 집합에서는 검증되지 않았다.

한계도 저자들이 직접 밝힌다. 증거는 상용 도구가 아니라 자체 분석기가 만든 것이고, 거짓 보장은 함수를 읽으면 반박 가능하며 구체적 코드 라인을 인용한다. 실제 도구의 잘못된 보장은 반박하기 더 어려울 수 있으므로 측정된 순응은 하한선으로 봐야 한다. 관련성은 패치를 기준으로 정의해 취약점의 본질과 완전히 같지 않다. 실험은 150줄 이하(홀드아웃 300줄) C/C++ 함수를 호출 관계 없이 단독으로 감사한 경우에 한정되고, PrimeVul 라벨에도 잡음이 있으며 학습 데이터 오염 가능성도 배제할 수 없다. 방향 인지 지표는 처음 네 구성 결과를 본 뒤 정의했으므로 그 부분은 탐색적으로 취급하고, 이후 7개 모델에 내부 등록으로 확인했다. 완화책은 두 모델에서만 시험됐고, deepseek-v4-pro 결과는 60쌍 부분집합에 근거한다.