Missing Object-Level Authorization in Phproject REST API Issue Endpoints
What fixes it
- 1.8.7phprojectGitHub
A fixed version on one release line is not the upgrade target for every line. Check your exact version and any vendor backports.
Description
Summary
The three API endpoints load an issue by id and check only that the row exists (if ($issue->id)), never calling Model\Issue::allowAccess(). When an administrator has enabled security.restrict_access (which limits issue visibility to the owner, author, or group), any authenticated principal with a valid API key can therefore read the full contents and comments of any issue, including owner and author email addresses, and post comments to restricted issues. The same codebase enforces allowAccess() in the web UI issue view and in the sibling write endpoints single_put and single_delete, making this an inconsistent, missing authorization check at these specific call sites rather than intended behavior.
Details
app/controller/api/issues.phpsingle_get(GET/issues/@id.json), approx. line 291single_comments(GET/issues/@id/comments.json), approx. line 324single_comments_post(POST/issues/@id/comments.json), approx. line 345app/model/issue.php:allowAccess(), approx. line 605 (authorization routine that is not called by the endpoints above)- Reference enforcement that is present elsewhere:
app/controller/issues.php(web UI, lines 217 and 436) and the sibling API methodssingle_put(line 255) andsingle_delete(line 313), all of which do callallowAccess().
Proof of concept
Preconditions: security.restrict_access=1; a confidential issue #1 owned by user alice; a low privilege user bob in an unrelated group with his own API key.
# Denied in the web UI: GET /issues/1 -> HTTP 404 # Allowed through the API with bob's key: curl "$B/issues/1.json?key=$BOB_KEY" curl "$B/issues/1/comments.json?key=$BOB_KEY" curl -X POST "$B/issues/1/comments.json?key=$BOB_KEY" --data-urlencode "text=INJECTED-BY-BOB"
Confirmed output:
api GET /issues/1.json -> HTTP 200 {"issue":{"name":"CONFIDENTIAL: acquisition salary
figures","description":"...secret-token=RS_9f13ac.","owner":
{"username":"alice","email":"alice@test.local"}}}
api GET /issues/1/comments.json -> HTTP 200 [{"text":"Internal comment: board approved 2026-10."}]
api POST /issues/1/comments.json -> HTTP 200 {"id":2,"issue_id":1,"user_id":2(bob),"text":"INJECTED-BY-BOB"}Reproduced deterministically; the web UI returns HTTP 404 for the same user while the API returns HTTP 200.
Impact
Any authenticated account or API key holder can defeat the security.restrict_access confidentiality control: full read of all restricted issues and their comments, including owner and author email addresses, plus unauthorized comment writes to restricted issues. API keys are long lived and per user, and no CSRF or user interaction is required. The read exposure affects every restricted issue in the instance, not only the attacker's own, and written comments persist on the victim issue.
Text from GitHub Advisory Database
Affected versions 1
- phproject<= 1.8.6GitHub