Every CVE Search/ Get API key

CVE-2026-47414

praisonai-platform: Label endpoints accept any label_id and any issue_id without workspace ownership check, cross-workspace label edit/delete and issue-label-link IDOR

7.6 HighFix available

PraisonAI Platform is the platform layer for the PraisonAI multi-agent teams system. Versions prior to 0.1.4 have an Insecure Direct Object Reference. Five label endpoints — PATCH /workspaces/{workspace_id}/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 — gate access on require_workspace_member(workspace_id) only and pass URL-supplied label_id and issue_id straight through to LabelService without verifying either belongs to the workspace. 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
Low
Integrity
High
Availability
Low

Exploit likelihood

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

What each source reports

CVE List Score used 7.6

praisonai-platform: Label endpoints accept any label_id and any issue_id without workspace ownership check, cross-workspace label edit/delete and issue-label-link IDOR

PraisonAI Platform is the platform layer for the PraisonAI multi-agent teams system. Versions prior to 0.1.4 have an Insecure Direct Object Reference. Five label endpoints — PATCH /workspaces/{workspace_id}/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 — gate access on require_workspace_member(workspace_id) only and pass URL-supplied label_id and issue_id straight through to LabelService without verifying either belongs to the workspace. PraisonAI Platform version 0.1.4 patches the issue.

Record
CVE-2026-47414
CVSS 3.1
7.6 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:L
Weakness
CWE-639
Updated
2026-11-02
EUVDEUVD-2026-46332 7.6

PraisonAI Platform is the platform layer for the PraisonAI multi-agent teams system. Versions prior to 0.1.4 have an Insecure Direct Object Reference. Five label endpoints — PATCH /workspaces/{workspace_id}/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 — gate access on require_workspace_member(workspace_id) only and pass URL-supplied label_id and issue_id straight through to LabelService without verifying either belongs to the workspace. PraisonAI Platform version 0.1.4 patches the issue.

Record
EUVD-2026-46332
CVSS 3.1
7.6 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:L
Updated
2026-11-02
GitHub AdvisoriesGHSA-5jx9-w35f-vp65 7.6

praisonai-platform: Label endpoints' unchecked label_id/issue_id enable cross-workspace label IDOR (edit, delete, link)

Summary

Type: Insecure Direct Object Reference. Five label endpoints — PATCH /workspaces/{workspace_id}/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 — gate access on require_workspace_member(workspace_id) only and pass URL-supplied label_id and issue_id straight through to LabelService without verifying either belongs to the workspace. File: src/praisonai-platform/praisonai_platform/services/label_service.py, lines 35-100; route handlers at src/praisonai-platform/praisonai_platform/api/routes/labels.py, lines 42-106. Root cause: identical pattern to the agent / issue / project / comment IDORs in this codebase: the route's workspace_id is used as a membership predicate but never threaded through to the service layer. LabelService.get(label_id) runs session.get(IssueLabel, label_id) with no workspace filter; update/delete inherit the gap; add_to_issue(issue_id, label_id) and remove_from_issue(issue_id, label_id) write/delete association rows without verifying either ID belongs to the membership-checked workspace; list_for_issue(issue_id) reads them.

Affected Code

File 1: src/praisonai-platform/praisonai_platform/services/label_service.py, lines 35-100.

class LabelService:
    ...

    async def get(self, label_id: str) -> Optional[IssueLabel]:
        return await self._session.get(IssueLabel, label_id)         # <-- BUG: no workspace_id predicate

    async def update(
        self,
        label_id: str,
        ...
    ) -> Optional[IssueLabel]:
        label = await self.get(label_id)                             # <-- inherits the gap
        ...

    async def delete(self, label_id: str) -> bool:
        label = await self.get(label_id)                             # <-- inherits the gap
        ...

    async def add_to_issue(self, issue_id: str, label_id: str) -> None:
        # writes a row in issue_label association table; no workspace check on either id

    async def remove_from_issue(self, issue_id: str, label_id: str) -> None:
        # deletes from association table; no workspace check on either id

    async def list_for_issue(self, issue_id: str) -> list[IssueLabel]:
        # reads from association table; no workspace check on issue_id

File 2: src/praisonai-platform/praisonai_platform/api/routes/labels.py, lines 42-106.

@router.patch("/labels/{label_id}", response_model=LabelResponse)
async def update_label(workspace_id: str, label_id: str, body: LabelUpdate, ...):
    svc = LabelService(session)
    label = await svc.update(label_id, body.name, body.color)        # <-- writes any label in the DB
    ...

@router.delete("/labels/{label_id}", ...)
async def delete_label(workspace_id: str, label_id: str, ...):
    deleted = await svc.delete(label_id)                             # <-- deletes any label in the DB
    ...

