3장. 데이터 보호와 권한

학습 목표

  • 민감 정보가 입력부터 로그까지 데이터 수명주기의 어느 지점에서 새는지 찾아 최소화한다.
  • 과도한 대리권을 기능·권한·자율성으로 나누어 진단하고, 도구 설계로 권한을 줄인다.
  • 에이전트가 누구의 권한으로 실행되는지 정하고, 위임 토큰과 범위를 최소화한다.
  • 모델 출력을 신뢰하지 않는 입력으로 다루어, 도착지에 맞게 안전하게 렌더링하고 처리한다.
  • 시스템 프롬프트와 벡터 저장소에 대한 흔한 오해를 바로잡는다.

들어가며

어느 쇼핑몰의 상담 챗봇은 질문에 정확히 답하려고 고객 계정 전체를 조회하는 도구를 썼습니다. 배송 문의 하나에 주소, 전화번호, 최근 주문 열 건, 적립금 내역까지 컨텍스트로 들어왔습니다. 대부분의 날에는 아무 문제가 없었습니다. 그러다 한 고객이 가족과 공유하는 계정에서 "지난달 주문 목록을 다 보여 줘"라고 묻자, 챗봇은 친절하게 다른 가족 구성원의 주문까지 펼쳐 보였습니다. 모델은 실수하지 않았습니다. 받은 데이터를 성실하게 정리했을 뿐입니다. 팀은 서둘러 프롬프트에 "다른 사람의 정보는 말하지 말라"는 문장을 넣었지만, 같은 계정을 쓰는 가족 가운데 누가 지금 묻고 있는지 모델은 알 길이 없었습니다. 해결책은 프롬프트가 아니라 조회 도구에 있었습니다.

2장이 "공격자의 지시가 어떻게 들어오는가"를 다뤘다면, 이 장은 "들어왔을 때 무엇까지 할 수 있는가"를 다룹니다. 모델은 컨텍스트에 들어온 것을 말할 수 있고, 손에 쥔 도구로 할 수 있는 일을 합니다. 그래서 데이터와 권한을 줄이는 일이 인젝션 대책의 절반입니다. 이 장은 민감 정보의 경로와 최소화에서 시작해 외부 AI 서비스의 데이터 조건, 시스템 프롬프트와 벡터 저장소, 과도한 대리권과 도구 권한 설계, 위임과 신원을 차례로 다루고, 마지막으로 모델 출력을 안전하게 렌더링하고 처리하는 법을 배웁니다.

핵심 개념

민감 정보는 어디서 새는가: 데이터 수명주기

OWASP LLM02(Sensitive Information Disclosure)는 개인정보, 금융 정보, 건강 기록, 기밀 업무 데이터, 자격 증명, 법률 문서가 모델 출력을 통해 드러나는 위험을 다룹니다. 사용자가 입력한 데이터가 나중에 모델 출력에 다시 나타날 수 있다는 점도 함께 지적합니다. 최종 답변만 보면 놓치는 지점이 많으므로 수명주기 전체를 따라갑니다.

단계 새는 모습 기본 통제
입력 수집 사용자가 주민등록번호나 비밀번호를 그대로 입력 입력 안내, 패턴 탐지와 가림
컨텍스트 조립 필요 이상의 레코드와 필드를 넣음 필드 단위 조회 도구
외부 모델 호출 외부 공급자에게 원문 전송 가림·가명 처리, 계약 조건 확인
도구 인자 모델이 민감 값을 다른 도구에 넘김 인자 검증, 목적지 제한
출력 다른 사용자나 다른 가족 구성원의 정보 노출 서버 측 인가, 출력 검사
로그·캐시 원문 대화가 로그와 캐시에 남음 로그 가림, 보존 기간(5장)
파생 데이터 요약·임베딩·미세조정 데이터에 남음 학습 전 정제, 파생물 삭제 절차

OWASP는 시스템 프롬프트로 "이런 데이터는 돌려주지 말라"고 제한하는 방법이 도움은 되지만 항상 지켜지지 않고 인젝션으로 우회될 수 있다고 경고합니다. 가장 확실한 보호는 모델에게 애초에 보여 주지 않는 것입니다.

최소화·가림·가명 처리

