Every CVE Search/ Get API key

CVE-2026-47407

PraisonAI Platform has a cross-workspace IDOR + member-role privilege escalation

9.4 CriticalFix available

PraisonAI Platform is the platform layer for the PraisonAI multi-agent teams system. Prior to version 0.1.4, the Platform server exposes resources under /api/v1/workspaces/{workspace_id}/... and protects them with a require_workspace_member(workspace_id) FastAPI dependency. The dependency only checks that the caller is a member of the workspace_id in the URL prefix. The route handlers then look up the inner resource (agent_id, issue_id, project_id, label_id, comment_id, dependency_id) by primary key alone. The resource's own workspace_id is never compared to the URL's workspace_id. A user can therefore put their own workspace in the URL prefix and any other workspace's resource ID in the path. The auth check passes, since they really are a member of the prefix workspace. The service then returns the cross-tenant resource for read, update, or delete. There is a second bug in the member-management routes (add_member, update_member_role, remove_member, update_workspace, delete_workspace). Each one inherits the default min_role="member" from require_workspace_member. Any basic member can therefore promote themselves to admin or owner, demote or remove other members, and delete the workspace. The role hierarchy exists in the schema but is not enforced. Registration is open at /api/v1/auth/register with no email verification. The default server bind is 0.0.0.0:8000 (python -m praisonai_platform). One curl from any unauthenticated network position is enough to bootstrap into the system. PraisonAI Platform version 0.1.4 patches the issue.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
Low
User interaction
None

What an attacker can affect

Confidentiality
High
Integrity
High
Availability
High

Exploit likelihood

0.30%Up 0.3 points since Jun 12, 2026
90%50%10%1%

What each source reports

CVE List Score used 9.4

PraisonAI Platform has a cross-workspace IDOR + member-role privilege escalation

PraisonAI Platform is the platform layer for the PraisonAI multi-agent teams system. Prior to version 0.1.4, the Platform server exposes resources under /api/v1/workspaces/{workspace_id}/... and protects them with a require_workspace_member(workspace_id) FastAPI dependency. The dependency only checks that the caller is a member of the workspace_id in the URL prefix. The route handlers then look up the inner resource (agent_id, issue_id, project_id, label_id, comment_id, dependency_id) by primary key alone. The resource's own workspace_id is never compared to the URL's workspace_id. A user can therefore put their own workspace in the URL prefix and any other workspace's resource ID in the path. The auth check passes, since they really are a member of the prefix workspace. The service then returns the cross-tenant resource for read, update, or delete. There is a second bug in the member-management routes (add_member, update_member_role, remove_member, update_workspace, delete_workspace). Each one inherits the default min_role="member" from require_workspace_member. Any basic member can therefore promote themselves to admin or owner, demote or remove other members, and delete the workspace. The role hierarchy exists in the schema but is not enforced. Registration is open at /api/v1/auth/register with no email verification. The default server bind is 0.0.0.0:8000 (python -m praisonai_platform). One curl from any unauthenticated network position is enough to bootstrap into the system. PraisonAI Platform version 0.1.4 patches the issue.

Record
CVE-2026-47407
CVSS 4.0
9.4 CriticalCVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H
Weakness
CWE-269, CWE-639, CWE-863
Updated
2026-11-02
EUVDEUVD-2026-46319 9.4

PraisonAI Platform is the platform layer for the PraisonAI multi-agent teams system. Prior to version 0.1.4, the Platform server exposes resources under /api/v1/workspaces/{workspace_id}/... and protects them with a require_workspace_member(workspace_id) FastAPI dependency. The dependency only checks that the caller is a member of the workspace_id in the URL prefix. The route handlers then look up the inner resource (agent_id, issue_id, project_id, label_id, comment_id, dependency_id) by primary key alone. The resource's own workspace_id is never compared to the URL's workspace_id. A user can therefore put their own workspace in the URL prefix and any other workspace's resource ID in the path. The auth check passes, since they really are a member of the prefix workspace. The service then returns the cross-tenant resource for read, update, or delete. There is a second bug in the member-management routes (add_member, update_member_role, remove_member, update_workspace, delete_workspace). Each one inherits the default min_role="member" from require_workspace_member. Any basic member can therefore promote themselves to admin or owner, demote or remove other members, and delete the workspace. The role hierarchy exists in the schema but is not enforced. Registration is open at /api/v1/auth/register with no email verification. The default server bind is 0.0.0.0:8000 (python -m praisonai_platform). One curl from any unauthenticated network position is enough to bootstrap into the system. PraisonAI Platform version 0.1.4 patches the issue.

