agentsclimarketplace

Django security

Skill roodlicht/accans-sec-skills/skills/django-security

47 Claude skills for security tradecraft across AppSec, Pentest, Blue Team, and GRC. NL/EU regulatory-anchored. Pattern-level discipline.

Install
npx -y skills add roodlicht/accans-sec-skills --skill django-security

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Django security review — CSRF, ORM-level SQL injection (raw/extra/annotate), template injection via |safe, admin hardening, middleware ordering, settings deploy checklist, and recent Django CVE patterns.

SKILL.md

11.1 KB, as published. Nobody here has run it

Django Security

When to use

This skill is the Django-specific layer on top of secure-coding. Use it when Django gets in its own way: defaults that invite misunderstanding, ORM paths that look safe but still allow SQLi, or settings that may go wrong per environment.

Triggers on:

  • A question like "review this Django app", "is our deploy safe", "what are our SECURE_ settings", "are we using CSRF correctly", "Django admin hardening".
  • Presence of manage.py, settings.py, urls.py, models.py, views.py, Django middleware class paths in MIDDLEWARE, DRF viewsets.py or serializers.py.
  • A PR that introduces @csrf_exempt, |safe, mark_safe, .raw(), .extra(), RawSQL, or HttpResponse(user_input).
  • Django version bumps that are a security release (release notes will explicitly mention fixes).
  • A handoff from security-review where Django is in the stack.

When NOT (handoff)

  • General Python secure-coding (not Django-specific) → secure-coding.
  • DRF as an API layer overlaps heavily with api-security: OAuth/JWT flow, OWASP API Top 10 belong there. Django-specific DRF foot-guns (e.g. HyperlinkedModelSerializer authorization bypass) stay here.
  • SAST tool config (Bandit, Semgrep p/django) → sast-orchestrator.
  • Dep vulns in Django or third-party packages → cve-triage.
  • Deploy infrastructure (nginx, gunicorn, containers) → container-hardening / iac-security.
  • Secrets handling (SECRET_KEY, DB creds) → secrets-scanner.

Approach

Six phases. Django defaults are reasonably safe; most issues arise where you deliberately override them.

1. Settings and deploy checklist

python manage.py check --deploy is a Django-built-in checker. Always run it, fix every warning before production. Not sufficient, but necessary.

Critical settings:

  • DEBUG = False in production. DEBUG = True leaks stack traces, env vars, SQL queries: full app-internal exposure. No exceptions.
  • ALLOWED_HOSTS explicit. Wildcard ['*'] in prod is a Host-header-injection vector.
  • SECRET_KEY from environment or vault, never in source. Rotation schedule on suspicion of leak. See secrets-scanner.
  • SECURE_SSL_REDIRECT = True, SECURE_HSTS_SECONDS >= 31536000 with SECURE_HSTS_INCLUDE_SUBDOMAINS and SECURE_HSTS_PRELOAD, SESSION_COOKIE_SECURE = True, CSRF_COOKIE_SECURE = True. Only where TLS is guaranteed.
  • SESSION_COOKIE_HTTPONLY = True (default), SESSION_COOKIE_SAMESITE = 'Lax' or 'Strict'.
  • SECURE_CONTENT_TYPE_NOSNIFF = True, SECURE_REFERRER_POLICY explicitly set.
  • CSRF_TRUSTED_ORIGINS with full scheme+host where relevant (Django 4+).
  • PASSWORD_HASHERS with Argon2 first, then PBKDF2 as fallback. Requires django-argon2 package.
  • Database: ATOMIC_REQUESTS where appropriate, separate DB user with least privilege (no DROP/CREATE rights for the web user).

2. ORM and SQL injection

Django's ORM parameterizes by default. SQLi arises in places where you step out of it:

  • .raw(): string formatting in the raw queryset gives SQLi. Use placeholder params: Model.objects.raw('SELECT * FROM app_model WHERE name = %s', [name]). Not f'SELECT ... WHERE name = {name}'.
  • .extra(): deprecated, still widely used. where=, params=, select= can be abused. Prefer to replace with Func(), RawSQL() with params, or annotate() with ExpressionWrapper.
  • RawSQL: parameter list MUST be used. The example in the Django docs shows RawSQL("select col from sometable where othercol = %s", (someparam,)). Follow that.
  • QuerySet.annotate() / aggregate() with dict keys from user input. Historically vulnerable (see CVE-2022-28346, SQL injection via column aliases in dict keys). Reviewer rule: dict keys in annotate/aggregate never come from user input, hardcode them.
  • Order-by with user input. .order_by(request.GET.get('sort')) lets users pick columns. Allowlist permitted column names.
  • __in= with large lists from user input: not SQLi but still DoS. Cap list size.