데이터 최소화는 "업무에 필요한 필드만 필요한 순간에 넘긴다"는 원칙입니다. 배송 문의에는 배송 상태와 예정일이 필요하지 주소 전체가 필요하지 않습니다. 이 원칙은 프롬프트가 아니라 도구 설계로 구현합니다. 고객 레코드 전체를 돌려주는 도구 대신 "이 주문의 배송 상태"만 돌려주는 도구를 만듭니다. 국내 개인정보의 안전성 확보조치 기준도 개인정보를 출력할 때 용도를 특정하고 용도에 따라 출력 항목을 최소화하라고 요구합니다. LLM 컨텍스트로 넘기는 일도 같은 정신으로 설계하면 됩니다.

넘길 수밖에 없는 값은 가립니다.

방법 하는 일 쓰는 곳
가림(redaction) 값을 지우거나 별표로 바꿈 로그, 모델이 값을 알 필요가 없을 때
토큰화 값을 의미 없는 대체 문자열로 바꾸고 대응표를 따로 보관 모델이 "같은 사람"임만 알면 될 때
가명 처리 추가 정보 없이는 특정 개인을 알아볼 수 없게 바꿈 분석, 미세조정 데이터 준비

토큰화를 쓰면 대응표가 새로운 핵심 자산이 됩니다. 대응표는 모델과 같은 저장소에 두지 않고, 암호화해 보관하며 접근을 따로 통제하고 기록합니다. 외부로 보내기 전에 가리고, 응답을 받은 뒤 필요한 곳에서만 원래 값으로 되돌립니다.

외부 AI 서비스로 보내는 데이터의 조건

외부 공급자의 모델을 쓰면 데이터가 조직의 경계를 넘습니다. 확인할 질문은 학습에 쓰이는가, 오남용 감시를 위해 얼마나 보관되는가, 애플리케이션 상태(대화, 파일, 벡터 저장소)는 언제까지 남는가, 보관을 줄이는 옵션은 어떤 조건으로 쓸 수 있는가, 어느 지역에 저장되는가입니다.

OpenAI의 데이터 통제 문서를 예로 들면 다음과 같습니다. API로 보낸 데이터는 사용자가 명시적으로 동의하지 않는 한 모델 학습에 쓰이지 않습니다. 오남용 감시 로그는 최대 30일 보관되지만, 법이 요구하거나 서비스와 제3자를 해로부터 보호하는 데 필요하면 더 오래 보관될 수 있습니다. 데이터 보관을 줄이는 Zero Data Retention과 Modified Abuse Monitoring은 사전 승인을 받아야 쓸 수 있습니다. 일부 기능은 사용자가 지울 때까지 애플리케이션 상태를 보관합니다. 조건은 기능과 계약마다 다르므로 공식 문서와 계약서를 기능 단위로 확인하고 확인 날짜를 기록합니다. 국외 공급자에게 개인정보를 보낸다면 개인정보 보호법 제28조의8의 국외 이전 요건(별도 동의 또는 법이 정한 예외)도 개인정보 보호 책임자와 함께 확인합니다.

시스템 프롬프트는 비밀이 아니다

OWASP LLM07의 핵심 문장은 "시스템 프롬프트를 비밀로 간주하거나 보안 통제로 써서는 안 된다"입니다. 같은 문서는 프롬프트 문구가 드러나는 것 자체보다, 그 안에 둔 민감 정보와 권한 구조가 진짜 위험이라고 설명합니다.

프롬프트에 두면 안 되는 것 드러나면 생기는 일 둘 곳
API 키, 데이터베이스 접속 정보 다른 시스템 직접 접근 비밀값 저장소, 서버 설정
거래 한도, 승인 규칙 한도 바로 아래로 쪼개 요청 서버 측 정책 엔진
필터링 기준 필터를 피하는 표현 탐색 별도 가드레일
사용자 역할과 권한 구조 권한 상승 시도 인가 시스템

권한 분리와 인가 검사는 모델 밖에서 결정적이고 감사 가능한 방식으로 수행합니다. 접근 수준이 다른 작업은 최소 권한을 가진 에이전트 여럿으로 나눕니다. 목표는 "프롬프트가 통째로 공개되어도 아무 일이 일어나지 않는 설계"입니다. OWASP 2026년판은 이 항목을 숨은 컨텍스트 노출(LLM08:2026 Hidden Context Exposure)로 넓혀 개발자 지시, 검색해 넣은 정책 문구, 도구 스키마까지 같은 원칙으로 다룹니다.

