Skip to content

security: learning-path APIs accept trivially weak client-chosen tokens (length/entropy only advisory in docstring) #1874

Description

@ionfwsrijan

Summary

The learning-path APIs use the client-chosen X-Learning-Path-Token as the only authorization secret, but the API accepts any token value with no length/entropy requirement. The route docstring merely advises callers to use "a random UUID or similar" — it is not enforced. Anyone who can guess or reuse a weak token (e.g. "test", "1234", an empty-ish string, or a token the client also echoes in URLs) can read and overwrite the path's data, which contains the user's full learning-path state.

Evidence

src/routes/main_routes.py:940-974 (create_learning_path route):

token = _extract_token(request)
if not token:
    return jsonify({"error": f"'{_TOKEN_HEADER}' header is required."}), 400
...

Only the header's presence is checked. The docstring itself concedes the weakness:

X-Learning-Path-Token  (required) - the secret token chosen by the
                       client (should be a random UUID or similar).

Read/update/progress routes (main_routes.py:993, 1026, 1164) likewise accept any non-empty token and compare it with secrets.compare_digest against the stored owner token (learning_path.py). There is no server-side token generation, no uuid validation, and no entropy floor.

Impact

  • The security of every learning path rests entirely on an unvalidated client-supplied string.
  • Paths created with short/guessable tokens are trivially readable and overwritable by third parties (the GET route is rate-limited at 20/min but guessing a 4-char token is far below that threshold).

Suggested Fix

  • Validate the token server-side: require a minimum length (e.g. >= 16) and optionally require UUID format (uuid.UUID(token)), or generate the token server-side and return it to the client.
  • Document the requirement in the route docstring and add a route-level test rejecting weak tokens.

Metadata

Metadata

Assignees

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions