과도한 위임
더 많은 작업
- Excessive Agency; 과도한 위임
- LLM 애플리케이션에 필요 이상의 기능·권한·자율성을 주어, 모델이 잘못된 출력을 내면 그대로 해로운 행동으로 이어지는 취약점
과도한 위임(Excessive Agency)은 대형 언어 모델(LLM)에 연결된 도구(확장, 플러그인, 스킬)가 지나치게 많은 일을 할 수 있어서, 모델이 환각을 일으키거나 프롬프트 인젝션에 속았을 때 피해가 실제 행동으로 번지는 취약점이다. 원인이 무엇이든 모델의 출력은 틀릴 수 있다고 보고, 틀렸을 때 할 수 있는 일의 범위를 줄이자는 관점이다.[1]
OWASP Top 10 for LLM Applications의 항목 이름으로, 2023년판에서 LLM08이었고[2] 2025년판에서 LLM06, 2026년판에서 LLM03으로 올라왔다.[3] 에이전트가 늘면서 비중이 커진 위험이다. "과도한 위임"은 OWASP 2025년판 공식 한국어판(2025년 6월)의 표기이고, "과도한 에이전시"라고도 쓴다.
| 원인 | 뜻 | 예 |
|---|---|---|
| 과도한 기능 | 필요 없는 기능이 있는 도구를 준다 | 문서를 읽기만 하면 되는데 수정·삭제도 되는 도구를 붙인다. 시험용으로 붙였다가 쓰지 않게 된 도구가 남아 있다. 특정 셸 명령 하나만 필요한데 모든 명령을 실행하는 도구를 준다 |
| 과도한 권한 | 도구가 하위 시스템에 필요 이상으로 접근한다 | 조회만 하는 도구가 쓰기·삭제 권한이 있는 DB 계정을 쓴다. 사용자별로 동작해야 할 도구가 모든 사용자의 파일에 접근하는 공용 고권한 계정을 쓴다 |
| 과도한 자율성 | 영향이 큰 행동을 사람 확인 없이 한다 | 사용자 확인 없이 문서를 삭제한다 |
OWASP는 이것을 부적절한 출력 처리(Improper Output Handling)와 구분한다. 부적절한 출력 처리는 모델 출력을 검증 없이 SQL·HTML·셸로 넘기는 문제이고, 과도한 위임은 모델이 고른 행동을 실행하는 권한의 범위 문제다.[1]
OWASP가 드는 예는 메일 비서다. 메일을 읽어 요약하는 개인 비서 앱이 읽기와 보내기가 모두 되는 메일 도구를 쓴다. 공격자가 보낸 메일에 숨은 지시가 있으면 모델은 받은편지함에서 민감한 정보를 찾아 공격자에게 전달한다(간접 프롬프트 인젝션). 대책은 읽기 전용 메일 도구, 읽기 전용 OAuth 스코프, 초안을 사람이 검토해 직접 보내게 하는 것이다. 발송 속도 제한은 피해를 줄인다.[1]
같은 구조는 에이전트에서 더 커진다. 코딩 에이전트에 모든 셸 명령을 허용하면 저장소 파일에 숨긴 지시 하나로 임의 명령이 실행된다. 2025년 7월 아마존 Q 디벨로퍼 VS Code 확장에 몰래 들어간 코드는 에이전트를 모든 도구를 신뢰하는 비대화형 모드로 띄워 파일과 클라우드 자원을 지우라고 지시했다(문법 오류로 실행되지는 않았다).[4]
OWASP 2025년판이 권하는 대책은 다음과 같다.[1]
- 도구 수 최소화: 꼭 필요한 도구만 붙인다.
- 도구 기능 최소화: 도구 안에도 필요한 기능만 구현한다.
- 범용 도구 피하기: 셸 명령 실행 대신 "파일 쓰기" 같은 좁은 도구를 만든다.
- 권한 최소화: 도구가 쓰는 계정의 권한을 DB·시스템 권한으로 제한한다(최소 권한 원칙).
- 사용자 맥락에서 실행: 공용 계정 대신 요청한 사용자의 인가로, 최소 스코프의 OAuth 토큰으로 동작한다.
- 사용자 승인: 영향이 큰 행동은 사람이 승인한다(HITL).
- 완전한 중재: 인가 판단을 모델에 맡기지 않고 하위 시스템이 모든 요청을 정책과 대조한다.
- 입력·출력 정제: OWASP ASVS 같은 보안 코딩 기준을 따르고 SAST·DAST로 검사한다.
피해를 줄이는 보조 수단으로 도구와 하위 시스템 활동의 기록·감시, 속도 제한을 든다.
범용 도구와 좁은 도구의 차이는 다음과 같다.
import subprocess
from pathlib import Path
* 나쁜 예: 모델이 만든 문자열을 셸에 그대로 넘긴다 (과도한 기능)
def run_shell(cmd: str) -> str:
return subprocess.run(cmd, shell=True, capture_output=True, text=True).stdout
* 나은 예: 정해진 폴더 안의 텍스트 파일만 읽는다
BASE = Path("/srv/reports").resolve()
def read_report(name: str) -> str:
p = (BASE / name).resolve()
if p.parent != BASE or p.suffix != ".txt":
raise PermissionError("허용되지 않은 경로")
return p.read_text(encoding="utf-8")
에이전트 전체의 설계 방어(이중 LLM 패턴, CaMeL, 격리)는 AI 에이전트 보안 문서 참고.