Local environment, attacks against YOUR app. Don't look at solutions.md before submitting.
Exercise 1 — SQLi: the f-string that burns
- Write (only on a throwaway branch, to learn) a view that filters events with a cursor + f-string:
f"... WHERE title LIKE '%{q}%'". Run it withq = "x' OR '1'='1". What did it return? And withq = "x'; DROP TABLE events_reservation; --"(on a disposable test DB). - Rewrite it with
%sparameters: repeat the payloads. What comes out now? - Your
available_seatsuses the ORM: demonstrate with a payload-like input ("'; DROP --as the seatrow) that nothing explodes — the ORM parameterized.
Exercise 2 — XSS: from JSON to the DOM
- Create an event whose title is
<img src=x onerror=alert('xss')>. Consume it from a mini HTML page with fetch +innerHTML: does it execute? (that is the FRONTEND's risk, not your API's). - Switch to
textContent(or the framework's escape): does it execute? Record the rule for your frontend team: "user HTML never goes through innerHTML; if there is legitimate rich HTML: sanitize with DOMPurify server-side or at render". - Basic CSP headers on your response (or Nginx):
Content-Security-Policy: default-src 'self'— what does that block from the previous scenario as a second layer?
Exercise 3 — SSRF: the guard
- Add (on a test branch) an endpoint
POST /api/tools/fetch/ {"url":...}that returns the URL's title. Attack it:http://localhost:6379/andhttp://169.254.169.254/latest/meta-data/(locally there is no real metadata, but the technique is the cloud attack's). - Implement the guard: http/https schemes only, resolve with
socket.getaddrinfoand reject private/loopback/link-local IPs (block the ranges 169.254.0.0/16, 127.0.0.0/8, 10/8, 172.16/12, 192.168/16), and a domain whitelist if the case allows it. - Why must DNS resolution happen BEFORE the fetch and against the IP you will connect to (DNS rebinding)?
Exercise 4 — check --deploy and the browseable API
- Run
python manage.py check --deploy: list the warnings it gives you today. - Configure the lesson's secure settings block (HSTS, secure cookies, nosniff, referrer, X-Frame-Options DENY) and run it again: does it go green?
- Turn off the browseable API in production (
DEFAULT_RENDERER_CLASSESJSON only) and justify what it exposed.
Exercise 5 — Components and dependencies
pip install pip-auditand runpip-auditover your requirements: how many known vulnerabilities are in your versions? Note the 2 most severe.- Pin exact versions (
==) in requirements and add pip-audit to your "local pipeline" (a script). Why is pinning + audit A06's minimum pair?
Exercise 11 — The three from §11, hunted
- Mass assignment: deliberately create the vulnerable endpoint (
fields = "__all__"on the profile serializer) and demonstrate it: PATCH the profile with"is_staff": true→ did the user self-escalate? Fix: explicit serializer + a regression test that sends the field and verifies it didn't land. - Timing: compare
secret == guessvshmac.compare_digestwith 1000 measurements (37's timeit): does the time difference reveal correct characters in the first? Paste the numbers. - Dependencies: introduce a typo in a test dependency (
pip install requetsin a lab venv): what does it install? Afterwards: pin your dependencies with hashes (pip-compile --generate-hashes) and runpip-audit— 41's report.
Exercise 12 — security.txt and the runbook
- Write your
/.well-known/security.txt(contact, expiry, disclosure policy, encryption for reports) and the test that verifies it exists and expires in the future. - The finding's runbook (§12) applied to a simulated vulnerability ("external report: the events endpoint leaks emails in the reservation listing"): the 5 steps with real commands (how do you contain? which regression test? do you notify?). Max 1 page (48).
- The postmortem's root question: which PIECE of the course (50's review, 41's pipeline, 34's tests) would have caught that leak? If the answer is "none": that is the P1 action.
Submit
Paste the outputs of the attacks (on your environment!) and the implemented guards. Next: Lesson 23 — Secrets, rate limiting and GDPR.