Every CVE Search/ Get API key

CVE-2026-47399

PraisonAI Platform workspace-scoped routes allow cross-workspace object access by global object ID

8.8 HighFix available

PraisonAI Platform is the platform layer for the PraisonAI multi-agent teams system. Prior to version 0.1.4, the workspace-scoped REST routes contain a systemic object-level authorization flaw that allows an authenticated user from one workspace to access, modify, and delete objects belonging to another workspace by supplying the victim object's global UUID. The affected pattern appears in workspace-scoped routes such as agents, projects, issues, and comments. The route layer verifies that the caller is a member of the workspace_id provided in the URL, but the service layer later resolves the target object by global object ID only. It does not verify that the resolved object actually belongs to the workspace in the URL. As a result, a valid member of workspace_attacker can call a route under /api/v1/workspaces/{workspace_attacker}/... while supplying an object UUID from workspace_victim. The server authorizes the request based on membership in workspace_attacker, then fetches or mutates the victim object by global UUID. This breaks the platform's workspace isolation boundary. 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.36%Up 0.3 points since Jun 12, 2026
90%50%10%1%

What each source reports

CVE List Score used 8.8

PraisonAI Platform workspace-scoped routes allow cross-workspace object access by global object ID

PraisonAI Platform is the platform layer for the PraisonAI multi-agent teams system. Prior to version 0.1.4, the workspace-scoped REST routes contain a systemic object-level authorization flaw that allows an authenticated user from one workspace to access, modify, and delete objects belonging to another workspace by supplying the victim object's global UUID. The affected pattern appears in workspace-scoped routes such as agents, projects, issues, and comments. The route layer verifies that the caller is a member of the workspace_id provided in the URL, but the service layer later resolves the target object by global object ID only. It does not verify that the resolved object actually belongs to the workspace in the URL. As a result, a valid member of workspace_attacker can call a route under /api/v1/workspaces/{workspace_attacker}/... while supplying an object UUID from workspace_victim. The server authorizes the request based on membership in workspace_attacker, then fetches or mutates the victim object by global UUID. This breaks the platform's workspace isolation boundary. PraisonAI Platform version 0.1.4 patches the issue.

Record
CVE-2026-47399
CVSS 3.1
8.8 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-284, CWE-639
Updated
2026-11-02
EUVDEUVD-2026-46313 8.8

PraisonAI Platform is the platform layer for the PraisonAI multi-agent teams system. Prior to version 0.1.4, the workspace-scoped REST routes contain a systemic object-level authorization flaw that allows an authenticated user from one workspace to access, modify, and delete objects belonging to another workspace by supplying the victim object's global UUID. The affected pattern appears in workspace-scoped routes such as agents, projects, issues, and comments. The route layer verifies that the caller is a member of the workspace_id provided in the URL, but the service layer later resolves the target object by global object ID only. It does not verify that the resolved object actually belongs to the workspace in the URL. As a result, a valid member of workspace_attacker can call a route under /api/v1/workspaces/{workspace_attacker}/... while supplying an object UUID from workspace_victim. The server authorizes the request based on membership in workspace_attacker, then fetches or mutates the victim object by global UUID. This breaks the platform's workspace isolation boundary. PraisonAI Platform version 0.1.4 patches the issue.

Record
EUVD-2026-46313
CVSS 3.1
8.8 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Updated
2026-11-02
GitHub AdvisoriesGHSA-6h6v-6m7w-7vxx 8.8

PraisonAI Platform workspace-scoped routes allow cross-workspace object access by global object ID

Summary

PraisonAI Platform's workspace-scoped REST routes contain a systemic object-level authorization flaw that allows an authenticated user from one workspace to access, modify, and delete objects belonging to another workspace by supplying the victim object's global UUID.

The affected pattern appears in workspace-scoped routes such as agents, projects, issues, and comments. The route layer verifies that the caller is a member of the workspace_id provided in the URL, but the service layer later resolves the target object by global object ID only. It does not verify that the resolved object actually belongs to the workspace in the URL.

