Software Securityhome
Fix a findingSearch
Learning path · Foundation · Software developers

Developer foundations

Start at the data boundary. Build habits that make common defects harder to introduce.

WHAT YOU WILL BUILD
  • 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.
BEFORE YOU START
  • 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.

Keep the artifacts from each step together. Mark a step complete after checking its stated outcome. A lab or guide you complete here also shows as complete in other paths that include it.

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 sqlite3

Run 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 sqlite3

Use 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 action

Edit 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 bug

Draw 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 pipeline

Run 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 traversal

Use 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 response

Trace 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 acting

Use 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 twice

Download 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 API

Run 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 pages

Review 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 injection

Work 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 templates
FINAL APPLICATION · FRESH SCENARIO

Release 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

Plain text
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

  1. Mark each source of identity and data as authoritative or caller-controlled. List the independent query, permission, file-publication and credential problems.

  2. Write a replacement handler contract with parameter binding, owner-and-tenant enforcement, generated storage IDs, a private quarantine state and authorized download.

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

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

D1: valid signature, merchant-A, event e44, I-7, 2400
D2: a byte-identical retry of D1
D3: same event ID, invalid signature
D4: valid event e45 for I-7, amount 2300

Who may attach a receipt?

Ana (u1, north) attaches to I-7
Ben (u2, north) attaches to I-7
Cy (u3, south) attaches to I-7
Ana (u1, north) attaches to I-9

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

1. Separates query safety, actor/tenant/owner policy and file state.
2. Preserves the legitimate owner path and rejects every prohibited actor/object pair.
3. Authenticates before deduplication and makes event acceptance plus the local effect atomic.
4. Specifies revocation and post-rotation evidence instead of treating log deletion as closure.
Critical failures: tick any your answer still contains

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.

Download case workbook

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

Next path · Foundation

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.

Find your next answer

Type to search. Search runs in your browser.

Searches run in your browser, but the host can infer them from the index files they load. The address shows your search so you can bookmark or share it.