RAG와 벡터 저장소의 권한

OWASP LLM08(Vector and Embedding Weaknesses)은 벡터 저장소의 위험으로 접근 통제 실패와 데이터 유출, 여러 사용자 집단이 한 저장소를 공유할 때의 교차 문맥 유출, 임베딩에서 원문을 상당 부분 복원하는 임베딩 역변환, 색인 데이터 오염을 듭니다. 완화책은 권한을 인식하는 벡터 저장소와 엄격한 분할, 지식 출처의 검증, 결합 데이터의 검토와 분류, 검색 활동의 변경 불가능한 로그입니다.

설계 원칙은 "권한은 생성 전에, 검색 단계에서 적용한다"입니다. 권한 없는 문서를 모델이 읽은 뒤 "이 문서는 말하지 말라"고 지시하는 방식은 프롬프트를 통제로 쓰는 실수입니다. 검색 질의 자체에 요청자의 권한 조건을 붙이는 사전 필터링으로 애초에 허용된 조각만 돌려받습니다. 문서의 권한이 바뀌거나 문서가 삭제되면 색인의 조각과 캐시도 함께 갱신해야 합니다. 원본에서 지운 문서가 색인에 남아 계속 검색되는 일이 흔합니다. 임베딩도 원문만큼 민감한 데이터로 다루세요. 숫자 배열이라는 사실이 보호 수단은 아닙니다.

과도한 대리권: 세 뿌리와 여덟 가지 예방책

OWASP LLM06(Excessive Agency)은 예상치 못한, 모호한, 또는 조작된 모델 출력에 대응해 해로운 행동이 실행될 수 있게 만드는 취약점입니다. 원인이 환각이든 인젝션이든 상관없이, 모델이 잘못 판단했을 때 무엇까지 일어나는지가 핵심입니다. 뿌리는 셋입니다.

뿌리 예 고치는 법
과도한 기능 문서 읽기 도구에 수정·삭제 기능까지 있음, 시험하다 남겨 둔 도구 필요한 기능만 가진 도구, 안 쓰는 도구 제거
과도한 권한 읽기만 필요한데 쓰기 권한, 모든 사용자 데이터에 닿는 공용 고권한 계정 읽기 전용 권한, 사용자 맥락 실행
과도한 자율성 영향이 큰 행동을 독립 검증이나 사용자 확인 없이 실행 사용자 승인

2025년판이 제시하는 예방책은 여덟 가지입니다. 확장 기능(도구) 수 줄이기, 도구마다 기능 줄이기, 범용 도구 피하기, 도구 권한 줄이기, 사용자 맥락에서 실행하기, 사용자 승인 받기, 완전한 중재, 입출력 정제입니다. 2026년판(LLM03:2026)은 입출력 정제를 이 목록에서 빼고 일곱 가지로 정리했습니다. 로깅·모니터링과 요청률 제한은 피해 규모를 줄이지만 과도한 대리권 자체를 예방하지는 못한다고 따로 분류합니다.

완전한 중재(complete mediation)는 "허용 여부는 모델이 아니라 하위 시스템이, 요청마다 판단한다"는 원칙입니다. 출입증 검사를 안내 직원의 기억이 아니라 출입문 장치가 하는 것과 같습니다. 모델은 출입증을 위조할 수는 없어도 안내 직원을 설득할 수는 있습니다.

도구 권한 최소화를 설계로 옮기기

도구 권한 최소화는 원칙이 아니라 도구 명세로 나타나야 합니다. OWASP AI Agent Security Cheat Sheet는 도구별로 읽기와 쓰기, 대상 자원을 나누어 권한을 정하고, 신뢰 수준이 다른 에이전트에는 서로 다른 도구 묶음을 주고, 알 수 없는 도구나 승인 요건이 빠진 경우에는 닫힌 쪽으로 실패(fail closed)하라고 권합니다.