As a result, a valid member of workspace_attacker can call a route under:

/api/v1/workspaces/{workspace_attacker}/...

while supplying an object UUID from workspace_victim. The server authorizes the request based on membership in workspace_attacker, then fetches or mutates the victim object by global UUID.

This breaks the platform's workspace isolation boundary.

Details

The root cause is that workspace membership authorization and object ownership validation are not bound together.

The workspace dependency validates only that the caller is a member of the workspace named in the URL:

# praisonai_platform/api/deps.py
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)

This confirms that the caller has access to the URL workspace. However, it does not prove that the target object belongs to that workspace.

For example, the agent routes are scoped under a workspace path, but object access is performed using only the raw agent_id:

# praisonai_platform/api/routes/agents.py
@router.get("/{agent_id}", response_model=AgentResponse)
async def get_agent(workspace_id: str, agent_id: str, ...):
    agent = await svc.get(agent_id)
    return AgentResponse.model_validate(agent)

The service method resolves the agent by global UUID only:

# praisonai_platform/services/agent_service.py
async def get(self, agent_id: str) -> Optional[Agent]:
    return await self._session.get(Agent, agent_id)

The same pattern is used for update and delete operations:

# praisonai_platform/api/routes/agents.py
agent = await svc.update(agent_id, ...)

deleted = await svc.delete(agent_id)
# praisonai_platform/services/agent_service.py
agent = await self.get(agent_id)
...
await self._session.delete(agent)

There is no check equivalent to:

agent.workspace_id == workspace_id

Therefore, if an attacker is a valid member of any workspace, they can pass their own workspace ID in the URL while supplying an object ID from another workspace.

The same architectural pattern appears in other workspace-scoped object routes, including projects, issues, and comments:

# praisonai_platform/api/routes/projects.py
project = await svc.get(project_id)
project = await svc.update(project_id, ...)
deleted = await svc.delete(project_id)
# praisonai_platform/services/project_service.py
return await self._session.get(Project, project_id)
# praisonai_platform/api/routes/issues.py
issue = await svc.get(issue_id)
issue = await svc.update(issue_id, ...)
deleted = await svc.delete(issue_id)
comments = await svc.list_for_issue(issue_id)
# praisonai_platform/services/issue_service.py
return await self._session.get(Issue, issue_id)
# praisonai_platform/services/comment_service.py
select(Comment).where(Comment.issue_id == issue_id)

This indicates a systemic object-level access control issue: routes are workspace-scoped, but service-layer object lookups are not workspace-bound.

PoC

The following local…

Record
GHSA-6h6v-6m7w-7vxx
CVSS 3.1
8.8 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-284, CWE-639
Updated
2026-11-02
NVD 8.8

PraisonAI Platform is the platform layer for the PraisonAI multi-agent teams system. Prior to version 0.1.4, the workspace-scoped REST routes contain a systemic object-level authorization flaw that allows an authenticated user from one workspace to access, modify, and delete objects belonging to another workspace by supplying the victim object's global UUID. The affected pattern appears in workspace-scoped routes such as agents, projects, issues, and comments. The route layer verifies that the caller is a member of the workspace_id provided in the URL, but the service layer later resolves the target object by global object ID only. It does not verify that the resolved object actually belongs to the workspace in the URL. As a result, a valid member of workspace_attacker can call a route under /api/v1/workspaces/{workspace_attacker}/... while supplying an object UUID from workspace_victim. The server authorizes the request based on membership in workspace_attacker, then fetches or mutates the victim object by global UUID. This breaks the platform's workspace isolation boundary. PraisonAI Platform version 0.1.4 patches the issue.

Record
CVE-2026-47399
CVSS 3.1
8.8 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-284, CWE-639
Updated
2026-11-02
OSV 8.8