Record
EUVD-2026-46319
CVSS 4.0
9.4 CriticalCVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H
Updated
2026-11-02
GitHub AdvisoriesGHSA-h8q5-cp56-rr65 9.4

PraisonAI Platform has a cross-workspace IDOR + member-role privilege escalation

Summary

The Platform server exposes resources under /api/v1/workspaces/{workspace_id}/... and protects them with a require_workspace_member(workspace_id) FastAPI dependency. The dependency only checks that the caller is a member of the workspace_id in the URL prefix. The route handlers then look up the inner resource (agent_id, issue_id, project_id, label_id, comment_id, dependency_id) by primary key alone. The resource's own workspace_id is never compared to the URL's workspace_id.

A user can therefore put their own workspace in the URL prefix and any other workspace's resource ID in the path. The auth check passes, since they really are a member of the prefix workspace. The service then returns the cross-tenant resource for read, update, or delete.

There is a second bug in the member-management routes (add_member, update_member_role, remove_member, update_workspace, delete_workspace). Each one inherits the default min_role="member" from require_workspace_member. Any basic member can therefore promote themselves to admin or owner, demote or remove other members, and delete the workspace. The role hierarchy exists in the schema but is not enforced.

Registration is open at /api/v1/auth/register with no email verification. The default server bind is 0.0.0.0:8000 (python -m praisonai_platform). One curl from any unauthenticated network position is enough to bootstrap into the system.

Affected functionality

Every nested-resource route under /api/v1/workspaces/{workspace_id}/...:

| File | Routes | |------|--------| | routes/agents.py | GET /agents/{agent_id}, PATCH /agents/{agent_id}, DELETE /agents/{agent_id} | | routes/issues.py | GET /issues/{issue_id}, PATCH /issues/{issue_id}, DELETE /issues/{issue_id}, POST /issues/{issue_id}/comments, GET /issues/{issue_id}/comments | | routes/projects.py | GET /projects/{project_id}, PATCH /projects/{project_id}, DELETE /projects/{project_id}, GET /projects/{project_id}/stats | | routes/labels.py | PATCH /labels/{label_id}, DELETE /labels/{label_id}, POST /issues/{issue_id}/labels/{label_id}, DELETE /issues/{issue_id}/labels/{label_id}, GET /issues/{issue_id}/labels | | routes/dependencies.py | every route | | routes/workspaces.py | PATCH /{workspace_id}, DELETE /{workspace_id}, POST /{workspace_id}/members, PATCH /{workspace_id}/members/{user_id}, DELETE /{workspace_id}/members/{user_id} (these have a role-enforcement bug rather than a cross-tenant bug) |

Root cause

A. The auth dependency only sees the URL prefix

src/praisonai-platform/praisonai_platform/api/deps.py:54-73:

async def require_workspace_member(
    workspace_id: str,
    user: AuthIdentity = Depends(get_current_user),
    session: AsyncSession = Depends(get_db),
    min_role: str = "member",
) -> AuthIdentity:
    member_svc = MemberService(session)
    has = await member_svc.has_role(workspace_id, user.id, min_role)
    if not has:
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=...)
    user.workspace_id = workspace_id
    return user

This only validates that the user is a member of the URL workspace_id. It does not (and cannot, given its signature) validate any inner resource ID.

B. The service-layer lookups are unscoped

Example, src/praisonai-platform/praisonai_platform/services/agent_service.py:53-55:

async def get(self, agent_id: str) -> Optional[Agent]:
    return await self._session.get(Agent, agent_id)