설계 수단 예
조회와 변경 분리 get_order_status와 request_refund를 별도 도구로
열린 도구 대신 목적형 도구 범용 셸 대신 run_test_suite, 임의 URL 가져오기 대신 허용 도메인 검색
인자 제약 스키마에 열거형·범위·형식을 두고, 서버가 다시 검증
대상 제한 수신자 허용 목록, 금액 상한, 하루 호출 횟수
짧은 수명의 자격 증명 작업 단위로 발급하고 끝나면 폐기
기본 거부 목록에 없는 도구·인자·대상은 실행하지 않음
{
  "name": "reschedule_my_booking",
  "description": "로그인한 사용자 본인의 예약 한 건의 날짜를 바꾼다. 실행 전 사용자 확인이 필요하다.",
  "input_schema": {
    "type": "object",
    "properties": {
      "booking_id": { "type": "string", "pattern": "^BK-[0-9]{8}$" },
      "new_date": { "type": "string", "format": "date" }
    },
    "required": ["booking_id", "new_date"],
    "additionalProperties": false
  }
}

스키마는 모델이 엉뚱한 모양의 인자를 만들지 않도록 돕는 장치이고, 진짜 통제는 서버에 있습니다. 서버는 이 예약이 로그인한 사용자의 것인지, 새 날짜가 허용 범위인지, 사용자가 확인했는지를 요청마다 다시 검사합니다.

위임과 신원: 누구의 권한으로 실행되는가

에이전트가 사용자를 대신해 다른 시스템을 호출할 때는 "누구의 권한으로"가 분명해야 합니다. 모든 호출이 강한 권한의 공용 서비스 계정으로 나가면, 모델을 속인 사용자는 그 계정이 닿는 모든 데이터에 닿고 로그에는 요청자가 남지 않습니다. OWASP Agentic Top 10은 에이전트에 관리되는 자기 신원이 없으면 진정한 최소 권한을 강제할 수 없다며 이를 ASI03(Identity and Privilege Abuse)의 원인으로 듭니다. OWASP LLM06은 사용자를 대신한 행동을 그 사용자의 맥락에서 최소 권한으로, 예컨대 필요한 최소 범위의 OAuth 인증으로 실행하라고 합니다. MCP 보안 모범 사례는 위임 구조의 함정을 구체적으로 짚습니다.

함정 MCP 문서의 요구
토큰 그대로 넘기기(token passthrough) 받는 토큰의 대상(audience)이 이 MCP 서버인지 확인하고, 다른 곳을 위해 발급된 토큰은 거부한다. 인가 사양은 이 패턴을 명시적으로 금지한다
혼동된 대리인(confused deputy, 권한 있는 중계자가 속아 남 대신 권한을 쓰는 문제) 제3자 API를 중계하는 MCP 프록시 서버는 클라이언트별 동의를 구현해야 한다
상태 핸들 탈취 상태 핸들을 가졌다는 사실을 인증으로 취급해서는 안 되며, 핸들을 서버에서 인증된 사용자에게 묶는다
넓은 범위 최소 범위로 시작해 필요할 때 단계적으로 올리고, 와일드카드·통합 범위를 피한다

토큰을 그대로 넘기면 하위 API의 요청률 제한과 감사 기록이 무력해지고, 토큰을 훔친 사람이 중계 서버를 유출 통로로 쓸 수 있습니다. 넓은 범위를 처음부터 받아 두면 토큰 하나가 새는 순간 모든 도구가 열립니다.

출력은 신뢰하지 않는 입력이다

OWASP LLM05(Improper Output Handling)는 모델 출력을 하위 구성 요소로 넘기기 전에 검증·정제·처리하지 않는 결함입니다. 프롬프트로 출력을 조종할 수 있으므로, 출력을 그대로 쓰는 것은 사용자에게 하위 기능에 대한 간접 접근을 주는 것과 같습니다. OWASP는 모델을 "다른 사용자처럼" 대하는 제로 트러스트 접근을 권합니다.

출력이 가는 곳 위험 기본 통제
브라우저(HTML, 마크다운) XSS, 외부 요청을 통한 반출 문맥별 인코딩, 정화, CSP
데이터베이스 SQL 인젝션 매개변수화된 쿼리
셸, eval, 템플릿 엔진 원격 코드 실행 실행하지 않기, 불가피하면 샌드박스
파일 경로 경로 조작 정규화와 허용 디렉터리
메일 템플릿 피싱 이스케이프
스프레드시트로 내보내는 CSV 수식 실행 셀이 수식 문자로 시작하지 않게 처리

