agentsclimarketplace

Django security scan

Skill Dolphinllc/claude-security-skills/skills/defensive/web/django-security-scan

Defensive security skills for Claude Code and the Claude Agent SDK — web applications and generative AI systems.

Install
npx -y skills add Dolphinllc/claude-security-skills --skill django-security-scan

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

One thing to look at

  • 1 stars1 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

Defensive security scan for Django and Django REST Framework projects. Detects DEBUG=True in production, wildcard ALLOWED_HOSTS, SECRET_KEY in source, missing CSRF, raw ORM queries with string formatting, mark_safe on user input, AllowAny on mutating DRF views, and ModelSerializer fields="__all__" leaking sensitive fields. Invoke when the user asks to "review", "audit", or "scan" a Django project.

SKILL.md

4.7 KB, as published. Nobody here has run it

Django Security Scan

Defensive scan for Django (4.2+/5.x) and Django REST Framework projects. Reports findings using the shared scoring schema.

Scope

  • settings.py / settings/*.py
  • views.py, class-based views, DRF ViewSets and Serializers
  • urls.py, middleware.py, custom managers and querysets
  • Templates with {% autoescape off %} / |safe

Procedure

  1. Read settings and assess configuration first.
  2. Walk views and serializers for permissions and validation.
  3. Grep for raw(, extra(, mark_safe, format_html, |safe.

Rules

IDSeverityDetectionFix
DJ-CFG-001criticalDEBUG = True not gated by env in any settings module loaded in prodDEBUG = os.environ.get("DJANGO_DEBUG") == "1"
DJ-CFG-002criticalALLOWED_HOSTS = ["*"]Pin to canonical hostnames
DJ-CFG-003criticalSECRET_KEY = "..." literal in repoRead from env / secret manager; rotate immediately
DJ-CFG-004highSECURE_SSL_REDIRECT, SESSION_COOKIE_SECURE, CSRF_COOKIE_SECURE not all True in prodSet all three
DJ-CFG-005highSECURE_HSTS_SECONDS = 0 (or unset) on a TLS siteSet ≥ 31536000 with subdomains/preload as appropriate
DJ-CFG-006mediumX_FRAME_OPTIONS removed or default SAMEORIGIN overridden to ALLOWALLKeep DENY unless embedding is needed
DJ-MW-001highMIDDLEWARE missing CsrfViewMiddleware or XFrameOptionsMiddlewareRestore default middleware order
DJ-CSRF-001high@csrf_exempt on state-changing view that uses session authRemove decorator; if API, switch to token/header auth
DJ-ORM-001criticalModel.objects.raw(f"...{var}...") / cursor.execute(f"...")Use parameterized: raw("SELECT ... WHERE id=%s", [var])
DJ-ORM-002high.extra(where=[f"col = '{var}'"])Use .filter() ORM constructs or parameterize
DJ-TPL-001highmark_safe(user_input) / format_html("{}", user_input) where {} is unescaped intentionallyRender via template auto-escaping; never mark_safe user input
DJ-TPL-002mediumTemplate uses {% autoescape off %} block containing variablesRe-enable autoescape; use `
DJ-DRF-001criticalDRF view permission_classes = [AllowAny] (or default) on mutating endpointUse IsAuthenticated (+ object-level perms)
DJ-DRF-002highModelSerializer with fields = "__all__" on User/auth/PII modelsEnumerate fields; exclude password, is_staff, etc.
DJ-DRF-003mediumSearchFilter / OrderingFilter exposing fields not safe to enumerate (e.g., password_hash)Define explicit search_fields / ordering_fields
DJ-AUTH-001highLOGIN_URL view has no rate limiting / lockout (no django-axes / django-ratelimit)Add django-axes
DJ-FILE-001highFileField / ImageField without validators and used without MIME/size check on uploadValidate extension + content-type + size; store outside web root
DJ-CORS-001highCORS_ALLOW_ALL_ORIGINS = True together with CORS_ALLOW_CREDENTIALS = TrueUse CORS_ALLOWED_ORIGINS = [...]

Wrong vs. right

DJ-DRF-002 (serializer leaks)

# ❌ Exposes password hash, is_staff, etc.
class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = "__all__"
# ✅ Explicit allowlist
class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ["id", "username", "email", "date_joined"]
        read_only_fields = ["id", "date_joined"]

DJ-ORM-001 (raw SQL)

# ❌
User.objects.raw(f"SELECT * FROM auth_user WHERE email = '{email}'")
# ✅
User.objects.raw("SELECT * FROM auth_user WHERE email = %s", [email])

DJ-TPL-001 (mark_safe)

# ❌ Stored XSS pipeline
context["bio"] = mark_safe(user.bio)
# ✅ Let the template engine escape
context["bio"] = user.bio  # rendered as {{ bio }} — auto-escaped

References

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.