Blog series
Secure by Design
Web Application Security with Python & Django
One attack per post: how it works, how it is exploited, and the exact Django code that stops it. Every defence is backed by a public, runnable lab you can clone and scan with the same tools a security team uses — and every attack is mapped to CompTIA CySA+ CS0-003 and the OWASP Top 10.
What every post contains
Every post in the series follows the same structure, so you always know where to look:
- The Attack — what it is and how it is exploited, in plain prose.
- Real-World Incidents — a named breach or CVE, its MITRE ATT&CK technique, and the LGPD/GDPR consequence read by a trained lawyer.
- Django's Default Protections — what the framework already does for you, and exactly where that stops.
- Vulnerable Pattern — the insecure code, written the way it really gets written.
- Secure Implementation — the Django fix, from the broadest control to the most specific.
- The Analyst's View — the CySA+ bridge: preventive vs. compensating controls, blast radius, defence in depth.
- Catching It Automatically — the test that proves your defence, plus real captured output from Bandit, Semgrep, sqlmap or pip-audit run against the companion lab.
The series is written as learning in public — a lawyer-turned-developer studying application security with the CySA+ syllabus in hand. Authority comes from verified code and reproducible scans, not from claimed years on a SOC floor.
Injection Attacks
Five posts, one root cause: conflating data with code. The same mistake is carried into a different interpreter each time — the SQL database, the browser DOM, the template engine, the OS shell, and the XML parser. Django parameterises or escapes most of these by default; every post studies the escape hatch a developer reaches for when the safe default gets in the way.
-
1 A03
SQL Injection
SQL Injection: how attackers exploit unsanitised queries, why Django's ORM stops them, and where the protection ends. OWASP A03:2021, CySA+ VM.
May 4, 2026 Read more →
-
2 A03
Cross-Site Scripting (XSS)
XSS in Django: how stored, reflected and DOM-based attacks work, why mark_safe() and unsafe Markdown open the same hole, and how to migrate to nh3.
May 7, 2026 Read more →
-
3 A03
Server-Side Template Injection (SSTI)
SSTI in Django: how Jinja2 MRO traversal achieves RCE, why Django's DTL is safe by design, and where that guarantee evaporates. OWASP A03:2021, CVE-2022-22954.
May 11, 2026 Read more →
-
4 A03
OS Command Injection
OS Command Injection in Django: how shell=True turns user input into RCE, why shell=False with an argument list stops it. OWASP A03:2021, CVE-2016-3714.
May 14, 2026 Read more →
-
5 A05
XXE & XML Bombs
XXE in Django: how external entities read files and reach the metadata endpoint, Billion Laughs exhausts memory, and defusedxml is the fix. OWASP A03:2021.
May 21, 2026 Read more →
Broken Access Control
Five posts on a single failure: the app authenticates who you are but never enforces what you may touch. Django hands you authentication primitives (login_required, is_authenticated) and leaves object-level and field-level authorization to you — every post is a place that gap opens.
-
6 A01
Broken Access Control & IDOR
IDOR in Django: how swapping a URL ID leaks another user's data, why login_required is not authorization, and how to scope querysets. OWASP A01:2021.
May 28, 2026 Read more →
-
7 A01
Privilege Escalation
Privilege escalation in Django: how fields='__all__' exposes is_staff and is_superuser, and how explicit field lists stop it. OWASP A01:2021.
June 4, 2026 Read more →
-
8 A01
Cross-Site Request Forgery (CSRF)
CSRF in Django: how hidden forms ride the victim's session cookie, why @csrf_exempt is dangerous, and how CsrfViewMiddleware stops it. OWASP A01:2021.
June 11, 2026 Read more →
-
9 A01
Path Traversal
Path traversal in Django: how os.path.join lets attackers escape MEDIA_ROOT, why safe_join stops it, and when FileField eliminates the risk. OWASP A01:2021.
June 18, 2026 Read more →
1 more post in this series, publishing weekly.
Authentication & Session
Seven posts on the front door: proving who a user is, and keeping that proof safe. Django's auth framework ships strong primitives — password hashing, session-key rotation on login, HMAC reset tokens — but leaves rate limiting, MFA, and token / OAuth wiring to the developer and the ecosystem.
7 posts planned for this series.
Cryptographic Failures
Four posts on protecting data at rest, in transit, and the secret that underpins both. Django ships strong defaults (PBKDF2 hashing, a complete SECURE_* settings surface), so every post is a study of the moment a developer overrides a default, forgets a flag, or commits a secret.
4 posts planned for this series.
Security Misconfiguration
Five posts on getting the defaults and the deployment right. Django ships safe defaults for much of this — X-Frame-Options: DENY, a full SECURE_* surface — so the failures are the flags a developer flips off, the header they never add, and the third-party tool they misconfigure.
5 posts planned for this series.
Data Integrity & Deserialization
One post on trusting a payload the app should have treated as hostile. Django ships the right primitives — a JSON session serializer by default and django.core.signing for integrity — so the vulnerability is the developer who reaches for pickle or hand-rolls a token.
1 post planned for this series.
Concurrency & Resource Abuse
Two posts on the application mishandling its own resources under adversarial load. Both stay in scope precisely because Django ships concrete primitives — select_for_update(), F(), DATA_UPLOAD_MAX_*, throttling — that make the vulnerable-to-secure pair real.
2 posts planned for this series.
Security Logging & Monitoring
One post on the observability layer, kept strictly to what the developer owns: log injection (untrusted input forging log lines) and sensitive data leaking into logs. Monitoring strategy belongs to the SOC and stays a sidebar.
1 post planned for this series.
SSRF & Request Forgery
Three posts on making the server act against itself or its users. Django hands you ALLOWED_HOSTS, url_has_allowed_host_and_scheme() and URLValidator — so every failure here is trusting a user-supplied URL or the request Host without validation.
3 posts planned for this series.
API Security
One capstone post. The OWASP API Security Top 10 is not a new set of attacks — it is the earlier series re-expressed for APIs, where Django REST Framework's convenience defaults amplify every access-control mistake.
1 post planned for this series.
Vulnerable & Outdated Components
One coda post, anchored to a concrete Django-reachable exploit — a Pillow CVE reached through an ImageField upload, a PyJWT algorithm confusion — with software composition analysis (pip-audit, Dependabot, an SBOM) as how you catch them first.
1 post planned for this series.
No posts match the current filters.
Follow the series
New post every Thursday, English and Portuguese on the same day. Subscribe by feed, or clone the labs and scan them yourself.