모델의 특권이 사용자보다 클 때, 간접 인젝션에 취약할 때, 출력이 문맥에 맞게 인코딩되지 않을 때 영향이 커집니다. 모델이 지어낸 패키지 이름으로 공격자가 올린 악성 패키지를 설치하는 위험도 OWASP가 이 항목과 LLM09에서 다룹니다.

출력의 안전한 렌더링

모델 출력을 화면에 그리는 일은 사용자 입력을 화면에 그리는 일과 같은 규칙을 따릅니다. OWASP XSS Prevention Cheat Sheet의 원칙을 LLM 출력에 적용하면 다음과 같습니다.

  1. 기본은 텍스트로 그립니다. innerHTML 대신 textContent처럼 데이터를 텍스트로만 다루는 방식을 씁니다.
  2. 서식이 꼭 필요하면 마크다운 렌더러에서 원시 HTML을 끄고, 허용 목록 기반 정화기로 결과를 거릅니다. OWASP는 HTML 정화에 DOMPurify를 권합니다.
  3. 프레임워크의 이스케이프 우회 기능(React의 dangerouslySetInnerHTML 등)은 정화 없이 쓰지 않습니다.
  4. 링크와 이미지는 허용 목록으로 묶습니다. 외부 이미지를 자동으로 불러오지 않으면 이미지 주소에 데이터를 실어 보내는 반출 통로가 막힙니다. 링크는 스킴(javascript: 등)과 도메인을 검사하고, 필요하면 클릭 전에 실제 주소를 보여 줍니다.
  5. CSP(Content Security Policy)는 추가 방어층입니다. OWASP는 CSP를 주된 방어 수단으로 삼지 말라고 합니다.
  6. 스트리밍 출력은 조각이 다 모이기 전에 렌더링되므로, 정화를 거치지 않은 중간 결과가 화면에 그려지지 않는지 확인합니다.
<!-- 나쁜 예: 모델 출력을 그대로 HTML로 해석 -->
<div id="answer"></div>
<script>answer.innerHTML = modelOutput;</script>

<!-- 나은 예: 텍스트로 그리고, 서식은 정화된 결과만 -->
<script>answer.textContent = modelOutput;</script>

모델이 고른 주소와 코드: SSRF와 코드 실행

모델이 만든 값으로 서버가 요청을 보내거나 코드를 실행하면 출력 처리의 위험이 서버 안쪽으로 들어옵니다. 모델이 고른 URL을 서버가 그대로 가져오면, 인젝션으로 그 URL이 내부 관리 페이지나 클라우드 메타데이터 주소로 바뀔 수 있습니다. 서버 측 요청 위조(SSRF, Server-Side Request Forgery)입니다. MCP 보안 모범 사례는 OAuth 관련 URL을 가져오는 클라이언트에 대해 운영 환경에서는 HTTPS를 요구하고, 사설·루프백·링크 로컬 주소 대역을 막고, 리디렉션 대상도 같은 기준으로 검사하고, 내부 목적지를 막는 이그레스 프록시를 쓰라고 권합니다. IP 검증을 직접 구현하지 말라는 경고도 덧붙입니다. 인코딩 속임수를 놓치기 쉽기 때문입니다. 이 원칙은 모델이 URL을 고르는 모든 도구에 그대로 적용됩니다.

모델이 생성한 코드나 명령을 충분한 검증과 격리 없이 실행하면 OWASP Agentic Top 10의 ASI05(Unexpected Code Execution) 위험으로 이어집니다. 기본 원칙은 "실행하지 않을 수 있으면 실행하지 않는다"이고, 실행해야 한다면 권한이 최소인 전용 컨테이너나 가상 머신에서, 네트워크와 파일 접근을 제한하고, 비밀값 없이 돌립니다. Anthropic의 컴퓨터 사용 도구 문서도 권한이 최소인 전용 가상 머신이나 컨테이너, 도메인 허용 목록, 로그인 정보 같은 민감 데이터의 격리를 예방 조치로 듭니다.

깊이 읽기

승인과 실행을 묶기