Django CVE references (within a 3-year window, verify against release notes):

  • CVE-2022-28346: QuerySet.annotate/aggregate SQLi via dict keys. Fixed in Django 2.2.28, 3.2.13, 4.0.4. Canonical example of "the ORM is safe, except when ..."
  • CVE-2023-43665: Truncator DoS via crafted HTML. Fixed in 3.2.22, 4.1.12, 4.2.6.
  • More recent CVEs in the Django 4.2/5.x series: [verify against https://docs.djangoproject.com/en/dev/releases/security/] for the current window.

3. Template injection and XSS

Django templates have autoescape on by default. XSS arises when you turn it off.

  • {{ user_input|safe }}: renders raw HTML. Apply only to content you have controlled yourself (e.g. sanitized HTML from a trusted bleach call), never on unwashed user input.
  • {% autoescape off %}: disables escaping for the entire block. Rarely needed, review every use.
  • mark_safe(s) in Python code: same effect as |safe. If s contains user input or is composed of user input, you have XSS.
  • format_html('<a href="{}">', user_url): URL attributes are a separate problem. javascript: URLs via href bypass HTML escaping. Validate user_url.startswith(('http:', 'https:')).
  • Server-side template injection: if you render templates yourself with user-controlled template strings (Template(user_input).render(...)), you get SSTI with potential RCE. Never do this.
  • HttpResponse(user_input): bypasses template autoescape because there is no template. Use render() or encode explicitly.

4. CSRF model

Django's CsrfViewMiddleware is on by default for POST/PUT/PATCH/DELETE.

  • @csrf_exempt: turns CSRF off for a specific view. Use only on endpoints where CSRF structurally cannot work (e.g. webhook receivers with signature verification). Every @csrf_exempt in a PR is a security-review moment.
  • DRF and CSRF: DRF SessionAuthentication enforces CSRF, TokenAuthentication/JWT does not (stateless). Mixed auth modes: be explicit about which endpoints use which model.
  • CSRF_COOKIE_HTTPONLY: default False, which is needed for JS to read the token. Do not change unless you have a custom CSRF setup.
  • CSRF_TRUSTED_ORIGINS: stricter interpretation since Django 4 (full origin with scheme). Without correct config: legitimate POSTs are 403-rejected.

5. Auth, session, and admin

  • django.contrib.auth.password_validation: never remove. Length check, common-password check, attribute-similarity check must be active.
  • AUTHENTICATION_BACKENDS: custom backends are a classic foot-gun. Every custom backend must be timing-safe (identical response time for "user does not exist" vs. "wrong password").
  • Admin interface:
    • ADMIN_URL not /admin/ (security through obscurity + bot-traffic reduction).
    • IP allowlist via middleware or reverse proxy for /admin/*.
    • 2FA required via django-otp or django-allauth with TOTP.
    • is_staff and is_superuser assigned carefully. Superuser status only for a small team.
  • Session management: SESSION_COOKIE_AGE reasonably short, SESSION_EXPIRE_AT_BROWSER_CLOSE where appropriate, session rotation on privilege change (automatic on login since Django 2+).
  • django-allauth/django-axes for rate-limiting on login (brute-force prevention). Native Django has no rate limiter on auth endpoints.

6. Misc and verification-loop

  • File uploads: FileField does not validate content type. UploadedFile.content_type is set by the client. Validate magic bytes, whitelist extensions, store outside web root.
  • Open redirects: redirect(request.GET.get('next')) without validation is an open redirect. Django has url_has_allowed_host_and_scheme(url, allowed_hosts=...) for this purpose.
  • Middleware order: SecurityMiddleware belongs high, CsrfViewMiddleware before AuthenticationMiddleware, custom middleware with side effects close to the view. Wrong order can produce subtle bypasses.
  • django-admin check with --deploy required in CI.
  • Bandit + Semgrep p/django as the SAST layer, see sast-orchestrator.

Verification-loop: Layer 1 scope (settings file + urls + middleware stack all walked through?), assumptions (autoescape on everywhere, no |safe on user input?), gaps (DRF views included in the same review?). Layer 2 specifically on CVE IDs (verify against Django release notes, not memory), security-setting names (Django sometimes changes default values per major version), admin-hardening claims backed by concrete middleware/package.

Output

Follow the security-review report format, with a Django-specific scan summary at the top:

Django security review — <app/project>
Django version: <x.y.z> (latest security release: <...>)

Deploy checklist (python manage.py check --deploy):
  Warnings: N → resolved/open
  DEBUG in prod:        <False | FINDING>
  ALLOWED_HOSTS:        <explicit | wildcard — FINDING>
  SECURE_* settings:    <complete | gaps>
  PASSWORD_HASHERS:     <Argon2 first | PBKDF2 default>

Code patterns:
  @csrf_exempt:         <N, location, reason>
  |safe / mark_safe:    <N, on user input? FINDING>
  .raw() / .extra():    <N, parameterized?>
  order_by(user input): <list>

Admin:
  URL not /admin/:      <yes/no>
  IP restriction:       <yes/no>
  2FA on staff:         <yes/no>

Version check:
  On latest security release: <yes | N months behind>
  CVE relevance:              <handoff to cve-triage>

Findings (severity-sorted, follow security-review format)
Verification-loop: ...

References

Categories

  • appsec

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.