범용 문서 변환기가 바이러스를 'text/plain'으로 오인하여 소스 코드를 반환한 경험
요약
범용 문서 변환기가 바이너리 파일을 'text/plain'으로 오인하여 소스 코드와 쓰레기 데이터를 반환하는 보안 취약점을 경험했습니다. 이로 인해 LLM 컨텍스트 창에 원치 않는 데이터가 유입되는 프롬프트 주입 위험이 발생할 수 있습니다. 따라서 파일 유형 감지기는 단순한 편의 기능이 아닌, 필수적인 첫 번째 방어선으로 엄격하게 수정해야 합니다.
핵심 포인트
- 파일 유형 감지기(MIME type detection)는 보안 경계입니다.
- 허용 목록(Allowlist) 기반 접근 방식이 필수적입니다.
- 바이너리 쓰레기가 LLM 임베딩에 유출될 위험을 방지하세요.
- 지원하지 않는 파일 형식은 415 Unsupported Media Type으로 처리해야 합니다.
마법 바이트(magic bytes)를 통해 파일 유형을 감지하고 적절한 변환기(converter)로 라우팅하는 단일 엔드포인트를 구축했습니다 — PDF, DOCX, PPTX, XLSX, EPUB, HTML, 일반 텍스트. 클린 아키텍처를 적용하여 하나의 URL만 사용하며 클라이언트 측 분기가 없습니다.
그러자 .js 파일이 들어왔습니다. 제 스니퍼는 ASCII를 감지하고 text/plain이라고 판단했으며, 원본 소스를 마크다운(Markdown)으로 반환했습니다. 괜찮았습니다.
다음으로 베이스64(base64)로 가득 찬 <script> 태그를 가진 .html 파일이 들어왔습니다. 이것도 괜찮았습니다.
그러다가 우연히 MZ로 시작하는 .exe 파일이 들어왔는데, 당시 제 PE 파서(PE parser)가 아직 연결되지 않아 텍스트 폴백(text fallback)으로 넘어갔습니다. 변환기는 바이너리를 UTF-8 디코딩하려고 시도했고, 디코드할 수 없는 바이트를 U+FFFD로 대체하여 마크다운 코드 블록 안에 ���가 포함된 340KB의 데이터를 반환했습니다. 이 데이터를 받은 에이전트는 이를 "대체 문자(replacement characters)에 관한 문서"라고 의기양양하게 요약했습니다.
교훈은 이었습니다: 폴백 변환기는 당신이 알지 못했던 보안 경계입니다. 허용 목록(allowlist) 없이 자동 감지를 하면, 파싱할 수 없는 모든 것이 "텍스트"가 되고, 그 텍스트는 곧바로 LLM 컨텍스트 창으로 공급됩니다. 당신은 방금 프롬프트 주입(prompt-injection) 전달 시스템을 구축했으며, 심지어 바이너리 쓰레기까지 임베딩(embeddings)에 유출하고 있는 것입니다.
수정은 지루했지만 정확했습니다: 마법 바이트를 감지하고, 지원되는 유형의 명시적 허용 목록과 일치시키며, 나머지 모든 것 — .exe, .dmg, .zip을 포함하여 첫 512바이트에 null 바이트가 있는 모든 파일까지 — 에 대해서는 415 Unsupported Media Type을 반환하도록 했습니다. 이 "범용적인(universal)" 엔드포인트는 여전히 _문서(documents)_에는 범용적입니다. 다만, 더 이상 _파일(files)_에는 범용적이지 않을 뿐입니다.
만약 에이전트를 위한 문서 수집 파이프라인(document ingestion pipeline)을 구축하고 있다면, 유형 감지기는 편의 기능 계층이 아닙니다. 그것은 첫 번째 방어선입니다. 증명될 때까지 알 수 없는 것은 적대적이라고 간주하십시오.
이 엔드포인트는 https://x402.freeq.one/tools/document_to_markdown.html에 위치하며, 이제 엄격한 허용 목록과 처리하지 않을 항목에 대한 415 응답 코드를 갖추고 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기