9.3 KiB
name, description
| name | description |
|---|---|
| django | Security testing playbook for Django applications covering ORM injection, middleware gaps, auth/session flaws, and template issues |
Django
Security testing for Django web applications and Django REST Framework (DRF) APIs. Focus on ORM/raw query misuse, middleware ordering, permission class gaps, and session/auth configuration across views, admin, and channels.
Attack Surface
Core Components
- URL routing (
urls.py), class-based and function views, middleware stack - ORM (QuerySet filters), raw SQL,
extra(),RawSQL, annotations - Templates (Django template language, Jinja2 if configured)
- Forms, ModelForms, serializers (DRF)
Authentication
- Session framework,
AuthenticationMiddleware,@login_required, DRFpermission_classes - Token auth, JWT (djangorestframework-simplejwt), OAuth integrations
- Django admin (
/admin/), staff/superuser flags
Deployment
DEBUG=Trueexposure,ALLOWED_HOSTS,SECRET_KEYleakage- Static/media serving, reverse proxies, ASGI (Channels, Daphne, Uvicorn)
High-Value Targets
/admin/— brute force, credential stuffing, IDOR on admin objects- API endpoints with mixed permission classes across ViewSets
- File upload (
FileField,ImageField), import/export (django-import-export) - Search/filter endpoints using
filter(),Qobjects, or raw SQL - Password reset, email verification, invitation tokens
- WebSocket consumers (Django Channels) with weaker auth than HTTP equivalents
- Celery task triggers accepting user IDs without ownership checks
Reconnaissance
Fingerprinting
curl -I https://target/ -H "Cookie: sessionid=test"
# X-Frame-Options, Set-Cookie (sessionid, csrftoken), Server header
GET /admin/login/
GET /api/ /api/v1/ /swagger/ /api/schema/
Settings Leakage (when DEBUG=True or misconfigured)
- Yellow debug page exposes
SECRET_KEY, database credentials, installed apps /static/, error pages with stack traces revealing paths and ORM queries
OpenAPI / DRF
GET /api/schema/
GET /swagger.json
Map endpoints, authentication classes, and permission classes per route.
Key Vulnerabilities
Authentication & Authorization
Permission Class Gaps
- ViewSet with
listprotected butretrieve/updatemissingpermission_classes - Custom permissions checking authentication but not object ownership (IDOR)
@api_viewwithout explicit permissions inheriting permissive defaults- Admin actions or custom management commands without staff checks
Session Issues
SESSION_COOKIE_SECURE=Falseon HTTPS sites; missingHttpOnly- Session fixation if session key not rotated on login
- Weak or leaked
SECRET_KEY→ forge session cookies (django.contrib.sessions.backends.signed_cookies)
JWT (simplejwt)
- RS256→HS256 confusion if algorithm pinning is misconfigured
- Missing
user_id/tokenblacklist on logout - Refresh token rotation not enforced
Injection
ORM SQL Injection Vulnerable patterns (more common in legacy code):
User.objects.raw(f"SELECT * FROM auth_user WHERE username = '{user_input}'")
User.objects.extra(where=[f"username = '{user_input}'"])
Test: ' OR 1=1 --, time-based payloads, database-specific syntax.
DRF Filter Backends
django-filterwith unsafe field exposure:?username__icontains=on unintended columns- Ordering injection via
?ordering=if field whitelist missing
Template Injection Django templates auto-escape by default; risk rises with:
mark_safe(user_input)
|safe filter in templates
Template(user_input).render(...) # SSTI if user controls template source
Jinja2 backend without autoescape: {{7*7}}, RCE gadgets if sandbox misconfigured.
CSRF
@csrf_exempton state-changing views- DRF session authentication without CSRF enforcement on unsafe methods
- CSRF cookie not set (
CSRF_USE_SESSIONS, trusted origins misconfiguration) CSRF_TRUSTED_ORIGINStoo broad
Test: Cross-origin POST with victim session cookie; JSON endpoints with session auth.
IDOR and Mass Assignment
DRF Serializers
fields = '__all__'exposingis_staff,is_superuser,role,balanceread_only_fieldsmissing on sensitive ModelSerializer fields- Nested writes updating foreign keys across tenants
Object-Level Permissions
get_object()without filtering queryset by request.user- Generic views with
queryset = Model.objects.all()and weak permissions
File Handling
MEDIA_ROOTserved directly in DEBUG or via misconfigured nginx- Path traversal in custom file download views using user-supplied paths
- SVG/HTML uploads served with
Content-Typethat enables XSS - Missing file size/type validation on uploads
SSRF
requests.get(user_url)in webhooks, preview, import features- Celery tasks fetching user URLs server-side
- Test loopback, metadata IPs, redirect chains
Host Header / Password Reset
ALLOWED_HOSTS = ['*']or permissive subdomain patterns- Password reset emails built from
Hostheader → poisoned reset links - Cache poisoning via unkeyed Host header on cached pages
Django Admin
- Default
/admin/path with weak credentials has_add_permission/has_change_permissionoverrides with logic bugs- ModelAdmin exposing sensitive fields in list_display or export
Channels / WebSocket
- Consumer accepts connection without session/auth parity to HTTP
- Group name derived from user input → subscribe to other users' channels
- Missing origin validation on WebSocket handshake
Bypass Techniques
- Content negotiation: JSON vs form data hitting different parser/permission paths
- HTTP method override or trailing slash routing to alternate view
- Parameter pollution: duplicate
idfields in query and body - Race on state transitions (coupon redemption, inventory) via parallel requests
- Versioned API (
/api/v1/vs/api/v2/) with weaker auth on older version
Testing Methodology
- Map surface — URLs, DRF schema, admin, static/media paths
- Auth matrix — Unauthenticated/user/staff for each endpoint and method
- Object ownership — Swap IDs across two user accounts on every CRUD route
- Serializer audit — Identify writable sensitive fields and nested relations
- Middleware order — Confirm auth runs before business logic; check CSRF on session APIs
- Channel parity — Same authorization on WebSocket actions as REST equivalents
- Settings review (white-box) — DEBUG, ALLOWED_HOSTS, SECRET_KEY, session/cookie flags
Validation
- Side-by-side requests proving unauthorized access (IDOR, privilege escalation)
- CSRF PoC executing state change with victim session (for session-authenticated endpoints)
- SQLi/template injection with deterministic oracle (error, timing, or
7*7equivalent) - Document view/serializer/permission class where enforcement failed
- Show admin or staff capability gained from regular user context if applicable
False Positives
queryset.filter(user=request.user)consistently applied including nested routes- Object-level permission class correctly validates ownership on all actions
- DEBUG=False and generic error pages with no settings leakage confirmed
- Mark_safe used only on server-generated trusted content
- CSRF correctly enforced on all session-authenticated unsafe methods
Impact
- Account takeover via session forgery or password reset poisoning
- Horizontal/vertical privilege escalation through IDOR and mass assignment
- Data breach via ORM/SQL injection or excessive serializer fields
- Server compromise via SSTI, pickle in cache (if used), or SSRF to internal services
Pro Tips
- DRF ViewSets often protect
listbut forgetdestroyor custom@actionroutes - Check
APIViewsubclasses for missingpermission_classes— common oversight - Test
?format=and browsable API HTML responses for CSRF on session auth django.contrib.adminuses separate auth — don't assume API auth covers admin- Compare ASGI WebSocket consumers against REST permissions for the same resource
Tooling
Static analysis is the fastest way to reach the sinks above in white-box scope. The sandbox ships python/pipx, semgrep, bandit, ast-grep, and ripgrep.
- bandit (preinstalled) — Python security linter; flags
mark_safe,extra(),RawSQL,subprocess, weak crypto, hardcoded secrets:bandit -r . -ll - semgrep (preinstalled) with the Django ruleset — higher-signal than bandit for framework-specific bugs (
.extra(),RawSQL,|safe,csrf_exempt,ALLOWED_HOSTS=['*']):semgrep --config p/django . - pip-audit (PyPA) — dependency CVE scanner for known-vuln Django/DRF/simplejwt versions:
pipx install pip-audit && pip-audit -r requirements.txt - ast-grep (preinstalled) — quick structural grep for risky calls without a full SAST run:
ast-grep run -p 'mark_safe($X)' -l python
For the SECRET_KEY → signed-cookie/reset-token forgery path noted under Session Issues, Django's own django.core.signing is the "tool": with a leaked key you can mint valid signing.dumps() values (session cookies, password-reset tokens, and PickleSerializer-backed session RCE).
Summary
Django's defaults help (CSRF middleware, template auto-escape) but DRF, raw SQL, custom permissions, and deployment settings introduce frequent gaps. Test every endpoint with role-separated principals and verify object-level enforcement on querysets, not just authentication presence.