이제 Claude가 사람보다 취약점을 잘 찾습니다: Nicholas Carlini 인터뷰

Anthropic 보안 연구자 Nicholas Carlini가 언어 모델로 실제 소프트웨어 취약점을 찾는 방법을 설명합니다. CTF 프롬프트로 파일을 하나씩 훑는 단순한 방법이 Firefox와 Linux 커널에서 수십 년 묵은 버그를 찾아냈고, 방어가 더 어려워지는 새 국면을 짚습니다.

이제 Claude가 사람보다 취약점을 잘 찾습니다

Anthropic 보안 연구자 Nicholas Carlini가 Security Cryptography Whatever 팟캐스트에 다시 나와, 언어 모델로 실제 소프트웨어의 보안 취약점을 찾는 요즘 상황을 이야기합니다. 핵심은 하나입니다. 이제 힘들이지 않아도 모델이 진짜 버그를 찾아냅니다. 그리고 그 파장이 방어하는 쪽을 훨씬 어렵게 만듭니다.

이제 정교한 도구 없이도 모델이 진짜 버그를 찾습니다

LLM으로 취약점을 찾는 시도는 예전에도 있었습니다. Google DeepMind도, OpenAI도 오래 해 왔습니다. 예전에는 잘 구성한 스캐폴딩과 프롬프트를 갖춰야 겨우 됐습니다.

Carlini가 말하는 변화는 이겁니다. 이제 그렇게 애쓸 필요가 없습니다. 10줄짜리 Bash 스크립트와 Docker 컨테이너 하나면 됩니다. "이 프로그램을 ASan으로 컴파일해 뒀다. 소스를 읽고 ASan이 터지는 입력을 찾아라"라고 시키면, 프로그램에 따라 절반 넘는 확률로 크래시를 내는 입력을 들고 옵니다. "null 포인터 관련은 다 무시하라"라고 덧붙이면 중요한 버그를 찾을 확률이 더 올라갑니다.

예전엔 화려한 스캐폴딩이 필요했습니다. 지금은 Claude Code나 Codex를 열고 그냥 겨냥한 뒤 "크래시 하나 찾아줘"라고 하면 대체로 성공합니다.

특별한 내부 모델을 쓰는 것도 아닙니다. 모두가 쓰는 그 실제 서비스용 모델 그대로입니다.

방법은 파일을 하나씩 점수화해서 겨냥하는 것입니다

메모리 손상만큼 깔끔한 오라클이 없는 CMS 같은 웹앱은 어떻게 찾을까요. Carlini의 방법은 단순합니다.

먼저 싼 모델로 프로젝트의 모든 파일을 훑고, 각 파일이 보안상 흥미로운 코드를 담고 있을 가능성을 1점에서 5점으로 매깁니다. 1~2점은 버리고 3~5점만 남깁니다. 그다음 Claude Code를 권한 확인 없이 도는 모드(dangerously-skip-permissions)로 띄우고 이렇게 시킵니다. "이 코드베이스의 보안을 감사해라. 이건 CMS다. 이 Docker 컨테이너를 마음대로 써라. 버그를 찾아라." 여기에 "이 파일을 봐라"라는 힌트로 진입점을 바꿔 가며 같은 프로젝트를 100번 돌립니다. 파일 이름만 바꿔 넣어 무작위성을 줍니다.

SQL injection이 뭔지 따로 설명하지 않습니다. 프롬프트에 넣는 취약점 설명은 0입니다. 모델은 SQL injection, 로그인 우회, XSS, CSRF가 무엇인지 이미 다 압니다. 프롬프트조차 Carlini가 직접 쓰지 않았습니다. Claude에게 "버그 찾는 에이전트를 만들어라"라고 시켜 받았습니다.

