Secure an Express API with real HTTP and signed tokens
Requires Node.js 22 or newer and npm. Installation downloads the pinned dependencies.

Reference solution: not included here, so the exercise does not hand you the answer.
Attempt the repair first. Then download express-api-solution.zip from the project card
on https://softwaresecurity.com/labs/#project-express-api and extract it into this folder;
it adds reference.mjs without changing your files, and the reference commands below
need it.

1. In this extracted folder run: npm ci --ignore-scripts
   [Needs internet access to the npm registry; everything after it runs locally.]
2. Run: npm test
   The server listens on a random localhost port only during tests, then closes.
   Authentication cases pass; same-tenant access and profile-property tests expose
   the deliberate policy defects. Every token and key is generated for this run.
3. Read app.mjs: jwtVerify pins issuer, audience, algorithm and access-token type.
   Authentication gives a verified subject; it does not grant invoice access.
4. Repair canReadInvoice in exercise.mjs. Require both tenant and owner equality.
   Keep the legitimate owner case passing and use 404 for unavailable resources.
5. Repair selectProfileUpdate. Validate displayName and construct a new object
   with that field only. Never copy role or tenant from user input.
6. Run npm test. All 14 tests should pass. Change the same-tenant policy back to
   observe which test catches it. Compare reference.mjs after attempting the fix.

Reference check (macOS/Linux): EXERCISE_MODULE=reference npm test
PowerShell: $env:EXERCISE_MODULE='reference'; npm test
Then remove the environment variable before testing your own repair.

Scope: actual Express routing, HTTP parsing, JOSE signature and claim validation.
The project uses in-memory invoices and a synthetic profile update; it is not an
identity provider or persistence layer. Production deployments still need HTTPS,
key discovery/rollover, rate limits, persistence authorization and operational
monitoring. It uses bearer tokens; this is not a cookie/CSRF implementation.
Sources:
https://expressjs.com/en/5x/api.html
https://github.com/panva/jose/blob/main/docs/jwt/verify/functions/jwtVerify.md
https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html

Static analysis (optional)
semgrep/mass-assignment.yaml holds Semgrep rules for the defect in this project,
and semgrep/mass-assignment.mjs holds their test cases. With Semgrep installed
(python3 -m pip install semgrep), run from this folder:
   semgrep --test semgrep/
   semgrep scan --metrics=off --config semgrep/mass-assignment.yaml exercise.mjs
The starter is reported at line 6; the reference solution is not. Checked with
Semgrep 1.180.0. The rule finds a request body copied whole into an update. It
cannot judge canReadInvoice: whether a caller may read an invoice is policy that
only the tests decide.

Dev container
.devcontainer/devcontainer.json opens this folder in VS Code Dev Containers or
GitHub Codespaces using the Dev Containers Node.js 24 image, pinned by digest.
Creating the container runs npm ci --ignore-scripts. Run the commands above in
its terminal.