And the route, src/praisonai-platform/praisonai_platform/api/routes/agents.py:53-64:

@router.get("/{agent_id}", response_model=AgentResponse)
async def get_agent(workspace_id: str, agent_id: str,
                    user: AuthIdentity = Depends(require_workspace_member),
                    session: AsyncSession = Depends(get_db)):
    svc = AgentService(session)
    agent = await svc.get(agent_id)             # ← no…
Record
GHSA-h8q5-cp56-rr65
CVSS 4.0
9.4 CriticalCVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H
Weakness
CWE-269, CWE-639, CWE-863
Updated
2026-11-02
NVD 9.4

PraisonAI Platform is the platform layer for the PraisonAI multi-agent teams system. Prior to version 0.1.4, the Platform server exposes resources under /api/v1/workspaces/{workspace_id}/... and protects them with a require_workspace_member(workspace_id) FastAPI dependency. The dependency only checks that the caller is a member of the workspace_id in the URL prefix. The route handlers then look up the inner resource (agent_id, issue_id, project_id, label_id, comment_id, dependency_id) by primary key alone. The resource's own workspace_id is never compared to the URL's workspace_id. A user can therefore put their own workspace in the URL prefix and any other workspace's resource ID in the path. The auth check passes, since they really are a member of the prefix workspace. The service then returns the cross-tenant resource for read, update, or delete. There is a second bug in the member-management routes (add_member, update_member_role, remove_member, update_workspace, delete_workspace). Each one inherits the default min_role="member" from require_workspace_member. Any basic member can therefore promote themselves to admin or owner, demote or remove other members, and delete the workspace. The role hierarchy exists in the schema but is not enforced. Registration is open at /api/v1/auth/register with no email verification. The default server bind is 0.0.0.0:8000 (python -m praisonai_platform). One curl from any unauthenticated network position is enough to bootstrap into the system. PraisonAI Platform version 0.1.4 patches the issue.

Record
CVE-2026-47407
CVSS 4.0
9.4 CriticalCVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/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
Weakness
CWE-269, CWE-639, CWE-863
Updated
2026-11-02
OSV 9.4

PraisonAI Platform has a cross-workspace IDOR + member-role privilege escalation

PraisonAI Platform is the platform layer for the PraisonAI multi-agent teams system. Prior to version 0.1.4, the Platform server exposes resources under /api/v1/workspaces/{workspace_id}/... and protects them with a require_workspace_member(workspace_id) FastAPI dependency. The dependency only checks that the caller is a member of the workspace_id in the URL prefix. The route handlers then look up the inner resource (agent_id, issue_id, project_id, label_id, comment_id, dependency_id) by primary key alone. The resource's own workspace_id is never compared to the URL's workspace_id. A user can therefore put their own workspace in the URL prefix and any other workspace's resource ID in the path. The auth check passes, since they really are a member of the prefix workspace. The service then returns the cross-tenant resource for read, update, or delete. There is a second bug in the member-management routes (add_member, update_member_role, remove_member, update_workspace, delete_workspace). Each one inherits the default min_role="member" from require_workspace_member. Any basic member can therefore promote themselves to admin or owner, demote or remove other members, and delete the workspace. The role hierarchy exists in the schema but is not enforced. Registration is open at /api/v1/auth/register with no email verification. The default server bind is 0.0.0.0:8000 (python -m praisonai_platform). One curl from any unauthenticated network position is enough to bootstrap into the system. PraisonAI Platform version 0.1.4 patches the issue.

Record
CVE-2026-47407
CVSS 4.0
9.4 CriticalCVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H
Weakness
CWE-269, CWE-639, CWE-863
Updated
2026-11-02
OSVGHSA-h8q5-cp56-rr65 9.4

PraisonAI Platform has a cross-workspace IDOR + member-role privilege escalation

Summary

The Platform server exposes resources under /api/v1/workspaces/{workspace_id}/... and protects them with a require_workspace_member(workspace_id) FastAPI dependency. The dependency only checks that the caller is a member of the workspace_id in the URL prefix. The route handlers then look up the inner resource (agent_id, issue_id, project_id, label_id, comment_id, dependency_id) by primary key alone. The resource's own workspace_id is never compared to the URL's workspace_id.