사람 확인을 두어도 "사용자가 본 것"과 "실제로 실행되는 것"이 다르면 확인은 의미를 잃습니다. 승인 화면에는 "회의 일정 변경"이라고 보였는데 실제 호출 인자에는 참석자 열 명이 추가되어 있을 수 있습니다. 또 긴 작업 도중에 사용자의 권한이 회수되었는데, 작업 시작 때 받은 승인으로 끝까지 실행되기도 합니다. 검사 시점과 사용 시점이 어긋나는 문제(TOCTOU, Time-of-Check to Time-of-Use)입니다.

실행에 묶인 승인은 다음을 갖춥니다. 승인 요청에 대상, 인자, 예상 효과를 원래 값으로 담습니다. 승인은 그 인자의 해시와 함께 저장하고, 실행 직전 인자가 같은지 비교해 다르면 다시 묻습니다. 승인에는 유효 시간과 1회 사용 제한을 둡니다. 그리고 실행 직전에 사용자의 현재 권한을 다시 확인합니다. OWASP AI Agent Security Cheat Sheet가 권하는 "실행 전 행동 미리 보기"와 "되돌리기"도 이 설계와 함께 갑니다.

파생 데이터의 격리: 캐시·메모리·요약·내보내기

원본 저장소의 권한이 완벽해도 파생 경로에서 데이터가 섞입니다. 응답 캐시의 키에 사용자나 조직 식별자가 빠지면, 비슷한 질문을 한 다른 조직이 앞 조직의 답을 받습니다. 공용 요약을 여러 팀이 재사용하면 요약에 녹아든 기밀이 권한 없는 팀에게 갑니다. 대화 내보내기와 공유 링크는 원래 대화의 권한 검사를 거치지 않는 경우가 많습니다.

점검 질문은 하나입니다. "이 파생물은 원본의 권한 경계를 물려받는가?" 캐시 키, 메모리 저장소, 요약 저장소, 내보내기 파일, 임베딩 색인마다 이 질문에 답하고, 답이 "아니오"인 곳에는 사용자·조직 범위를 붙이거나 재사용을 막습니다. OWASP AI Agent Security Cheat Sheet도 사용자와 세션 사이의 메모리 격리를 별도 항목으로 둡니다.

실무 장면

온새미로병원: 예약 에이전트에게서 진료 기록을 거둔 이유

종합병원 '온새미로병원'은 진료 예약 에이전트를 도입하려 한다. 초안 설계에서 에이전트는 병원 전체 환자 DB에 읽기·쓰기 권한이 있는 서비스 계정을 쓰고, 답변 품질을 위해 환자의 최근 진료 기록 전체를 컨텍스트에 넣으며, 예약 변경을 바로 실행했다. 앱 화면에는 에이전트가 쓴 안내문이 HTML로 그려졌고, 시스템 프롬프트에는 내부 예약 API 주소와 키가 들어 있었다.

보안 검토자는 세 뿌리로 진단했다. 기능 면에서 예약에 진료 기록 조회가 필요한지 물었고, 필요한 것은 예약 가능 시간과 환자 본인의 예약 목록뿐이라는 답을 얻었다. 진료 기록 조회 도구는 뺐다. 권한 면에서는 쓰기 권한을 예약 테이블로 줄이고, 호출은 로그인한 환자 본인의 토큰으로 수행하게 했다. 예약 서버가 요청마다 "이 환자가 이 예약을 바꿀 수 있는가"를 직접 검사한다. 자율성 면에서는 예약 취소와 다른 진료과로의 변경은 환자가 날짜·진료과·의료진을 화면에서 확인한 뒤에만 실행되게 했다.

출력과 비밀값도 점검했다. 안내문은 텍스트로 그리되 굵은 글씨와 목록만 허용하는 정화기를 거치고, 링크와 이미지는 병원 도메인만 허용했다. 시스템 프롬프트에 있던 API 주소와 키는 서버 설정과 비밀값 저장소로 옮기고, 이미 프롬프트에 노출되었던 키는 폐기 후 재발급했다.

"진료 기록이 있어야 의사 추천을 잘한다"는 반론에는 진료과와 담당 의사 두 필드만 돌려주는 도구로 답했다. 결과적으로 에이전트가 속더라도 할 수 있는 일은 "본인 예약을 보여 주고, 확인을 받아 바꾸는 것"으로 줄었다. 위험 등록부에는 잔여 위험으로 "확인 화면에서 환자가 내용을 읽지 않고 승인"을 적고, 취소 후 24시간 이내 되돌리기 기능을 다음 분기 과제로 남겼다.

