FlawOpen

flawopen.com/참고 자료/PR 봇 보안

AI PR 리뷰 봇: Prompt Injection 및 SSRF 방어

AI PR 리뷰 봇: Prompt Injection SSRF 방지

신뢰할 수 없는 pull request 텍스트가 AI 도구에 미치는 영향과 봇 권한 및 네트워크 접근을 제한하는 방법을 설명합니다.

보안 위험 CWE-1427 / CWE-918 AI 및 개발 워크플로 보안

쉬운 설명: 사내 네트워크 통행증을 가진 리뷰 담당자

Pull Request는 리뷰 팀에 전달된 소포와 같습니다. 내용은 유용할 수 있지만 회사 정책이 되는 것은 아닙니다. AI 리뷰 봇이 사설 네트워크에서 임의 URL을 가져올 수도 있다면, 오해를 유도하는 지시가 접근 대상을 바꿀 수 있습니다. 위험은 도구와 네트워크 권한에 달려 있습니다. 적대적인 텍스트를 읽는 것만으로 네트워크 접근 권한이 생기지는 않습니다.

핵심 개념과 주요 용어

신뢰할 수 없는 입력:
기여자가 제출한 Pull Request 제목, 설명, 댓글, diff 및 링크된 콘텐츠.
간접 Prompt Injection:
신뢰할 수 없는 텍스트가 모델 컨텍스트에 포함되어 에이전트에 영향을 주는 현상.
SSRF 경계:
서버 측 가져오기 도구가 기여자가 직접 접근할 수 없는 목적지에 도달하는 것.
영향 조건:
접근 가능한 내부 서비스, 사용 가능한 자격 증명, 부족한 권한 또는 송신 제어가 함께 있어야 합니다.

작동 방식과 근본 원인

리뷰 봇은 기여자가 제어하는 텍스트와 신뢰할 수 있는 리뷰 지침을 모델에 함께 전달할 수 있습니다. 모델은 어느 쪽이든 근거로 도구 호출을 제안할 수 있습니다. 프롬프트와 구분자는 네트워크 접근을 허가하지 않습니다. 애플리케이션 코드가 모델이 고른 목적지를 받아들이고 네트워크 도구가 그곳에 도달할 때만 SSRF가 가능합니다. 클라우드 메타데이터나 자격 증명 접근은 추가적인 조건부 영향이지 Prompt Injection의 자동 결과가 아닙니다.

조건부 공격 경로

1

기여자가 PR 콘텐츠를 제어

외부 기여자는 제목, 설명, 댓글, 변경된 텍스트, 링크된 자료에 영향을 줄 수 있습니다.

2

에이전트가 콘텐츠를 읽음

서비스가 일부 신뢰할 수 없는 필드를 모델 컨텍스트에 넣으면 응답이나 도구 제안에 영향을 줄 수 있습니다.

3

도구 능력이 도달 범위를 결정

에이전트가 임의 URL을 가져올 수 있으면 runner가 네트워크에서 허용하는 대상에 접속할 수 있습니다. 해당 도구가 없다면 이 SSRF 경로는 없습니다.

4

영향은 배포 환경에 좌우됨

내부 데이터나 자격 증명은 접근 가능한 서비스, 메타데이터 설정, 권한, 출력 제어가 허용할 때만 노출됩니다.

코드: 무검증 호출과 권한이 확인된 읽기

무해한 모의 호출
# INERT DEMO: model-selected URL reaches a mock tool without policy checks
from dataclasses import dataclass

@dataclass
class ToolCall:
    name: str
    arguments: dict[str, str]

class MockFetch:
    def __init__(self):
        self.calls = []

    def __call__(self, url: str) -> str:
        self.calls.append(url)
        return "fixture response"

def dispatch_unchecked(call: ToolCall, tools: dict):
    # The mock records a string; it makes no network request.
    return tools[call.name](**call.arguments)

mock_fetch = MockFetch()
call = ToolCall("fetch_url", {"url": "https://docs.example.invalid/"})
assert dispatch_unchecked(call, {"fetch_url": mock_fetch}) == "fixture response"
assert mock_fetch.calls == ["https://docs.example.invalid/"]
정책으로 제한된 읽기 전용 도구
# SAFE DEMO: the agent receives only a read-only PR capability
from dataclasses import dataclass

@dataclass(frozen=True)
class ReviewContext:
    repository: str
    pull_request: int

@dataclass
class ToolCall:
    name: str
    arguments: dict[str, object]

READ_ONLY_TOOLS = {"read_pr_diff"}

def dispatch_review_call(call: ToolCall, context: ReviewContext, policy, tools):
    if call.name not in READ_ONLY_TOOLS:
        raise PermissionError("Tool is not available to this review")
    expected = {"repository": context.repository,
                "pull_request": context.pull_request}
    if call.arguments != expected:
        raise ValueError("Arguments must match the authorized review")
    if not policy.can_read_pr(context.repository, context.pull_request):
        raise PermissionError("Review principal cannot read this pull request")
    # The injected read_pr_diff function is trusted app code, not model output.
    return tools["read_pr_diff"](**expected)

엔지니어링 보안 강화 체크리스트

관련 문서 취약점 — CVE-2023-32786

GitHub 검토 권고문에 따르면 CVE-2023-32786은 LangChain 0.0.329 이전 버전에서 Prompt Injection으로 임의 URL을 가져오게(SSRF) 하고 후속 작업에 영향을 줄 수 있었습니다. 수정 버전은 0.0.329입니다. 이는 문서화된 URL 가져오기 흐름이며 PR 봇 침해나 클라우드 메타데이터 탈취를 입증하지 않습니다.

주요 지침 및 기록

보안 디렉터리 보기 → 다른 참고 가이드 보기 →
함께 보기 서버 측 요청 위조(SSRF, CWE-918): 동작 원리와 언어별 방어 방법 — flawopen.com Node.js fetch() SSRF와 안전한 URL 요청 SSRF와 클라우드 메타데이터: 자격 증명 위험과 방어