Start learning free

LESSON 14 OF 20 · SECURITY: TOKENS AND SESSIONS

Project: Find the Holes

Practice

This project is a small shop API, already written, with four holes from this section. Your job is an audit: for each hole, see what the attacker gets, then close it with one check while honest visitors keep working.

The four attacks: read_token never checks the signature, so a visitor who writes their own token with {"customer_id": 2} reads another customer's orders. Anyone who reads the log sees Ana's password. GET /help/../secrets.txt hands out the token secret and the supplier's API key. And /continue?next=https://evil.example/login turns a link on the shop's own address into a trip to the attacker's page.

How to spot them: every value that comes from the request, a token, a JSON field, a path or a query parameter, is the visitor's choice. In this route from another shop, file=../app.py would read the shop's own code:

@app.get("/download")
def download():
    file = request.args.get("file")   # the visitor picks this
    return send_file(os.path.join("files", file))

The requests and answers your code must give:

POST /login  {"email": "ana@example.com", "password": "ana-pass-123"}  →  200  {"token": "<token>"}
GET /_test/log  →  200  ["POST /login {'email': 'ana@example.com', 'password': '***'}"]
GET /orders  with Ana's token  →  200  [{"id": 1, "ordered": "2026-03-02", "status": "paid"}, {"id": 3, "ordered": "2026-04-05", "status": "paid"}]
GET /orders  with a forged token for customer 2  →  401  {"error": "Login required"}
GET /help/shipping.txt  →  200  We ship every order within 2 working days.
GET /help/../secrets.txt  →  404  {"error": "Page not found"}
GET /continue?next=/orders  →  302  Location: /orders
GET /continue?next=https://evil.example/login  →  302  Location: /
GET /continue?next=//evil.example/login  →  302  Location: /

Your task: close the four holes: refuse a token whose signature doesn't match, hide the password in the log, answer 404 for a help path that leaves the help folder, and send any next that isn't a page of the shop to /.


Assignment
Follow the Coding Tutorial to add one check to each of read_token, log_request, help_page and continue_to.


Hint
Each fix is an if with one line inside. Compare signatures with hmac.compare_digest, compare the real path with HELP + os.sep so a folder like help-old doesn't slip through, and remember that a browser reads //evil.example as another website.


STEP 1 OF 8
    Ctrl + Enter to check