@router.post("/issues/{issue_id}/labels/{label_id}", ...)
async def add_label_to_issue(workspace_id: str, issue_id: str, label_id: str, ...):
    await svc.add_to_issue(issue_id, label_id)                       # <-- attaches any label to any issue cross-workspace

@router.delete("/issues/{issue_id}/labels/{label_id}", ...)
async def remove_label_from_issue(workspace_id: str, issue_id: str, label_id: str, ...):
    await svc.remove_from_issue(issue_id, label_id)                  # <-- detaches any label from any issue cross-workspace

@router.get("/issues/{issue_id}/labels", ...)
async def list_issue_labels(workspace_id: str, issue_id: str, ...):
    labels = await svc.list_for_issue(issue_id)                      # <-- reads label assignments for any issue

Why it's wrong: the workspace_id URL segment is treated as a UI hint; the actual label_id and issue_id lookups query the database without a workspace constraint. The MemberService in this same…

Record
GHSA-5jx9-w35f-vp65
CVSS 3.1
7.6 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:L
Weakness
CWE-639
Updated
2026-11-02
NVD 7.6

PraisonAI Platform is the platform layer for the PraisonAI multi-agent teams system. Versions prior to 0.1.4 have an Insecure Direct Object Reference. Five label endpoints — PATCH /workspaces/{workspace_id}/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 — gate access on require_workspace_member(workspace_id) only and pass URL-supplied label_id and issue_id straight through to LabelService without verifying either belongs to the workspace. PraisonAI Platform version 0.1.4 patches the issue.

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

praisonai-platform: Label endpoints accept any label_id and any issue_id without workspace ownership check, cross-workspace label edit/delete and issue-label-link IDOR

PraisonAI Platform is the platform layer for the PraisonAI multi-agent teams system. Versions prior to 0.1.4 have an Insecure Direct Object Reference. Five label endpoints — PATCH /workspaces/{workspace_id}/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 — gate access on require_workspace_member(workspace_id) only and pass URL-supplied label_id and issue_id straight through to LabelService without verifying either belongs to the workspace. PraisonAI Platform version 0.1.4 patches the issue.

Record
CVE-2026-47414
CVSS 3.1
7.6 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:L
Weakness
CWE-639
Updated
2026-11-02
OSVGHSA-5jx9-w35f-vp65 7.6

praisonai-platform: Label endpoints' unchecked label_id/issue_id enable cross-workspace label IDOR (edit, delete, link)

Summary

Type: Insecure Direct Object Reference. Five label endpoints — PATCH /workspaces/{workspace_id}/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 — gate access on require_workspace_member(workspace_id) only and pass URL-supplied label_id and issue_id straight through to LabelService without verifying either belongs to the workspace. File: src/praisonai-platform/praisonai_platform/services/label_service.py, lines 35-100; route handlers at src/praisonai-platform/praisonai_platform/api/routes/labels.py, lines 42-106. Root cause: identical pattern to the agent / issue / project / comment IDORs in this codebase: the route's workspace_id is used as a membership predicate but never threaded through to the service layer. LabelService.get(label_id) runs session.get(IssueLabel, label_id) with no workspace filter; update/delete inherit the gap; add_to_issue(issue_id, label_id) and remove_from_issue(issue_id, label_id) write/delete association rows without verifying either ID belongs to the membership-checked workspace; list_for_issue(issue_id) reads them.

Affected Code

File 1: src/praisonai-platform/praisonai_platform/services/label_service.py, lines 35-100.

class LabelService:
    ...

    async def get(self, label_id: str) -> Optional[IssueLabel]:
        return await self._session.get(IssueLabel, label_id)         # <-- BUG: no workspace_id predicate

    async def update(
        self,
        label_id: str,
        ...
    ) -> Optional[IssueLabel]:
        label = await self.get(label_id)                             # <-- inherits the gap
        ...

    async def delete(self, label_id: str) -> bool:
        label = await self.get(label_id)                             # <-- inherits the gap
        ...

    async def add_to_issue(self, issue_id: str, label_id: str) -> None:
        # writes a row in issue_label association table; no workspace check on either id

    async def remove_from_issue(self, issue_id: str, label_id: str) -> None:
        # deletes from association table; no workspace check on either id

    async def list_for_issue(self, issue_id: str) -> list[IssueLabel]:
        # reads from association table; no workspace check on issue_id

File 2: src/praisonai-platform/praisonai_platform/api/routes/labels.py, lines 42-106.

@router.patch("/labels/{label_id}", response_model=LabelResponse)
async def update_label(workspace_id: str, label_id: str, body: LabelUpdate, ...):
    svc = LabelService(session)
    label = await svc.update(label_id, body.name, body.color)        # <-- writes any label in the DB
    ...

@router.delete("/labels/{label_id}", ...)
async def delete_label(workspace_id: str, label_id: str, ...):
    deleted = await svc.delete(label_id)                             # <-- deletes any label in the DB
    ...

