Developer foundations
Start at the data boundary. Build habits that make common defects harder to introduce.
- Distinguish syntax safety, object permission and authenticated messages.
- Trace untrusted input through storage, credentials and business effects.
- Retain paired positive and negative evidence for a concrete repair.
- Read a small request handler and a JSON object.
- Basic HTTP and SQL vocabulary helps; the linked examples supply all data and the labs run in the browser.
Estimated time: about 7–8 hours across 13 steps, including 5 browser labs and 1 local project.
By the end: A small boundary notebook containing five worked decisions and four lab repairs, with the claim and limitations of every result.
0 of 13 steps complete
Work through the supplied query and identify which characters became SQL syntax. Compare the unsafe and bound forms using the ordinary and injection inputs.
Keep: A before/after query explanation and input/result table.
Complete when: Explain why bound values preserve ordinary search and why any dynamic identifier still needs its own constraint.
Open guide : Fix SQL injection in Python sqlite3Run the SQL injection lab in its Python runtime: bind the category and the search term as parameters, and build the LIKE pattern with its wildcards escaped.
Keep: A repaired search function with the lab's passing cases.
Complete when: A crafted term stays data and matches only what it says, while ordinary category and keyword searches return the same rows as before.
Open lab : SQL injection lab: Separate SQL structure from data with sqlite3Use the supplied accounts and invoices to decide owner, same-tenant non-owner and cross-tenant requests before reading the answer.
Keep: A permission matrix with the authoritative source of actor, tenant and ownership.
Complete when: Every allow and denial names its decisive relationship; a valid login alone never explains object access.
Open guide : Enforce authorization for every object actionEdit the browser lab, run its supplied cases and explain the decision for each actor/object combination.
Keep: Saved repair and actual lab result summary.
Complete when: The legitimate owner succeeds and both tenant and ownership violations fail; record any remaining failed case instead of only the total.
Open lab : IDOR lab: Repair an invoice authorization bugDraw receive, quarantine, inspection, publication and download for the guide fixture. Mark when bytes become accessible and who can advance each state.
Keep: An upload state diagram plus one bypass and its enforcing control.
Complete when: Explain why a name/type check alone does not authorize safe storage or another user’s download.
Open guide : Design a safer file-upload pipelineRun the path traversal lab: resolve the requested name, symlinks included, and refuse any target outside the upload directory before opening it.
Keep: A repaired download function with the lab's passing cases.
Complete when: ../ sequences, absolute paths and symlinks that point outside are refused, and files in nested upload folders still download.
Open lab : Path traversal lab: Serve an uploaded file without path traversalUse the guide’s leak/rotation evidence to identify every known copy, consumer and revocation dependency.
Keep: A credential lifecycle record distinguishing removal, rotation and revocation.
Complete when: Removing the visible secret is not recorded as closure while an old credential or retained copy can still be used.
Open guide : Secrets management: storage, rotation and leaked-secret responseTrace raw bytes, signature, freshness, event identity and payment state in the supplied delivery scenario.
Keep: A five-boundary webhook decision table.
Complete when: A valid signature does not justify a duplicate payment, and a retry is resolved from durable state rather than message wording.
Open guide : Verify webhook deliveries before actingUse the webhook lab to repair verification and duplicate-effect handling, then compare your code with the earlier decision table.
Keep: A repaired handler plus explanation of its authentication and replay boundaries.
Complete when: Invalid deliveries produce no payment, duplicate valid delivery produces one logical effect, and the valid first delivery still works.
Open lab : Webhook signature and replay lab: Repair a webhook handler that pays twiceDownload the Express project, install its pinned packages with npm ci --ignore-scripts, run npm test, then repair invoice authorization and the profile update in exercise.mjs.
Keep: The failing and passing test output, and a note naming each request field the repaired profile update ignores.
Complete when: All 14 tests pass, the owner can still read their invoice, and a request cannot change role or tenant through the profile update.
Needs: Internet access for npm ci, which downloads the pinned packages; the tests run on localhost only.
Open project : Secure a real HTTP APIRun the file upload lab: require the extension, declared type and first bytes to agree on PNG or JPEG within 512 KiB, store the file outside the web root under a generated name, and serve it as an image attachment with nosniff.
Keep: A repaired upload decision with the lab's passing cases.
Complete when: SVG and HTML uploads, renamed and double-extension files, ../ names and oversize files are refused or neutralized, while PNG, JPEG, .JPG, .jpeg and a file of exactly 512 KiB are still accepted.
Open lab : File upload lab: Accept avatars without publishing pagesReview the six process calls in the guide’s exercise and classify each as shell injection, argument injection or safe; then run one language’s example and its regression test.
Keep: A table of the six calls with the weakness, the fixed call and the payload your test sends.
Complete when: Explain why an argument array stops a semicolon but not an option such as --output=, and where --end-of-options replaces --.
Open guide : Run external programs without command or argument injectionWork through the guide’s six customization features and decide which compile input as code, then run the Python template and formula tests.
Keep: A findings table with the weakness, the fix and the probe each regression test sends.
Complete when: Show that the probe {{ 7 * 7 }} comes back as text from the fixed template, and justify where a sandbox is still needed.
Open guide : Keep untrusted input out of eval, expression languages and templatesRelease a tenant-scoped receipt import
Use the complete synthetic fixture below in a notebook or text file. No live target, paid service or secret is needed. Make your own decision before opening the worked assessment. Then take the implementation option below, a local project in which you repair running code until its tests pass, and keep its test output with your written answers.
You own a receipt-import API. Review the proposed change, specify the repair, and write the evidence a reviewer would need before release.
Supplied material
Actors: Ana = user u1, tenant north; Ben = user u2, tenant north; Cy = user u3, tenant south.
Invoice I-7: tenant north, owner u1, amount 2400 cents, status pending.
Invoice I-9: tenant south, owner u3, amount 1700 cents, status pending.
Policy: only the owner in the active tenant can attach a receipt. Uploads remain private while quarantined.
POST /invoices/{id}/receipts accepts invoiceId, tenantId, filename and bytes.
Proposed handler: SELECT * FROM invoices WHERE id = '<route id>'; check row.tenant == body.tenantId; write bytes to /public/<filename>; return its URL.
Payment provider contract: verify its signature over the exact raw body, then parse the event; delivery is at least once. Event identity is (provider account,event ID).
Deliveries: D1 valid signature, account merchant-A, event e44, invoice I-7, amount 2400; D2 is a byte-identical retry; D3 same event ID but invalid signature; D4 valid event e45 for I-7 but amount 2300.
Local accepted event and payment must be committed in one transaction. No external money transfer is part of this fixture.
An upload-service token was copied into a CI log; deleting that log does not revoke it.Work through the case
Mark each source of identity and data as authoritative or caller-controlled. List the independent query, permission, file-publication and credential problems.
Write a replacement handler contract with parameter binding, owner-and-tenant enforcement, generated storage IDs, a private quarantine state and authorized download.
Build a decision table for Ana/Ben/Cy attaching to I-7 and Ana attaching to I-9. Add ordinary and SQL-metacharacter route inputs.
Specify D1–D4 payment outcomes and an atomic event/effect transaction. Record token revocation, replacement and affected-consumer checks.
Decide the fixed cases
These parts of the case have one right answer, taken from the worked assessment. Check them here; the rubric below assesses your written reasoning. The capstone meets the bar when every decision is right and the self-check reaches it.
What happens to each payment delivery?
Who may attach a receipt?
Evidence to retain
- Four-row actor/object matrix with reasons.
- Upload lifecycle diagram and safe query shape.
- Delivery/effect ledger including invalid and mismatched events.
- Credential containment and closure checklist tied to the leaked token.
Assess your work
Score each criterion with the anchor whose evidence your answer shows: 0, 1 or 2 points. Every anchor describes something a reviewer can point to in your work. Aim for at least 7 of 8, with no unresolved critical failure.
Score your answer against the anchors
Choose the anchor that matches your answer for each criterion.
Recorded checks stay in this browser only, so you can compare attempts. This is a self-assessment, not a certification.
Compare with the worked assessment
D1 records one accepted event and changes I-7 from pending to paid for 2400. D2 returns the saved outcome without another effect. D3 is rejected before trusting the event identity. D4 is authenticated but inconsistent with the invoice amount and must not change payment state. Only Ana→I-7 may attach; Ben fails ownership, Cy fails tenant and ownership, Ana→I-9 fails tenant and ownership. Tenant identity comes from authenticated context, not body. Query parameterization and object permission solve separate defects. Quarantine bytes are not public. Close the credential incident only after the old credential is unusable and legitimate consumers work with its replacement.
Save a draft on this device to resume later. Automatic saving begins after you choose Save. Drafts are never sent by this application; use synthetic data.
No draft saved on this device yet.
Implementation option: Secure a real HTTP API
Repair invoice authorization and the profile update in exercise.mjs until all 14 tests pass, then add a test of your own for the metacharacter row of your decision table: a request for an invoice ID such as one' OR '1'='1 must return 404 like any other unknown ID.
Keep: The failing starter output, the passing output after your repair, and the test you added with the row of the decision table it covers.
Node.js 22+ · npm · 45–60 min · 14 tests
Other connected projects
- Keep extracted files inside their boundary — Python 3.11+ · standard library
Browser and API boundaries
Protect state changes, browser policies, rendering, object access and concurrent business operations, repairing seven concrete defects along the way.
Your progress, your browser
Progress is stored on this device. Export it to carry it to another browser, or clear it whenever you want. Importing a file adds its completed items to the progress already here; items this site no longer offers are skipped and counted, and nothing else is removed.