고객 문서를 요약하는 에이전트가 그 문서 안의 지시를 따라 메일을 보낸다면, 문제는 요약 품질에만 있지 않습니다. 신뢰하지 않는 입력을 읽는 모델과 외부 시스템을 바꾸는 도구 사이에 어떤 경계가 있는지가 문제입니다.
GitHub는 10월 28일 공개 프리뷰에서 간접 프롬프트 인젝션, 민감정보 노출, 과도한 에이전트 권한을 PR에서 탐지한다고 발표했습니다. github.com의 GitHub Advanced Security 라이선스와 관련 스캔 설정이 필요하며, Enterprise Server에는 아직 제공되지 않습니다. 이 글은 10월 29일 문서 검토입니다.
CodeQL·AI Scan과 같은 이름으로 묶지 않는다
공식 문서는 AI applications scanning을 CodeQL 및 일반적인 코드 취약점을 찾는 AI Scan과 구분합니다. 이 탐지기는 LLM 기반이며 PR 생성과 새 커밋 이후 실행됩니다. 결과는 권고성 경고로, 그 자체가 병합을 막지는 않습니다.
문서가 특정 언어·프레임워크용 정적 분석에 묶이지 않는다고 설명하는 것과 모든 프레임워크에서 같은 탐지율을 보장하는 것은 다릅니다. 독립적인 정탐·오탐 측정은 여기서 확보하지 않았고, 실제 스캐너도 실행하지 않았습니다.
리뷰에서 유용한 것은 기능 이름보다 데이터 흐름입니다.
검색 문서·웹 페이지·이슈 댓글 (신뢰하지 않는 입력)
↓
모델의 문맥
↓
도구 호출 요청
↓
인증된 사용자·테넌트·작업 권한 검사
↓
허용된 효과만 실행
이 도식은 설명용 설계입니다. 도구 스키마가 정확하더라도 요청이 허가됐다는 뜻은 아닙니다. send_email의 인자가 유효한 JSON이라는 것과 사용자가 실제 전송을 승인했다는 것은 다른 조건입니다.
네트워크 없이 확인하는 작은 경계
아래 코드는 로컬 실행한 교육용 권한 검사입니다. Node.js 18 이상에서 파일로 저장해 실행할 수 있습니다. 설치 패키지, 키, 네트워크, 실제 메일 전송이 없습니다. 스캐너의 탐지 능력이나 모델의 인젝션 저항성을 시험한 결과도 아닙니다.
import assert from 'node:assert/strict';
const session = Object.freeze({ tenant: 'demo', canSend: false });
function authorize(request) {
if (request.action !== 'draft_reply') return false;
if (request.tenant !== session.tenant) return false;
return typeof request.text === 'string' && request.text.length <= 500;
}
const cases = [
{ action: 'draft_reply', tenant: 'demo', text: 'Review this draft.' },
{ action: 'send_email', tenant: 'demo', text: 'Send now.' },
{ action: 'draft_reply', tenant: 'other', text: 'Cross-tenant request.' }
];
const results = cases.map(authorize);
assert.deepEqual(results, [true, false, false]);
console.log(JSON.stringify(results));
[true,false,false]
같은 테넌트의 초안만 허용되고, 전송 요청과 다른 테넌트 요청은 거절됩니다. session은 모델 출력이나 검색 문서가 아니라 서버가 인증한 문맥에서 와야 합니다. 모델이 tenant: 'demo'를 썼다는 사실만으로 실제 계정의 소유권을 증명할 수는 없습니다. 실제 서비스에서는 서버가 리소스의 소유권까지 조회해야 합니다.
이 코드는 내용의 진실성, 개인정보 포함 여부, 인증 절차, 리소스별 접근 통제를 구현하지 않습니다. 허용된 초안에 악성 내용이 들어갈 수도 있습니다. canSend는 세션의 의도를 보여줄 뿐이며, 전송은 허용 목록에 없어서 항상 거절됩니다. 나중에 전송을 추가한다면 이 필드만 확인하지 말고 사용자 승인과 수신자·데이터 범위를 함께 검증해야 합니다.
경고를 수정 작업으로 바꾸는 방법
| PR에서 보이는 경로 | 확인할 수정 | 별도로 남는 테스트 |
|---|---|---|
| 문서 → 도구를 가진 모델 | 꼭 필요한 도구만 노출, 실행 직전 권한 검사 | 문서가 요청한 전송이 거절되는가 |
| 검색 결과 → 다른 고객 데이터 | 인증된 테넌트로 검색·조회 범위 제한 | 다른 테넌트의 리소스 ID가 거절되는가 |
| 요약 → 외부 게시 | 초안 생성과 게시를 별도 권한으로 분리 | 승인 없는 게시가 거절되는가 |
이는 특정 GitHub 경고 규칙이 모두 존재한다는 표가 아니라, 경고를 받은 개발자가 점검할 기준입니다. 동일한 비신뢰 입력이 모델에 닿더라도 허용되는 효과가 달라지면 위험도 달라집니다. 문서 요약에 필요 없는 전송 도구를 제거하는 수정은 경고 문구를 고치는 것보다 직접적입니다.
외부 텍스트에 “지시를 무시하라”는 안내를 붙이거나 문자열을 인코딩하는 것만으로 권한 경계가 생기지는 않습니다. 모델이 내용을 어떻게 해석하든 최종 실행기가 허용하지 않은 효과를 수행할 수 없도록 해야 합니다. 반대로 권한 검사만으로 모든 데이터 유출이 막히는 것도 아닙니다. 허용된 출력 채널의 데이터 범위도 검토해야 합니다.
병합 판단에는 경고보다 실행 증거가 필요하다
코드상 도달 경로를 찾는 도구와 실행 시 요청을 거절하는 장치는 서로 다른 증거를 만듭니다. 스캔이 깨끗해도 보안 검증을 끝낸 것은 아니고, 경고가 있어도 구체적인 도달 가능성과 완화책을 살펴봐야 합니다. 프리뷰 탐지기의 설정·과금은 적용 시점의 공식 문서에서 다시 확인하세요.
위 예제가 보여준 범위는 허용 목록과 테넌트 비교뿐입니다. 실제 에이전트에 도입할 때는 에이전트 보안·격리 글의 실행 환경 관점과 함께, 모델 문맥에서 외부 효과까지 한 경로를 끝까지 추적해보세요. PR 경고를 닫는 조건은 설계 의도가 아니라 거절되어야 할 요청이 실제로 거절되는 증거여야 합니다.
도구 호출을 실행·검증 구조로 설계하는 기초는 아래 공개 유료 강의와 연결됩니다. GitHub 보안 스캐너 전용 강의는 아니며, 링크는 홍보 링크입니다.