결과 보고서는 또 다른 모델이 검증합니다. "누가 이런 보고서를 보냈다. 진짜인가? 깨끗한 이미지에서 재현해 봐라." 이 비평 에이전트가 가짜를 걸러 냅니다. 가장 흔한 실패는, 모델이 세션 초반에 로그인 우회용 디버그 코드를 몰래 심어 두고, 컨텍스트가 여러 번 압축된 뒤 자기가 심은 그 코드를 "버그 발견"이라고 착각하는 경우입니다. 비평 에이전트는 깨끗한 이미지에서 돌려 이런 걸 지웁니다. 마지막에 모델이 스스로 매긴 잠정 CVSS 점수를 붙이게 해서 CVSS 9대를 grep으로 뽑아 심각한 것부터 사람이 확인합니다.

오라클이 있으면 진위 판별이 공짜가 됩니다

Carlini가 메모리 손상부터 시작한 이유는 오라클이 완벽하기 때문입니다. ASan으로 컴파일한 프로그램에 입력을 넣어 크래시가 나면, 그건 버그입니다. 판별에 사람 손이 필요 없습니다.

Firefox에 Opus 4.6을 돌려 크래시 입력 122개를 Mozilla에 보냈고, Mozilla가 전부 진짜 버그라고 확인했습니다. 참 양성률 100%입니다. 그중 22개가 심각도가 높아 CVE를 받았습니다.

오라클이 없는 곳에서도 성과가 있습니다. Ghost는 GitHub 스타 5만 개짜리 Node 기반 CMS인데, 프로젝트 역사상 심각도 최상 등급 버그가 한 번도 없었습니다. Opus 4.6이 하나를 찾았습니다. 권한이 전혀 없는 미인증 사용자가 관리자 DB를 장악하고 새 관리자 계정을 만들어 로그인하는 완전한 계정 탈취였습니다. 모델은 취약점만 찾은 게 아니라, WHERE 절 뒤 파라미터만 조작할 수 있는 까다로운 blind SQL injection 익스플로잇까지 통째로 작성했습니다.

모델이 사람을 이기는 건 똑똑해서가 아니라 규모 때문입니다

Carlini는 자기가 여전히 모델보다 낫다고 말합니다. 자기 완결적인 300줄짜리 코드를 같은 시간 들여 보면 자기가 이깁니다.

하지만 그가 못 하는 게 있습니다. Linux 커널의 모든 C 파일을 하나하나 다 분석하는 일입니다. 사람은 어디를 볼지 좋은 직관에 시간을 씁니다. 모델은 직관이 없어도 됩니다. 그냥 다 봅니다. 로드도 안 되는 드라이버까지 절반은 헛수고로 훑지만, 워낙 빠르고 싸서 그 낭비가 문제가 안 됩니다.

저는 어디를 봐야 할지 직관에 대부분의 시간을 씁니다. 모델은 직관이 필요 없습니다. 모든 곳을 다 볼 수 있습니다.

그렇게 수십 년 잠자던 버그가 나옵니다. Linux NFS 데몬에서 찾은 힙 버퍼 오버플로는 22년 됐고, Git보다 오래돼서 고침 표시에 커밋 해시 대신 2.6 시절 변경분을 적어야 했습니다. 두 클라이언트가 같은 파일에 락을 걸 때, 이름이 아주 긴 쪽이 상대에게 에러로 반사되며 힙 버퍼를 넘칩니다. 여러 클라이언트가 패킷을 딱 맞게 엇갈려 보내야 해서 발견이 어려웠을 뿐, 알고 보면 이해되는 버그입니다.

퍼저가 절대 못 찾는 버그도 모델은 찾습니다. FFmpeg의 H.264 코드에는 프레임이 정확히 65535개일 때 넘치는 20년 묵은 버그가 있었습니다. 퍼저가 루프를 6만 5천 번 돌려 크래시를 낼 리 없습니다. CRC32 체크섬이 든 프로토콜도 마찬가지입니다. 퍼저는 유효한 체크섬을 우연히 만들지 못하지만, 모델은 나머지를 추론하다가 체크섬이 필요한 지점에서 Python으로 올바른 값을 계산해 패킷에 붙여 보냅니다. 퍼저는 국소적으로 브랜치만 보지만, 모델은 코드를 이해합니다.

쓴 교훈: 하네스에 힘을 빼면 안 됩니다

인터뷰에서 가장 곱씹을 대목입니다. Anthropic의 500개 zero-day 결과는 하네스나 프롬프트 기술이 아니라 거의 전적으로 모델 자체의 힘이었습니다.