고래마켓: 한 문장이 세 곳에서 다르게 위험하다

중고 거래 플랫폼 '고래마켓'은 판매자가 사진과 짧은 메모를 올리면 모델이 판매글 제목과 설명을 써 주는 기능을 만들었다. 모델이 쓴 설명은 세 곳으로 간다. 공개 판매글 페이지에 마크다운으로 렌더링되고, 운영팀의 검수 화면에 표시되고, 매주 운영 보고용 CSV로 내보내져 스프레드시트에서 열린다.

베타 기간에 두 가지가 발견되었다. 한 판매자가 메모에 넣은 HTML 조각을 모델이 설명에 그대로 옮겨 적어, 검수 화면에서 서식이 깨지고 스크립트 태그가 화면에 그대로 섞여 나왔다. 다행히 검수 화면이 텍스트로 그리고 있어서 실행되지는 않았다. 또 일부 설명에는 판매자가 메모로 유도한 외부 결제 사이트 링크가 들어갔다. 운영팀은 "모델에게 HTML과 링크를 쓰지 말라고 지시하자"고 제안했다.

보안 담당자는 그 지시를 보조 수단으로만 받아들이고 도착지마다 통제를 따로 걸었다. 공개 페이지는 원시 HTML을 끈 마크다운 렌더러와 허용 목록 정화기를 거치고, 링크는 플랫폼 도메인만 남기며, 이미지는 플랫폼에 올린 사진만 표시한다. 검수 화면은 텍스트로 그리되 원래 메모와 모델 설명을 나란히 보여 준다. CSV 내보내기에서는 수식 문자로 시작하는 셀 앞에 작은따옴표나 탭을 붙여 텍스트로 해석되게 했고, 스프레드시트마다 동작이 달라 보편적인 정화 방법이 없다는 OWASP의 경고에 따라 운영팀이 실제로 쓰는 프로그램으로 결과를 시험했다.

교훈은 "같은 출력이라도 도착지마다 위험과 통제가 다르다"는 것이다. 모델 지시 한 줄에 기댔다면 지시가 무시되는 날 세 곳이 동시에 열렸을 것이다.

자주 틀리는 지점

  1. "프롬프트에 금지 규칙을 쓰면 권한 통제가 된다." 규칙을 지키는 주체가 여전히 모델입니다. 허용 여부는 하위 시스템이 요청마다 판단해야 합니다.
  2. "자사 모델이 만든 출력이니 믿어도 된다." 출력은 모델이 읽은 외부 콘텐츠와 사용자 입력을 반영합니다. 렌더링과 실행 전에 사용자 입력과 똑같이 다룹니다.
  3. "사용자에게 안 보이니 시스템 프롬프트에 키를 둬도 된다." 보이지 않는다는 것은 보호 수단이 아닙니다. 키는 모델이 직접 닿지 않는 곳에 둡니다.
  4. "정확도를 위해 데이터를 많이 넣을수록 좋다." 넣는 만큼 노출면이 커집니다. 필요한 필드만 돌려주는 도구를 만드세요.
  5. "임베딩은 숫자라서 안전하다." 임베딩 역변환으로 원문의 상당 부분이 복원될 수 있습니다. 원문과 같은 수준으로 접근을 통제합니다.
  6. "로깅과 요청률 제한을 넣었으니 과도한 대리권은 해결되었다." OWASP는 이 둘을 피해를 줄이는 수단으로 분류합니다. 예방은 기능·권한·자율성을 줄이는 쪽입니다.
  7. "스키마 검증을 통과했으니 안전한 인자다." 형식이 맞아도 대상과 금액이 틀릴 수 있습니다. 업무 규칙과, 요청마다 그 객체에 대한 접근 권한을 서버가 다시 확인합니다(OWASP Authorization Cheat Sheet).
  8. "CSP가 있으니 출력 인코딩은 생략해도 된다." CSP는 추가 방어층입니다. 문맥별 인코딩과 정화가 먼저입니다.

한눈에 정리