PraisonAI Platform workspace-scoped routes allow cross-workspace object access by global object ID

PraisonAI Platform is the platform layer for the PraisonAI multi-agent teams system. Prior to version 0.1.4, the workspace-scoped REST routes contain a systemic object-level authorization flaw that allows an authenticated user from one workspace to access, modify, and delete objects belonging to another workspace by supplying the victim object's global UUID. The affected pattern appears in workspace-scoped routes such as agents, projects, issues, and comments. The route layer verifies that the caller is a member of the workspace_id provided in the URL, but the service layer later resolves the target object by global object ID only. It does not verify that the resolved object actually belongs to the workspace in the URL. As a result, a valid member of workspace_attacker can call a route under /api/v1/workspaces/{workspace_attacker}/... while supplying an object UUID from workspace_victim. The server authorizes the request based on membership in workspace_attacker, then fetches or mutates the victim object by global UUID. This breaks the platform's workspace isolation boundary. PraisonAI Platform version 0.1.4 patches the issue.

Record
CVE-2026-47399
CVSS 3.1
8.8 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-284, CWE-639
Updated
2026-11-02
OSVGHSA-6h6v-6m7w-7vxx 8.8

PraisonAI Platform workspace-scoped routes allow cross-workspace object access by global object ID

Summary

PraisonAI Platform's workspace-scoped REST routes contain a systemic object-level authorization flaw that allows an authenticated user from one workspace to access, modify, and delete objects belonging to another workspace by supplying the victim object's global UUID.

The affected pattern appears in workspace-scoped routes such as agents, projects, issues, and comments. The route layer verifies that the caller is a member of the workspace_id provided in the URL, but the service layer later resolves the target object by global object ID only. It does not verify that the resolved object actually belongs to the workspace in the URL.

As a result, a valid member of workspace_attacker can call a route under:

/api/v1/workspaces/{workspace_attacker}/...

while supplying an object UUID from workspace_victim. The server authorizes the request based on membership in workspace_attacker, then fetches or mutates the victim object by global UUID.

This breaks the platform's workspace isolation boundary.

Details

The root cause is that workspace membership authorization and object ownership validation are not bound together.

The workspace dependency validates only that the caller is a member of the workspace named in the URL:

# praisonai_platform/api/deps.py
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)

This confirms that the caller has access to the URL workspace. However, it does not prove that the target object belongs to that workspace.

For example, the agent routes are scoped under a workspace path, but object access is performed using only the raw agent_id:

# praisonai_platform/api/routes/agents.py
@router.get("/{agent_id}", response_model=AgentResponse)
async def get_agent(workspace_id: str, agent_id: str, ...):
    agent = await svc.get(agent_id)
    return AgentResponse.model_validate(agent)

The service method resolves the agent by global UUID only:

# praisonai_platform/services/agent_service.py
async def get(self, agent_id: str) -> Optional[Agent]:
    return await self._session.get(Agent, agent_id)

The same pattern is used for update and delete operations:

# praisonai_platform/api/routes/agents.py
agent = await svc.update(agent_id, ...)

deleted = await svc.delete(agent_id)
# praisonai_platform/services/agent_service.py
agent = await self.get(agent_id)
...
await self._session.delete(agent)

There is no check equivalent to:

agent.workspace_id == workspace_id

Therefore, if an attacker is a valid member of any workspace, they can pass their own workspace ID in the URL while supplying an object ID from another workspace.

The same architectural pattern appears in other workspace-scoped object routes, including projects, issues, and comments:

# praisonai_platform/api/routes/projects.py
project = await svc.get(project_id)
project = await svc.update(project_id, ...)
deleted = await svc.delete(project_id)
# praisonai_platform/services/project_service.py
return await self._session.get(Project, project_id)
# praisonai_platform/api/routes/issues.py
issue = await svc.get(issue_id)
issue = await svc.update(issue_id, ...)
deleted = await svc.delete(issue_id)
comments = await svc.list_for_issue(issue_id)
# praisonai_platform/services/issue_service.py
return await self._session.get(Issue, issue_id)
# praisonai_platform/services/comment_service.py
select(Comment).where(Comment.issue_id == issue_id)

