Overview

The praisonai-platform, specifically the dependency endpoints, is susceptible to an IDOR attack due to missing ownership checks. The affected endpoints include `POST/GET /workspaces/{workspace_id}/issues/{issue_id}/dependencies` and `DELETE .../dependencies/{dep_id}`. These endpoints only gate access based on `require_workspace_member(workspace_id)`, but then dispatch to `DependencyService` calls without verifying if the supplied issue and dependency IDs belong to the membership-checked workspace.

Technical Details

The vulnerability is rooted in the `DependencyService` layer, where methods take raw IDs and query them directly without workspace verification. Specifically: - `create(issue_id, depends_on_issue_id, ...)` writes a row with no workspace verification on either ID. - `list_for_issue(issue_id)` returns dependencies for any issue. - `delete(dep_id)` deletes any dependency by ID. The most damaging aspect is that `create_dependency` accepts `body.depends_on_issue_id` from the request body without checking it against anything, allowing an attacker to create links between any two issues across different workspaces.

Impact Analysis

The impact of this vulnerability is significant, with a CVSS score of 7.6. An attacker can: - Read any issue's dependency graph. - Create arbitrary 'blocks' / 'blocked_by' / 'related' links between any two issues across any two workspaces. - Delete any dependency by ID. This can lead to workflow disruption, data integrity issues, and confidentiality breaches across multiple workspaces.

Mitigation

To mitigate this vulnerability, the following steps are recommended: 1. Resolve every issue ID (URL and body) against `workspace_id` at the route layer before dispatching. 2. Apply the `issue_svc.get(workspace_id, issue_id)` precondition to `list_dependencies` and `delete_dependency` to verify both the issue and the dependency belong to `workspace_id`. Example of the suggested fix: ```diff --- a/src/praisonai-platform/praisonai_platform/api/routes/dependencies.py +++ b/src/praisonai-platform/praisonai_platform/api/routes/dependencies.py @@ -22,11 +22,16 @@ @router.post("/", response_model=DependencyResponse, status_code=status.HTTP_201_CREATED) async def create_dependency( workspace_id: str, issue_id: str, body: DependencyCreate, user: AuthIdentity = Depends(require_workspace_member), session: AsyncSession = Depends(get_db), ): + issue_svc = IssueService(session) + if await issue_svc.get(workspace_id, issue_id) is None: + raise HTTPException(status_code=404, detail="Issue not found") + if await issue_svc.get(workspace_id, body.depends_on_issue_id) is None: + raise HTTPException(status_code=404, detail="depends_on_issue_id not found in this workspace") svc = DependencyService(session) dep = await svc.create(issue_id, body.depends_on_issue_id, body.type) return DependencyResponse.model_validate(dep) ``` By implementing these changes, the vulnerability can be effectively mitigated, ensuring that only authorized users can create, read, and delete dependencies within their respective workspaces.