FlawOpen

flawopen.com/Справочник/Безопасность PR-ботов

PR-боты на ИИ: защита от Prompt Injection и SSRF

PR-боты на ИИ: защита от SSRF через Prompt Injection

Как недоверенный текст pull request может влиять на инструменты ИИ и как ограничить права бота и сетевой доступ.

Риск безопасности CWE-1427 / CWE-918 Безопасность ИИ и рабочих процессов разработки

ELI5 — помощник по проверке с пропуском во внутреннюю сеть

Pull request похож на посылку для команды проверки: её содержимое может быть полезным, но не становится политикой компании. Если ИИ-помощник может получать любые URL из частной сети, вводящая в заблуждение инструкция может повлиять на цель запроса. Риск зависит от прав инструмента и сети; чтение вредоносного текста само по себе не даёт сетевого доступа.

Основные понятия и термины

Недоверенный ввод:
Заголовки, описания, комментарии, diff и ссылки из pull request участников.
Косвенная Prompt Injection:
Недоверенный текст влияет на агента, поскольку включён в контекст модели.
Граница SSRF:
Серверный инструмент загрузки может достигать узлов, недоступных участнику напрямую.
Условия воздействия:
Также нужны доступный внутренний сервис, имеющиеся учётные данные и недостаточные проверки доступа или сетевого выхода.

Механизм и первопричина

Бот проверки может объединять контролируемый участником текст с доверенными инструкциями ревью. Модель может предложить вызов инструмента на основе любого из этих источников. Промпт и разделители не разрешают сетевой доступ. SSRF возможна только если код принимает выбранный моделью адрес, а инструмент с сетевым доступом может его достичь. Доступ к облачным метаданным или учётным данным — дополнительное условное воздействие, а не автоматический результат Prompt Injection.

Условная цепочка атаки

1

Участник контролирует содержимое PR

Внешний участник может влиять на заголовки, описания, комментарии, изменённый текст и ссылки.

2

Агент читает этот контент

Сервис помещает некоторые недоверенные поля в контекст модели; это может повлиять на ответ или предложение инструмента.

3

Инструмент определяет доступность

Если агент может получать произвольные URL, runner может обращаться к адресам, разрешённым сетью. Без такого инструмента этого пути SSRF нет.

4

Воздействие зависит от развёртывания

Внутренние данные или учётные сведения уязвимы только если это позволяют доступные сервисы, настройки метаданных, права идентичности и контроль вывода.

Код: непроверенный вызов и авторизованное чтение

ИНЕРТНАЯ MOCK-ДЕМОНСТРАЦИЯ
# 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/"]
READ-ONLY ИНСТРУМЕНТ С ПРОВЕРКОЙ ПОЛИТИКИ
# 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 рекомендации указано, что Prompt Injection в LangChain до 0.0.329 могла заставить сервис загрузить произвольный URL (SSRF) и потенциально повлиять на последующие задачи. Исправленной указана версия 0.0.329. Это документированная цепочка загрузки URL, а не подтверждённый инцидент с PR-ботом или доказательство кражи облачных метаданных.

Основные источники и рекомендации

Открыть каталог безопасности → Другие справочные руководства →
См. также Подделка запросов на стороне сервера (SSRF, CWE-918): как работает и как предотвратить на любом языке — flawopen.com SSRF в Node.js fetch(): безопасная загрузка URL SSRF и облачные метаданные: риски и защита