Carlini는 특정 모델에 맞춰 하네스를 아주 잘 만들면, 다음 모델이 나오는 순간 그 하네스가 오히려 족쇄가 된다고 말합니다. 2024년 11월에 만든 하네스는 모델이 기계를 망가뜨릴까 봐 "파일 6개만 수정하고, 명령 3개만 실행하라"라고 묶어야 했습니다. 지금 같은 하네스를 최신 모델로 돌리면, 모델은 시간을 아끼려고 백그라운드로 작업을 띄워 놓고 그 사이 코드를 읽으려 합니다. 좋은 생각인데, 옛 하네스가 그걸 막습니다.

Princeton의 한 벤치마크에서 Opus 4.5는 40%를 받았습니다. Carlini가 그 하네스를 다 버리고 Claude Code에 문제를 통째로 주고 "풀어라"라고만 하니 92%가 나왔습니다.

지금 모델에 맞춰 마지막 한 방울까지 뽑아내는 일에는 분명 가치가 있습니다. 하지만 다음 모델이 그냥 더 잘하게 될 만큼 늦고 헛된 일에 힘을 쏟지는 말아야 합니다.

John Carmack이 Doom을 위해 5년간 초최적화 어셈블리를 만들었다면, 정작 출시 시점엔 그냥 만든 C 코드도 똑같이 빨랐을 거라는 비유를 듭니다.

파장: 찾기보다 고치기가 더 어렵습니다

찾는 쪽이 쉬워졌다고 방어가 쉬워지는 게 아닙니다. 오히려 반대입니다.

크래시 입력을 찾는 건 완벽한 오라클 덕에 공짜에 가깝지만, 고치려면 왜 그런지부터 이해해야 하고 사용자 기능을 깨지 않아야 합니다. Firefox는 버그를 고치는 데 찾는 것보다 대략 두 배의 엔지니어 시간을 썼습니다. 게다가 버그 바운티는 과부하로 무너지고 있습니다. 그럴듯해 보이지만 틀린 보고서를 아무나 쏟아 낼 수 있게 되면서, 큰 플랫폼만 바운티를 남기고 나머지는 문을 닫고, 남은 곳도 POC 없는 제보는 받지 않는 쪽으로 갑니다.

정작 Carlini가 더 걱정하는 건 화려한 zero-day가 아닙니다. 대부분의 실제 공격은 그저 누가 패치를 안 한 서비스, 잘못 설정해 열어 둔 포트입니다. 이제 아무나 인터넷을 훑어 10년째 안 고친 서버를 찾아 털 수 있게 됩니다. 그는 이걸 스택 스매싱을 처음 알게 된 순간에 비유합니다. 2002~2004년 웜이 인터넷을 휩쓸던 세상이 다시 올 수 있다고 봅니다.

낙관도 있습니다. 새로 들어오는 커밋마다 이런 버그 사냥 모델이 코드 리뷰를 하게 하면, 새로 심기는 버그의 절반쯤은 걸러 낼 수 있습니다.

조금 무서워하는 게 올바른 반응입니다

Carlini는 이 도구들을 써 보고도 앞으로 벌어질 일이 조금도 무섭지 않다면, 비판적으로 생각하지 않는 거라고 말합니다. 코딩에서 먼저 터졌을 뿐, 다른 분야도 곧 같은 문제를 만납니다.

LLM이 멍청해서 취약한 코드를 쏟아 낼 거라는 흔한 걱정과는 방향이 정반대입니다. 모델은 표준적인 취약점을 사람보다 잘 잡아냅니다. 모델이 어떤 일에는 서툴 수 있다는 것과, 어떤 일에는 정말 잘한다는 것은 서로 모순되지 않습니다. 취약점 찾기가 바로 잘하는 쪽입니다.

세상은 몇 년이 아니라 몇 달 단위로 달라지고 있습니다. 가만히 앉아 잘되기를 바라지 말고, 무엇이 사실인지 알아내는 데 시간을 써야 합니다. 최소한 세상을 보는 자신의 관점부터 갱신해야 합니다.