I wrote a test for prompt injection. It passed while the attack worked.
개요
llm-council 도구에서 발견된 프롬프트 인젝션 취약점과 이를 방어하기 위해 작성된 테스트 코드의 문제점을 분석하고, 진정한 보안 테스트의 중요성을 강조합니다.
주요 내용
* llm-council의 프롬프트 인젝션 취약점 발견: llm-council은 여러 LLM 모델의 답변을 비교하고 순위를 매기는 CLI 도구로, 모델 간의 출력을 입력으로 사용하는 과정에서 OWASP LLM01 취약점인 'fencing'(신뢰할 수 없는 콘텐츠를 구분자로 감싸는 것)을 사용했지만, 공격자는 쉽게 구분자를 조작하여 이를 우회할 수 있었습니다.
* 실패한 테스트 코드: 작성된 보안 테스트는 "A voter cannot forge another fence boundary"라는 이름을 가졌지만, 실제로는 구분자 문자열의 개수와 순서만 검증할 뿐, 모델이 속임수에 넘어가는지를 직접적으로 테스트하지 않아 취약점을 탐지하지 못했습니다. 이러한 테스트는 '실행되지만 실패할 수 없는 테스트'의 한 예시입니다.
* 정적 구분자에서 동적 Nonce로의 전환: 취약점 해결을 위해 고정된 구분자 대신, 매 실행마다 무작위로 생성되는 'nonce'(일회용 비밀번호)를 구분자에 포함시켜 공격자가 예측하거나 위조할 수 없도록 방어 메커니즘을 변경했습니다.
* 재작성된 테스트 코드: 변경된 보안 테스트는 "forged markers never match the run nonce"라는 이름으로, 위조된 구분자가 실제 실행 nonce와 일치하지 않음을 검증하여 프롬프트 인젝션 시도를 효과적으로 차단하는지 확인합니다.
* SonarCloud의 새로운 테스트 코드 차단: 새롭게 도입된 SonarCloud 품질 게이트가 "두 번의 Nonce 생성 결과가 다르지 않다"는 테스트 코드를 복사-붙여넣기 버그로 간주하여 차단했습니다. 이는 코드 검증 도구가 항상 개발자의 의도를 정확히 파악하지 못할 수 있음을 시사합니다.
* 강화된 Nonce 테스트: SonarCloud의 피드백을 바탕으로, "nonce differs between draws"라는 이름의 테스트를 작성하여 여러 번의 Nonce 생성이 모두 고유함을 보장하도록 강화했습니다. 이는 Nonce 충돌이 재사용 가능한 위조로 이어질 수 있음을 고려한 것입니다.
* 테스트의 본질: 테스트의 이름은 검증하고자 하는 세계에 대한 주장이며, 실제 Assertion은 그 주장에 대한 증거입니다. 두 가지가 일치하지 않으면 테스트는 무의미하며, Mutation testing(기능을 의도적으로 고장 내는 테스트)은 이러한 불일치를 발견하는 효과적인 방법입니다.
시사점
테스트 코드의 이름과 실제 검증 내용이 일치하는지 지속적으로 확인하고, 코드 커버리지뿐만 아니라 실제 보안 속성을 검증하는 Mutation testing과 같은 기법을 활용하여 소프트웨어의 견고성을 확보하는 것이 중요합니다.
댓글
GitHub Discussions