Django Security Review Skill for Cline
Review a Django change for permission checks, ORM query shape, and migration behavior. Use for a Django security review. Do not use for a non-Django project or to assume a database cascade runs Django signals.
name: "django-security-review" description: "Review a Django change for permission checks, ORM query shape, and migration behavior. Use for a Django security review. Do not use for a non-Django project or to assume a database cascade runs Django signals."
Django Security Review Skill for Cline
Cline skill django-security-review for Django. /django-security-review forces it. A global skill of the same name overrides this project file.
When to run
Run this review for a Django view, model, form, or migration.
When to leave it
Stop for a non-Django repository. Do not upgrade Django or run a migration against production.
What to check
- Injection:
raw(),extra(), and.rawSQL built with f-strings or%formatting. Parameters are the safe form. - XSS:
|safe,mark_safe, andformat_htmlon user text without escaping. - CSRF: a state-changing view that is
@csrf_exemptwithout a documented machine client. - Secrets: a key or password in settings committed to the tree, or logged on the request.
- IDOR: a queryset that loads by the posted id and never checks the owner or a permission.
- SSRF: a view that
requests.gets a URL the user supplied, with no host allow-list. - Mass assignment: a model form with
fields = "__all__"facing the browser. - Uploads: a file stored with the original name and no type or size check.
Steps
- Read the installed Django version. A 6.1-only fetch mode or delete option on an older install is a high finding.
- Review permission checks on every changed write. A missing check is a high finding. A form with
fields = "__all__"facing users is a high finding. - Review querysets for per-row queries.
update()sends no signals.QuerySet.delete()sendspre_deleteandpost_deletebut skipsModel.delete(). A databaseON DELETE CASCADEsends nothing. Flag a comment or a test that assumes the wrong one of those three. Do not flagQuerySet.delete()itself for "no signals". - Review migrations for edits to shipped files and for destructive drops bundled with unrelated code.
- Check async views for a direct ORM call.
- Run the app's tests only if the user asked. Otherwise write
not run.
Output
Findings with severity, file, line, the permission or query issue, and a fix. State that production was not migrated.
## Findings
- high | path:line | what is wrong | what to do instead
## No findings
Say "No findings" and list the files you opened. A search you skipped is not a clean result.
## Example
Input: a comment says `Note.objects.filter(tenant=t).delete()` will run `Note.delete()`.
Output: high | notes/services.py:18 | `QuerySet.delete()` skips `Model.delete()` and still emits `pre_delete`/`post_delete` | call `note.delete()` when the override must run.
Do not flag the valid pattern named in the standards. Flag the mistake next to it.
Stop
Stop when the user asks you to migrate production or to disable auth tests.
Severity
high is a bug a caller can hit or a secret that leaks. medium is a broken contract that needs a specific input. low is a cleanup that does not change behaviour.