OWASP LLM Top 10: 빌더를 위한 지도
요약
OWASP LLM Top 10 (2025)의 업데이트 내용을 바탕으로, 정적 분석 도구가 탐지할 수 있는 영역과 런타임 리스크의 차이를 설명합니다. BrassCoders를 통해 소스 코드 패턴으로 검증 가능한 보안 항목과 배포 제어가 필요한 항목을 구분하는 가이드를 제공합니다.
핵심 포인트
- OWASP LLM Top 10 (2025)의 10가지 보안 카테고리 업데이트
- 정적 분석기가 탐지 가능한 소스 코드 패턴과 런타임 리스크의 구분 필요성
- 스캐너가 도달할 수 있는 3가지 카테고리와 도달 불가능한 7가지 리스크 식별
- 보안 계획 수립 시 코드 리뷰와 런타임 제어의 역할 분담 강조
OWASP LLM Top 10 (2025)은 단순히 훑어보고 넘어갈 체크리스트가 아닙니다. 10개 카테고리 중 7개는 런타임 리스크 (runtime risks)로, 정적 분석기 (static analyzer)가 플래그를 표시할 수 있는 소스 패턴을 생성하지 않습니다. 여러분의 스캐너가 도달할 수 있는 3가지와 도달할 수 없는 7가지가 무엇인지 아는 것이 보안 계획과 잘못된 보안 범위에 대한 착각 사이의 차이를 만듭니다.
OWASP LLM Top 10: 빌더를 위한 지도
BrassCoders는 현재의 OWASP LLM Top 10 (2025년 에디션, 2025년 3월 12일 OWASP GenAI Security Project에서 발표)을 스캔 시 실행되는 12개의 스캐너와 대조하여, 여러분의 코드 리뷰가 어디서 멈추고 런타임 제어 (runtime controls)가 어디서부터 시작되어야 하는지 정확히 알 수 있게 합니다.
2025년 목록은 2023년의 v1.1을 대체하였으며 여러 카테고리의 번호를 재지정했습니다. 만약 "LLM02: Insecure Output Handling"이라는 참조를 보셨다면, 그것은 v1.1의 번호였습니다. 현재 목록은 동일한 카테고리를 LLM05:2025 Improper Output Handling이라고 부릅니다. 전체 2025년 목록은 다음과 같습니다:
- LLM01:2025 Prompt Injection
- LLM02:2025 Sensitive Information Disclosure
- LLM03:2025 Supply Chain
- LLM04:2025 Data and Model Poisoning
- LLM05:2025 Improper Output Handling
- LLM06:2025 Excessive Agency
- LLM07:2025 System Prompt Leakage
- LLM08:2025 Vector and Embedding Weaknesses
- LLM09:2025 Misinformation
- LLM10:2025 Unbounded Consumption
권위 있는 출처는 genai.owasp.org/llm-top-10/ 입니다.
정적 분석이 다루는 범위 (및 그 이유)
BrassCoders는 소스 코드 패턴 (source-code pattern), 즉 탐지 가능한 데이터 흐름 (data flow), 안전하지 않은 API 호출 (unsafe API call), 이스케이프되지 않은 보간 (unescaped interpolation)으로 나타나는 모든 OWASP LLM Top 10 카테고리에 도달할 수 있습니다. 만약 리스크에 코드 시그니처 (code signature)가 없다면 — 즉, 모델의 학습 데이터 (training data), 런타임 에이전트 동작 (runtime agent behavior), 또는 인프라 구성 (infrastructure configuration)에 존재한다면 — 어떤 스캐너도 이를 볼 수 없습니다.
그것은 메워야 할 공백이 아닙니다. 그것은 올바른 분업입니다. 런타임 리스크 (runtime risks)에 대해 존재하지 않는 탐지 결과를 만들어내는 스캐너는 팀들이 이를 무시하도록 가르칩니다. BrassCoders는 커밋된 코드에서 검증할 수 있는 내용을 보고하며, 나머지 부분은 여러분의 배포 제어 (deployment controls)가 처리합니다.
2025년 리스트 중 세 가지 카테고리는 의미 있는 소스 코드 커버리지 (source-code coverage)를 가집니다. 하나는 애플리케이션 코드 레이어 (application-code layer)에서 부분적인 커버리지를 가집니다. 나머지 여섯 개는 커버리지가 전혀 없습니다.
LLM01:2025 프롬프트 인젝션 (Prompt Injection) — BrassCoders가 잡아낼 수 없는 것
BrassCoders는 프롬프트 인젝션을 플래그 (flag)하지 않으며, 다른 어떤 정적 분석기 (static analyzer)도 마찬가지입니다. 프롬프트 인젝션은 AI 에이전트에 대한 런타임 공격이지, 에이전트가 생성하는 소스 코드 내의 패턴이 아닙니다. 공격자는 에이전트가 읽는 콘텐츠 — 파일, 웹 페이지, 사용자 메시지 등 — 에 적대적인 지침 (adversarial instructions)을 삽입하며, 에이전트는 정당한 시스템 프롬프트 (system prompt) 대신 해당 지침을 따르게 됩니다. 커밋된 코드베이스에는 스캐너가 일치시킬 수 있는 대상이 아무것도 없습니다.
The Attack BrassCoders Can't Catch: Prompt Injection 포스트는 공격 표면 (attack surface)을 자세히 다루며, 완화 조치 (mitigations)가 실제로 어디에 위치하는지 설명합니다: 에이전트 샌드박싱 (agent sandboxing), 컨텍스트 격리 (context isolation), 제한된 도구 권한 (restricted tool permissions), 그리고 이그레스 제어 (egress control)입니다.
BrassCoders가 실제로 드러내는 것은 검증 없이 모델 호출에 사용자 입력을 전달하는 애플리케이션 레이어 (application-layer) 코드입니다. 이것은 프롬프트 인젝션 탐지 결과는 아니지만, 프롬프트 인젝션 공격을 더 쉽게 악용하게 만드는 코드 패턴입니다. 만약 여러분의 라우트 핸들러 (route handler)가 콘텐츠 필터나 길이 확인 없이 request.body를 openai.chat.completions.create() 호출로 직접 전달한다면, 이는 소스 코드에서 확인 가능하며, BrassCoders의 Semgrep 오염 분석 스캐너 (taint scanner)가 해당 입력 흐름 경로 (input-flow path)를 플래그할 것입니다.
LLM05:2025 부적절한 출력 처리 (Improper Output Handling) — BrassCoders가 잡아낼 수 있는 것
BrassCoders는 HTTP 요청 소스(source)에서 렌더링 싱크(sink)까지 사용자 제어 데이터를 추적하는 오염 분석 (taint analysis)을 통해 LLM05:2025 부적절한 출력 처리 (Improper Output Handling)를 잡아냅니다. 이는 애플리케이션이 이스케이프 (escaping) 처리 없이 AI 생성 출력을 템플릿에 전달할 때 AI 생성 출력을 위험하게 만드는 것과 동일한 패턴입니다.
구체적으로, BrassCoders는 Flask, Django, FastAPI 요청 소스를 통해 6가지 싱크 (sink) 범주로 이어지는 데이터 흐름을 추적하는 번들형 Semgrep 오염 규칙 (taint rules, mode: taint)을 제공합니다:
- Python 싱크 (sinks):
render_template_string(), Flask의Markup(), Django의mark_safe(), 그리고HttpResponse(..., content_type="text/html")— 이들은 모두 사용자 입력이 자동 이스케이프 없이 HTML 렌더링에 도달할 수 있는 패턴들입니다. - JavaScript/TypeScript 싱크 (sinks): React의
dangerouslySetInnerHTML, 직접적인innerHTML및outerHTML할당,document.write(), 그리고 jQuery의.html()— 이들은 모두 서버에서 가져오거나 사용자가 제공한 콘텐츠가 정화 (sanitization) 과정 없이 DOM에 도달하는 경로들입니다.
Pysa 인터프로시저럴 (interprocedural, 함수 간) 오염 스캐너는 Python 코드베이스에 대해 두 번째 탐지 계층을 추가하여, 정규 표현식 (regex) 기반 규칙이 놓치는 함수 경계 간의 XSS 흐름을 추적합니다. api_security_scanner는 안전한 래퍼 (safe-wrapper) 필터를 사용하여 dangerouslySetInnerHTML에 대한 경량 패턴 매칭을 추가합니다. 이미 DOMPurify.sanitize() 또는 동일한 이름의 함수로 래핑된 호출은 제외되므로, 검증되지 않은 표면적을 넓히지 않으면서 오탐 (false positives)을 줄여줍니다.
LLM05:2025는 "AI가 이 출력을 작성했고 우리가 이를 렌더링했다"라는 상황이 코드 계층의 취약점이 되는 바로 그 카테고리입니다. AI 어시스턴트가 HTML 스니펫을 생성하고, 애플리케이션이 이를 템플릿 문자열에 삽입하는 것은 SQL 인젝션 (SQL injection)과 다를 바 없는 오염 경로 (taint path)입니다. BrassCoders는 이를 동일하게 취급합니다.
런타임 카테고리: 스캐너 외부의 완화 조치 (Mitigations)
BrassCoders는 2025년 10개 카테고리 중 6개에 대해 보고할 결과가 없습니다. 이들은 스캐너가 도달할 수 있는 소스 코드 시그니처 (source-code signature)를 가지고 있지 않기 때문입니다.
**LLM04:2025 데이터 및 모델 포이즈닝 (Data and Model Poisoning)**은 여러분이 커밋하는 코드가 존재하기 전인, 학습(training) 또는 미세 조정(fine-tuning) 단계에서 발생합니다. 완화 계층은 데이터 출처(data provenance), 데이터셋 검증(dataset validation), 그리고 모델 아티팩트(model artifacts)에 대한 공급망 제어(supply-chain controls)입니다. 어떤 스캐너도 학습 데이터(training data)를 볼 수 없습니다.
**LLM07:2025 시스템 프롬프트 유출 (System Prompt Leakage)**은 런타임(runtime) 정보 노출 취약점입니다. 공격자는 모델 출력을 통해 시스템 프롬프트(system prompt)를 추출합니다. 이 위험은 배포된 시스템이 어떻게 구성되었는지, 그리고 모델이 적대적 탐색(adversarial probing)에 어떻게 반응하는지에 달려 있습니다. 여러분의 스캐너는 소스 코드에서 시스템 프롬프트 문자열을 볼 수는 있지만, 모델이 런타임에 이를 공개할지 여부는 판단할 수 없습니다.
**LLM08:2025 벡터 및 임베딩 취약점 (Vector and Embedding Weaknesses)**은 검색 증강 생성 (RAG, Retrieval-Augmented Generation) 파이프라인의 위험을 다룹니다. 여기에는 인덱스 포이즈닝 (index poisoning), 적대적 검색 조작 (adversarial retrieval manipulation), 그리고 임베딩 역전 (embedding inversion)이 포함됩니다. 이는 인프라 및 데이터 계층의 위험입니다. 벡터 저장소 (vector store)의 액세스 제어 (access controls)와 인덱싱 파이프라인은 소스 코드 분석 (source-code analysis)의 범위를 벗어납니다.
**LLM09:2025 잘못된 정보 (Misinformation)**는 출력 품질 (output-quality) 위험입니다. 모델이 사실과 다른 콘텐츠를 생성하고, 하위 사용자(downstream users)가 이를 바탕으로 행동하는 상황을 말합니다. 잘못된 정보를 유발하는 특정 코드 패턴은 존재하지 않습니다. 이는 모델의 가중치 (weights)와 모델에 제공된 컨텍스트 (context)의 속성입니다. 완화 방법으로는 그라운딩 전략 (grounding strategies), 검색 증강 (retrieval augmentation), 그리고 인간 검토 워크플로 (human review workflows)가 있습니다.
**LLM10:2025 무제한 소비 (Unbounded Consumption)**는 리소스 거버넌스 (resource-governance) 위험입니다. 공격자가 애플리케이션이 모델 토큰 (model tokens), API 할당량 (API quota), 또는 컴퓨팅 자원을 과다하게 소비하도록 유도하는 요청을 보냅니다. 완화 방법은 게이트웨이 (gateway) 또는 오케스트레이션 계층 (orchestration layer)에서의 속도 제한 (rate limiting), 토큰 예산 강제 (token-budget enforcement), 그리고 타임아웃 설정 (timeout configuration)입니다. 스캐너는 속도 제한 미들웨어 (rate-limit middleware)가 누락된 것을 찾아낼 수는 있지만, 제한 사항을 직접 강제할 수는 없습니다.
**LLM06:2025 과도한 권한 (Excessive Agency)**는 애플리케이션 코드와 직접적으로 연관되어 있으므로 면밀히 살펴볼 가치가 있습니다. 이 카테고리는 AI 에이전트에게 너무 많은 권한(데이터베이스 쓰기 권한, 이메일 전송 능력, 임의의 셸 명령 실행 권한 등)이 부여되고, 공격자가 제어하는 입력값에 따라 해당 권한을 사용하여 동작할 때 발생하는 문제를 다룹니다. 이에 대한 완화 방법은 **최소 권한 원칙 (principle of least privilege)**입니다. 즉, 에이전트에게 필요한 특정 도구만을 부여해야 합니다.
BrassCoders는 에이전트의 기능이나 권한 범위를 모델링하지는 않습니다. 그렇게 설계되지 않았기 때문입니다. 하지만 그 밑바탕에 깔린 위험한 패턴들은 잡아냅니다. 예를 들어, 흐름 내에 사용자 입력이 포함된 subprocess.call() 호출, 제한 없는 데이터베이스 쓰기, 에이전트의 피해 범위(blast radius)를 확장시킬 수 있는 하드코딩된 자격 증명(credentials) 등이 이에 해당합니다. 이러한 것들은 코드가 사람에 의해 호출되든 에이전트에 의해 호출되든 상관없이 Pysa 및 Semgrep이 찾아내는 표준적인 보안 취약점들입니다.
실질적인 구현 순서
BrassCoders는 가장 빠른 시작점을 제공합니다. 먼저 코드 수정이 가능한 카테고리를 노출시킨 다음, 나머지 부분에 대해 런타임 제어(runtime controls)를 계층적으로 적용하십시오.
1단계: BrassCoders 실행. 먼저 LLM05:2025 탐지 결과를 노출시키십시오. 즉, HTTP 입력에서 템플릿 렌더링(template rendering) 또는 DOM 인젝션(DOM injection)으로 이어지는 오염된 흐름(taint flows)을 찾아냅니다. 이들은 구체적인 해결책이 있습니다. render_template_string()을 render_template()로 교체하고, 사용자 제어 문자열에 대한 mark_safe()를 제거하며, 사용자 제공 콘텐츠를 dangerouslySetInnerHTML에 사용하기 전에 새니타이저(sanitizer)를 거치도록 경로를 지정하는 것입니다. 각 탐지 결과는 한 줄의 코드 변경으로 매핑됩니다.
동시에 소스 코드 내의 LLM01:2025 노출 여부를 검토하십시오. 콘텐츠 필터 없이 request.body가 모델 API 호출로 직접 전달되는 경로를 찾아보십시오. 이는 프롬프트 인젝션(prompt injection) 탐지 결과는 아니지만, 이러한 입력 경로를 강화함으로써 공격 표면(attack surface)을 줄일 수 있습니다.
2단계: 에이전트 설계 시 LLM06:2025를 해결하세요. 에이전트가 호출할 수 있는 도구(tools)를 감사(Audit)하십시오. 만약 에이전트가 데이터베이스, 이메일 시스템 또는 파일 시스템에 대한 쓰기 권한(write access)을 가지고 있다면, 해당 권한을 기능에 필요한 최소한의 범위로 제한하십시오. 이는 스캔 결과가 아닌 설계 결정(design decision)의 문제이지만, 과도한 권한 부여(excessive agency)를 막기 위한 가장 영향력 있는 통제 수단입니다.
3단계: 나머지 카테고리에 대한 런타임 통제(runtime controls)를 구축하세요. LLM10:2025 무제한 소비(Unbounded Consumption)는 게이트웨이(gateway)에 토큰 예산(token budget)과 속도 제한기(rate limiter)를 필요로 합니다. LLM07:2025 시스템 프롬프트 유출(System Prompt Leakage)은 코드 리뷰가 아닌 적대적 프롬프트(adversarial prompts)를 통한 레드팀(red-teaming) 방식으로 배포된 시스템을 테스트해야 합니다. LLM08:2025 벡터 및 임베딩 취약점(Vector and Embedding Weaknesses)은 검색 인덱스(retrieval index)에 대한 접근 제어와 인덱싱된 문서에 대한 출처 추적(provenance tracking)을 필요로 합니다.
4단계: LLM09:2025 잘못된 정보(Misinformation)를 제품 품질 리스크로 취급하세요. 근거 제시(Grounding, 인용된 출처를 포함한 검색 증강 생성(RAG)), 신뢰도 임계값(confidence thresholds), 그리고 인간 검토 워크플로(human review workflows)가 여기서 사용되는 도구들입니다. 그 어떤 스캐너도 이 계층에는 기여할 수 없습니다.
2025 OWASP LLM Top 10은 처음부터 끝까지 읽어볼 가치가 있습니다. 각 카테고리에 대한 완화(mitigations) 섹션은 구체적이고 실행 가능합니다. OWASP GenAI Security Project는 genai.owasp.org/llm-top-10/에서 가이드가 포함된 전체 목록을 게시합니다.
BrassCoders를 설치하고 LLM 애플리케이션 코드베이스에 실행하여 코드 수정이 가능한 카테고리를 찾아내세요:
pip install brasscoders
brasscoders scan /path/to/your/project
스캔 결과는 AI 어시스턴트가 직접 분류(triage)할 수 있는 YAML 보고서를 생성합니다. LLM05:2025 탐지 결과에는 오염 경로(taint path) — 소스(source), 싱크(sink), 그리고 특정 보간(interpolation) 또는 렌더링 호출 — 가 포함되어 있어, 파일을 열기 전에 수정 사항이 명확해집니다. BrassCoders 유료 플랜(개발자당 월 $12)은 원시 스캔 노이즈를 주의가 필요한 탐지 결과로 줄여주는 AI 기반 강화(enrichment) 단계를 추가로 제공합니다. 자세한 내용은 coppersun.dev/pricing에서 확인하세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기