This indicates a systemic object-level access control issue: routes are workspace-scoped, but service-layer object lookups are not workspace-bound.

PoC

The following local…

Record
GHSA-6h6v-6m7w-7vxx
CVSS 3.1
8.8 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-284, CWE-639
Updated
2026-11-02
OSVPYSEC-2026-2930 8.8

PraisonAI Platform workspace-scoped routes allow cross-workspace object access by global object ID

Summary

PraisonAI Platform's workspace-scoped REST routes contain a systemic object-level authorization flaw that allows an authenticated user from one workspace to access, modify, and delete objects belonging to another workspace by supplying the victim object's global UUID.

The affected pattern appears in workspace-scoped routes such as agents, projects, issues, and comments. The route layer verifies that the caller is a member of the workspace_id provided in the URL, but the service layer later resolves the target object by global object ID only. It does not verify that the resolved object actually belongs to the workspace in the URL.

As a result, a valid member of workspace_attacker can call a route under:

/api/v1/workspaces/{workspace_attacker}/...

while supplying an object UUID from workspace_victim. The server authorizes the request based on membership in workspace_attacker, then fetches or mutates the victim object by global UUID.

This breaks the platform's workspace isolation boundary.

Details

The root cause is that workspace membership authorization and object ownership validation are not bound together.

The workspace dependency validates only that the caller is a member of the workspace named in the URL:

# praisonai_platform/api/deps.py
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)

This confirms that the caller has access to the URL workspace. However, it does not prove that the target object belongs to that workspace.

For example, the agent routes are scoped under a workspace path, but object access is performed using only the raw agent_id:

# praisonai_platform/api/routes/agents.py
@router.get("/{agent_id}", response_model=AgentResponse)
async def get_agent(workspace_id: str, agent_id: str, ...):
    agent = await svc.get(agent_id)
    return AgentResponse.model_validate(agent)

The service method resolves the agent by global UUID only:

# praisonai_platform/services/agent_service.py
async def get(self, agent_id: str) -> Optional[Agent]:
    return await self._session.get(Agent, agent_id)

The same pattern is used for update and delete operations:

# praisonai_platform/api/routes/agents.py
agent = await svc.update(agent_id, ...)

deleted = await svc.delete(agent_id)
# praisonai_platform/services/agent_service.py
agent = await self.get(agent_id)
...
await self._session.delete(agent)

There is no check equivalent to:

agent.workspace_id == workspace_id

Therefore, if an attacker is a valid member of any workspace, they can pass their own workspace ID in the URL while supplying an object ID from another workspace.

The same architectural pattern appears in other workspace-scoped object routes, including projects, issues, and comments:

# praisonai_platform/api/routes/projects.py
project = await svc.get(project_id)
project = await svc.update(project_id, ...)
deleted = await svc.delete(project_id)
# praisonai_platform/services/project_service.py
return await self._session.get(Project, project_id)
# praisonai_platform/api/routes/issues.py
issue = await svc.get(issue_id)
issue = await svc.update(issue_id, ...)
deleted = await svc.delete(issue_id)
comments = await svc.list_for_issue(issue_id)
# praisonai_platform/services/issue_service.py
return await self._session.get(Issue, issue_id)
# praisonai_platform/services/comment_service.py
select(Comment).where(Comment.issue_id == issue_id)

This indicates a systemic object-level access control issue: routes are workspace-scoped, but service-layer object lookups are not workspace-bound.

PoC

The following local…

Record
PYSEC-2026-2930
CVSS 3.1
8.8 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A: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-47399 is a high vulnerability (CVSS 8.8) 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.36%, the 30th 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