A user can therefore put their own workspace in the URL prefix and any other workspace's resource ID in the path. The auth check passes, since they really are a member of the prefix workspace. The service then returns the cross-tenant resource for read, update, or delete.

There is a second bug in the member-management routes (add_member, update_member_role, remove_member, update_workspace, delete_workspace). Each one inherits the default min_role="member" from require_workspace_member. Any basic member can therefore promote themselves to admin or owner, demote or remove other members, and delete the workspace. The role hierarchy exists in the schema but is not enforced.

Registration is open at /api/v1/auth/register with no email verification. The default server bind is 0.0.0.0:8000 (python -m praisonai_platform). One curl from any unauthenticated network position is enough to bootstrap into the system.

Affected functionality

Every nested-resource route under /api/v1/workspaces/{workspace_id}/...:

| File | Routes | |------|--------| | routes/agents.py | GET /agents/{agent_id}, PATCH /agents/{agent_id}, DELETE /agents/{agent_id} | | routes/issues.py | GET /issues/{issue_id}, PATCH /issues/{issue_id}, DELETE /issues/{issue_id}, POST /issues/{issue_id}/comments, GET /issues/{issue_id}/comments | | routes/projects.py | GET /projects/{project_id}, PATCH /projects/{project_id}, DELETE /projects/{project_id}, GET /projects/{project_id}/stats | | routes/labels.py | PATCH /labels/{label_id}, DELETE /labels/{label_id}, POST /issues/{issue_id}/labels/{label_id}, DELETE /issues/{issue_id}/labels/{label_id}, GET /issues/{issue_id}/labels | | routes/dependencies.py | every route | | routes/workspaces.py | PATCH /{workspace_id}, DELETE /{workspace_id}, POST /{workspace_id}/members, PATCH /{workspace_id}/members/{user_id}, DELETE /{workspace_id}/members/{user_id} (these have a role-enforcement bug rather than a cross-tenant bug) |

Root cause

A. The auth dependency only sees the URL prefix

src/praisonai-platform/praisonai_platform/api/deps.py:54-73:

async def require_workspace_member(
    workspace_id: str,
    user: AuthIdentity = Depends(get_current_user),
    session: AsyncSession = Depends(get_db),
    min_role: str = "member",
) -> AuthIdentity:
    member_svc = MemberService(session)
    has = await member_svc.has_role(workspace_id, user.id, min_role)
    if not has:
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=...)
    user.workspace_id = workspace_id
    return user

This only validates that the user is a member of the URL workspace_id. It does not (and cannot, given its signature) validate any inner resource ID.

B. The service-layer lookups are unscoped

Example, src/praisonai-platform/praisonai_platform/services/agent_service.py:53-55:

async def get(self, agent_id: str) -> Optional[Agent]:
    return await self._session.get(Agent, agent_id)

And the route, src/praisonai-platform/praisonai_platform/api/routes/agents.py:53-64:

@router.get("/{agent_id}", response_model=AgentResponse)
async def get_agent(workspace_id: str, agent_id: str,
                    user: AuthIdentity = Depends(require_workspace_member),
                    session: AsyncSession = Depends(get_db)):
    svc = AgentService(session)
    agent = await svc.get(agent_id)             # ← no…
Record
GHSA-h8q5-cp56-rr65
CVSS 4.0
9.4 CriticalCVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H
Weakness
CWE-269, CWE-639, CWE-863
Updated
2026-11-02
OSVPYSEC-2026-482 9.4

PraisonAI Platform has a cross-workspace IDOR + member-role privilege escalation

Summary

The Platform server exposes resources under /api/v1/workspaces/{workspace_id}/... and protects them with a require_workspace_member(workspace_id) FastAPI dependency. The dependency only checks that the caller is a member of the workspace_id in the URL prefix. The route handlers then look up the inner resource (agent_id, issue_id, project_id, label_id, comment_id, dependency_id) by primary key alone. The resource's own workspace_id is never compared to the URL's workspace_id.

