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.

9 of 35 published
26%

One post every Thursday English + Portuguese Runnable labs

What every post contains

Every post in the series follows the same structure, so you always know where to look:

  1. The Attack — what it is and how it is exploited, in plain prose.
  2. Real-World Incidents — a named breach or CVE, its MITRE ATT&CK technique, and the LGPD/GDPR consequence read by a trained lawyer.
  3. Django's Default Protections — what the framework already does for you, and exactly where that stops.
  4. Vulnerable Pattern — the insecure code, written the way it really gets written.
  5. Secure Implementation — the Django fix, from the broadest control to the most specific.
  6. The Analyst's View — the CySA+ bridge: preventive vs. compensating controls, blast radius, defence in depth.
  7. 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.

Clone the labs on GitHub

Showing 9/9
I

Injection Attacks

OWASP A03 CySA+ · Vulnerability Management 5/5 published

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. 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. 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. 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. 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. 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 →

II

Broken Access Control

OWASP A01 CySA+ · Security Operations 4/5 published

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.

  1. 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 →

  2. 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 →

  3. 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 →

  4. 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.

III

Authentication & Session

OWASP A07 CySA+ · Security Operations

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.

IV

Cryptographic Failures

OWASP A02 CySA+ · Vulnerability Management

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.

V

Security Misconfiguration

OWASP A05 CySA+ · Vulnerability Management

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.

VI

Data Integrity & Deserialization

OWASP A08 CySA+ · Incident Response

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.

VII

Concurrency & Resource Abuse

OWASP A04 CySA+ · Security Operations

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.

VIII

Security Logging & Monitoring

OWASP A09 CySA+ · Security Operations

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.

IX

SSRF & Request Forgery

OWASP A10 CySA+ · Security Operations

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.

X

API Security

OWASP A01 / A03 / A05 CySA+ · Security Operations

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.

XI

Vulnerable & Outdated Components

OWASP A06 CySA+ · Vulnerability Management

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.

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.