@router.post("/issues/{issue_id}/labels/{label_id}", ...)
async def add_label_to_issue(workspace_id: str, issue_id: str, label_id: str, ...):
    await svc.add_to_issue(issue_id, label_id)                       # <-- attaches any label to any issue cross-workspace

@router.delete("/issues/{issue_id}/labels/{label_id}", ...)
async def remove_label_from_issue(workspace_id: str, issue_id: str, label_id: str, ...):
    await svc.remove_from_issue(issue_id, label_id)                  # <-- detaches any label from any issue cross-workspace

@router.get("/issues/{issue_id}/labels", ...)
async def list_issue_labels(workspace_id: str, issue_id: str, ...):
    labels = await svc.list_for_issue(issue_id)                      # <-- reads label assignments for any issue

Why it's wrong: the workspace_id URL segment is treated as a UI hint; the actual label_id and issue_id lookups query the database without a workspace constraint. The MemberService in this same…

Record
GHSA-5jx9-w35f-vp65
CVSS 3.1
7.6 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:L
Weakness
CWE-639
Updated
2026-11-02
OSVPYSEC-2026-2929 7.6

praisonai-platform: Label endpoints' unchecked label_id/issue_id enable cross-workspace label IDOR (edit, delete, link)

Summary

Type: Insecure Direct Object Reference. Five label endpoints — PATCH /workspaces/{workspace_id}/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 — gate access on require_workspace_member(workspace_id) only and pass URL-supplied label_id and issue_id straight through to LabelService without verifying either belongs to the workspace. File: src/praisonai-platform/praisonai_platform/services/label_service.py, lines 35-100; route handlers at src/praisonai-platform/praisonai_platform/api/routes/labels.py, lines 42-106. Root cause: identical pattern to the agent / issue / project / comment IDORs in this codebase: the route's workspace_id is used as a membership predicate but never threaded through to the service layer. LabelService.get(label_id) runs session.get(IssueLabel, label_id) with no workspace filter; update/delete inherit the gap; add_to_issue(issue_id, label_id) and remove_from_issue(issue_id, label_id) write/delete association rows without verifying either ID belongs to the membership-checked workspace; list_for_issue(issue_id) reads them.

Affected Code

File 1: src/praisonai-platform/praisonai_platform/services/label_service.py, lines 35-100.

class LabelService:
    ...

    async def get(self, label_id: str) -> Optional[IssueLabel]:
        return await self._session.get(IssueLabel, label_id)         # <-- BUG: no workspace_id predicate

    async def update(
        self,
        label_id: str,
        ...
    ) -> Optional[IssueLabel]:
        label = await self.get(label_id)                             # <-- inherits the gap
        ...

    async def delete(self, label_id: str) -> bool:
        label = await self.get(label_id)                             # <-- inherits the gap
        ...

    async def add_to_issue(self, issue_id: str, label_id: str) -> None:
        # writes a row in issue_label association table; no workspace check on either id

    async def remove_from_issue(self, issue_id: str, label_id: str) -> None:
        # deletes from association table; no workspace check on either id

    async def list_for_issue(self, issue_id: str) -> list[IssueLabel]:
        # reads from association table; no workspace check on issue_id

File 2: src/praisonai-platform/praisonai_platform/api/routes/labels.py, lines 42-106.

@router.patch("/labels/{label_id}", response_model=LabelResponse)
async def update_label(workspace_id: str, label_id: str, body: LabelUpdate, ...):
    svc = LabelService(session)
    label = await svc.update(label_id, body.name, body.color)        # <-- writes any label in the DB
    ...

@router.delete("/labels/{label_id}", ...)
async def delete_label(workspace_id: str, label_id: str, ...):
    deleted = await svc.delete(label_id)                             # <-- deletes any label in the DB
    ...

@router.post("/issues/{issue_id}/labels/{label_id}", ...)
async def add_label_to_issue(workspace_id: str, issue_id: str, label_id: str, ...):
    await svc.add_to_issue(issue_id, label_id)                       # <-- attaches any label to any issue cross-workspace

@router.delete("/issues/{issue_id}/labels/{label_id}", ...)
async def remove_label_from_issue(workspace_id: str, issue_id: str, label_id: str, ...):
    await svc.remove_from_issue(issue_id, label_id)                  # <-- detaches any label from any issue cross-workspace

@router.get("/issues/{issue_id}/labels", ...)
async def list_issue_labels(workspace_id: str, issue_id: str, ...):
    labels = await svc.list_for_issue(issue_id)                      # <-- reads label assignments for any issue

Why it's wrong: the workspace_id URL segment is treated as a UI hint; the actual label_id and issue_id lookups query the database without a workspace constraint. The MemberService in this same…

Record
PYSEC-2026-2929
CVSS 3.1
7.6 HighCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:L
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-47414 is a high vulnerability (CVSS 7.6) 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.38%, the 32nd 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