A user can therefore put their own workspace in the URL prefix and any other workspace's resource ID in the path. The auth check passes, since they really are a member of the prefix workspace. The service then returns the cross-tenant resource for read, update, or delete.

There is a second bug in the member-management routes (add_member, update_member_role, remove_member, update_workspace, delete_workspace). Each one inherits the default min_role="member" from require_workspace_member. Any basic member can therefore promote themselves to admin or owner, demote or remove other members, and delete the workspace. The role hierarchy exists in the schema but is not enforced.

Registration is open at /api/v1/auth/register with no email verification. The default server bind is 0.0.0.0:8000 (python -m praisonai_platform). One curl from any unauthenticated network position is enough to bootstrap into the system.

Affected functionality

Every nested-resource route under /api/v1/workspaces/{workspace_id}/...:

| File | Routes | |------|--------| | routes/agents.py | GET /agents/{agent_id}, PATCH /agents/{agent_id}, DELETE /agents/{agent_id} | | routes/issues.py | GET /issues/{issue_id}, PATCH /issues/{issue_id}, DELETE /issues/{issue_id}, POST /issues/{issue_id}/comments, GET /issues/{issue_id}/comments | | routes/projects.py | GET /projects/{project_id}, PATCH /projects/{project_id}, DELETE /projects/{project_id}, GET /projects/{project_id}/stats | | routes/labels.py | PATCH /labels/{label_id}, DELETE /labels/{label_id}, POST /issues/{issue_id}/labels/{label_id}, DELETE /issues/{issue_id}/labels/{label_id}, GET /issues/{issue_id}/labels | | routes/dependencies.py | every route | | routes/workspaces.py | PATCH /{workspace_id}, DELETE /{workspace_id}, POST /{workspace_id}/members, PATCH /{workspace_id}/members/{user_id}, DELETE /{workspace_id}/members/{user_id} (these have a role-enforcement bug rather than a cross-tenant bug) |

Root cause

A. The auth dependency only sees the URL prefix

src/praisonai-platform/praisonai_platform/api/deps.py:54-73:

 async def require_workspace_member(
    workspace_id: str,
    user: AuthIdentity = Depends(get_current_user),
    session: AsyncSession = Depends(get_db),
    min_role: str = "member",
) -> AuthIdentity:
    member_svc = MemberService(session)
    has = await member_svc.has_role(workspace_id, user.id, min_role)
    if not has:
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=...)
    user.workspace_id = workspace_id
    return user

This only validates that the user is a member of the URL workspace_id. It does not (and cannot, given its signature) validate any inner resource ID.

B. The service-layer lookups are unscoped

Example, src/praisonai-platform/praisonai_platform/services/agent_service.py:53-55:

async def get(self, agent_id: str) -> Optional[Agent]:
   return await self._session.get(Agent, agent_id)

And the route, src/praisonai-platform/praisonai_platform/api/routes/agents.py:53-64:

@router.get("/{agent_id}", response_model=AgentResponse)
async def get_agent(workspace_id: str, agent_id: str,
                    user: AuthIdentity = Depends(require_workspace_member),
                    session: AsyncSession = Depends(get_db)):
    svc = AgentService(session)
    agent = await svc.get(agent_id)             # ← no…
Record
PYSEC-2026-482
CVSS 4.0
9.4 CriticalCVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
praisonai-platform
PyPI
through 0.1.2
0.1.4
praisonai-platform
PyPI
before 0.1.4, plus listed versions
0.1.00.1.10.1.20.1.3
0.1.4

History

History
RecordedChangedSources
aliasesEUVD
first indexedCVE List, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-47407 is a critical vulnerability (CVSS 9.4) in Mervinpraison Praisonai-platform, published May 29, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.30%, the 23rd percentile. Fixed in praisonai-platform 0.1.4.

References

This page doesn't list everything

Left out here: the rest of 3 source descriptions. The JSON record has them.

MoveEnter Open