주제 기억할 문장
민감 정보 모델은 본 것을 말한다. 보여 주지 않는 것이 가장 확실하다
최소화 필드 단위 도구로, 외부 전송 전에 가린다
외부 공급자 학습 사용, 보관 기간, 상태 보관, 승인 조건을 기능 단위로 확인한다
시스템 프롬프트 비밀이 아니며 통제가 아니다
RAG 권한은 검색 단계에서, 삭제와 권한 변경은 색인까지
과도한 대리권 기능·권한·자율성, 완전한 중재
도구 설계 조회·변경 분리, 목적형 도구, 인자 제약, 기본 거부
위임 사용자 맥락, 최소 범위, 토큰 그대로 넘기기 금지
출력 처리 모델은 신뢰하지 않는 사용자, 도착지별 통제
렌더링 텍스트 우선, 정화, 링크·이미지 허용 목록, CSP는 보조
SSRF·코드 실행 모델이 고른 주소는 검증, 코드는 격리된 곳에서만

공식 문서로 확인하기

셀프 체크

3-1. 최종 답변 말고 민감 정보가 남거나 새는 수명주기 지점 세 곳을 들고, 각 지점의 기본 통제를 하나씩 쓰라.

3-2. OWASP LLM06이 예방책과 구분해 "피해 규모를 줄이는 수단"으로 분류하는 두 가지는 무엇이며, 왜 예방책이 아닌가?

3-3. 완전한 중재 원칙을 한 문장으로 정의하고, 이 원칙을 어긴 설계의 예를 하나 들라.

3-4. 외부 LLM API 공급자의 데이터 조건을 검토할 때 기능 단위로 확인해야 할 항목 네 가지를 쓰라.

3-5. 모델 출력을 웹 화면에 그릴 때의 기본 방식, 서식 있는 HTML이 꼭 필요할 때의 방식, 그리고 CSP가 이 둘과 맺는 관계를 각각 한 문장으로 쓰라.

3-6. MCP 보안 모범 사례가 상태 핸들에 대해 금지하는 것은 무엇이며, 대신 서버가 해야 할 일은 무엇인가?

3-7. 설계 과제: 직원의 일정을 읽고 회의실을 예약해 주는 사내 비서가 있다. 이 비서가 쓸 도구를 세 개 이내로 설계하고, 도구마다 기능·권한·사용자 확인 여부를 한 줄씩 적어라.

실습 과제

실습

도구 권한 축소안 쓰기 (40분)

  1. 에이전트나 챗봇이 쓰는 도구를 모두 나열하고, 도구마다 기능·권한·자율성(확인 없이 실행되는가)과 실행 신원(공용 계정인가 사용자 맥락인가)을 표로 적는다.
  2. 실제 업무에 필요한 최소 기능과 권한을 옆 열에 적는다.
  3. 차이가 나는 칸마다 "목적형 도구로 교체", "조회·변경 분리", "읽기 전용", "사용자 맥락 실행", "인자·대상 제한", "사람 승인" 가운데 무엇으로 줄일지 고른다.
  4. 시스템 프롬프트에 비밀값, 한도, 권한 구조가 들어 있는지 찾아 목록으로 남기고 옮길 곳을 적는다.

완료 기준: 도구 하나 이상에서 기능이나 권한이 실제로 줄었고, 프롬프트 속 비밀값을 0건으로 만드는 계획이 있다.

실습

모델 출력 도착지 점검표 만들기 (35분)

  1. 모델 출력이 가는 곳을 모두 적는다(웹 화면, 관리자 화면, 메일, DB, 파일, 내보내기, 다른 도구의 인자).
  2. 도착지마다 "출력이 무엇으로 해석될 수 있는가"(HTML, SQL, 셸, 경로, 수식, URL)를 적는다.
  3. 도착지마다 지금 적용된 통제와 이 장의 기본 통제를 비교하고, 빠진 통제를 표시한다.
  4. 가장 위험한 도착지 하나에 대해, 모델이 위험한 출력을 냈다고 가정한 시험 입력을 가짜 데이터로 하나 만들고 기대 결과를 적는다.

완료 기준: 도착지가 세 곳 이상 정리되어 있고, 모든 도착지에 모델 지시와 무관하게 작동하는 통제가 하나 이상 적혀 있다.