The praisonai-platform AI agent orchestration framework (≤ 0.1.2) exposes five label management API endpoints that accept attacker-supplied label_id and issue_id values without verifying workspace ownership, allowing any authenticated tenant to rename, delete, or reassign labels across all workspaces in a multi-tenant deployment. Exploitation requires only a valid membership token—obtainable by any free registrant—and knowledge of foreign IDs discoverable through sequential enumeration or normal API responses, placing this squarely in low-complexity, low-privilege territory with no user interaction needed. The integrity impact is acute for AI agent platforms where labels govern task routing and triage: a malicious tenant can silently corrupt a competitor's AI workflow taxonomy, mislabel security-sensitive agent tasks, or strip labels from critical issues—all without triggering victim-side notification. This is not an isolated flaw; 59 other CVEs exist in the same package and the advisory explicitly names four companion IDORs (AgentService, IssueService, ProjectService, CommentService), signaling a systemic authorization defect. Upgrade to praisonai-platform 0.1.4 immediately and audit all companion service classes before returning multi-tenant access.
What is the risk?
High risk for any multi-tenant praisonai-platform deployment. CVSS 7.6 with network attack vector, low complexity, and low privileges reflects a genuinely low barrier to exploitation—no AI/ML expertise required, only HTTP access and a free account. The 59 other CVEs in this package and four explicitly documented companion IDORs in the same advisory signal a systemic authorization defect pattern rather than an isolated bug, substantially elevating confidence that additional unexplored attack surfaces remain. Single-tenant self-hosted deployments face significantly reduced risk; shared SaaS or enterprise multi-workspace instances running ≤ 0.1.2 are directly exposed with no mitigating control in the default configuration.
Attack Kill Chain
What systems are affected?
| Package | Ecosystem | Vulnerable Range | Patched |
|---|---|---|---|
| praisonai-platform | pip | <= 0.1.2 | 0.1.4 |
Do you use praisonai-platform? You're affected.
Severity & Risk
Attack Surface
What should I do?
5 steps-
Patch immediately: upgrade praisonai-platform to 0.1.4, which adds workspace_id predicates to every single-row label lookup and association write.
-
If patching is blocked, restrict label API endpoints at the API gateway or WAF layer—validate that label_id and issue_id exist within the authenticated workspace before forwarding requests to the service layer.
-
Audit the four explicitly named companion services in the same codebase: AgentService, IssueService, ProjectService, and CommentService share the identical authorization gap per the advisory.
-
Review audit logs for cross-workspace anomalies: PATCH or DELETE requests on label endpoints where label_id is absent from the authenticated workspace's own label inventory.
-
For multi-tenant operators: notify affected tenants and restore labels from backup if tampering is suspected, as renames and deletes are silent and permanent in the unpatched version.
Classification
Compliance Impact
This CVE is relevant to:
Frequently Asked Questions
What is CVE-2026-47414?
The praisonai-platform AI agent orchestration framework (≤ 0.1.2) exposes five label management API endpoints that accept attacker-supplied label_id and issue_id values without verifying workspace ownership, allowing any authenticated tenant to rename, delete, or reassign labels across all workspaces in a multi-tenant deployment. Exploitation requires only a valid membership token—obtainable by any free registrant—and knowledge of foreign IDs discoverable through sequential enumeration or normal API responses, placing this squarely in low-complexity, low-privilege territory with no user interaction needed. The integrity impact is acute for AI agent platforms where labels govern task routing and triage: a malicious tenant can silently corrupt a competitor's AI workflow taxonomy, mislabel security-sensitive agent tasks, or strip labels from critical issues—all without triggering victim-side notification. This is not an isolated flaw; 59 other CVEs exist in the same package and the advisory explicitly names four companion IDORs (AgentService, IssueService, ProjectService, CommentService), signaling a systemic authorization defect. Upgrade to praisonai-platform 0.1.4 immediately and audit all companion service classes before returning multi-tenant access.
Is CVE-2026-47414 actively exploited?
No confirmed active exploitation of CVE-2026-47414 has been reported, but organizations should still patch proactively.
How to fix CVE-2026-47414?
1. Patch immediately: upgrade praisonai-platform to 0.1.4, which adds workspace_id predicates to every single-row label lookup and association write. 2. If patching is blocked, restrict label API endpoints at the API gateway or WAF layer—validate that label_id and issue_id exist within the authenticated workspace before forwarding requests to the service layer. 3. Audit the four explicitly named companion services in the same codebase: AgentService, IssueService, ProjectService, and CommentService share the identical authorization gap per the advisory. 4. Review audit logs for cross-workspace anomalies: PATCH or DELETE requests on label endpoints where label_id is absent from the authenticated workspace's own label inventory. 5. For multi-tenant operators: notify affected tenants and restore labels from backup if tampering is suspected, as renames and deletes are silent and permanent in the unpatched version.
What systems are affected by CVE-2026-47414?
This vulnerability affects the following AI/ML architecture patterns: agent frameworks, multi-tenant AI platforms, AI task orchestration, collaborative AI workflow systems.
What is the CVSS score for CVE-2026-47414?
CVE-2026-47414 has a CVSS v3.1 base score of 7.6 (HIGH).
AI Security Impact
Affected AI Architectures
MITRE ATLAS Techniques
AML.T0006 Active Scanning AML.T0012 Valid Accounts AML.T0021 Establish Accounts AML.T0049 Exploit Public-Facing Application Compliance Controls Affected
Technical Details
Original Advisory
## 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. ```python 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. ```python @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 codebase uses a composite key correctly; the label service does not. The `add_to_issue` and `remove_from_issue` paths are particularly nasty because they touch *two* unverified IDs at once: an attacker can attach a foreign workspace's label to a foreign workspace's issue (or detach the legitimate labels), corrupting both sides of an association the attacker has no business touching. ## Exploit Chain 1. Attacker registers a workspace `W_attacker` (member) and harvests a foreign-workspace `label_id` `L_T` and a foreign-workspace `issue_id` `I_T`. Both leak via `list_labels` responses (which include label IDs — but only for `W_attacker`; for the target the IDs come from issue records that include label associations, activity feeds, exported dumps, error messages). State: attacker holds `L_T` and `I_T`. 2. Attacker authenticates and sends `PATCH /workspaces/W_attacker/labels/L_T` with `{"name": "<deleted>", "color": "#000000"}`. `require_workspace_member(W_attacker, attacker)` passes. `LabelService.update(L_T, ...)` loads the foreign label and renames it. State: every issue across the foreign workspace that bears this label now displays the attacker-chosen name and colour. 3. Attacker sends `DELETE /workspaces/W_attacker/labels/L_T`. `LabelService.delete(L_T)` deletes the foreign label, dropping every issue-label association row that referenced it (cascade or orphan, depending on schema). State: foreign workspace's labels are gone or corrupted. 4. Attacker sends `POST /workspaces/W_attacker/issues/I_T/labels/L_T2` to attach foreign label `L_T2` to foreign issue `I_T`. `LabelService.add_to_issue(I_T, L_T2)` writes the association row regardless of either ID's workspace. State: the foreign issue now carries an arbitrary attacker-chosen label, which surfaces in every filter/search/board view in the foreign workspace's UI. 5. Attacker sends `DELETE /workspaces/W_attacker/issues/I_T/labels/L_legit` to strip the legitimate label off the foreign issue. State: triagers can no longer find the issue via label filters. 6. Attacker sends `GET /workspaces/W_attacker/issues/I_T/labels` to read the current label set on any foreign issue. State: the attacker fingerprints the foreign workspace's triage taxonomy. 7. Final state: with one workspace-member token plus harvested foreign IDs, the attacker rewrites and deletes other workspaces' labels, attaches/detaches arbitrary labels on other workspaces' issues, and reads triage state across the deployment. ## Security Impact **Severity:** sec-moderate. CVSS 6.3: network attack, low complexity, low privileges, no user interaction, scope unchanged. The integrity damage is high (rename/delete of foreign labels is permanent and silent; cross-workspace label-attachment corrupts UI filters), confidentiality is low (label names are not the most sensitive field but do leak triage taxonomy), availability low (foreign workspaces may lose triage visibility into their own issues until the labels are restored). **Attacker capability:** rename and delete any label in the multi-tenant deployment; attach any label to any issue; detach any label from any issue; list label assignments for any issue. Combined with the companion `IssueService` IDOR (separate advisory), the attacker can also modify the underlying issue, making the cross-workspace tampering very difficult to detect. **Preconditions:** `praisonai-platform` is deployed multi-tenant; the attacker has any membership token; target IDs are known or guessable. **Differential:** source-inspection-verified end-to-end. The asymmetry between `LabelService.list_for_workspace(workspace_id)` (correctly workspace-scoped) and `LabelService.get(label_id) / add_to_issue(issue_id, label_id)` (no workspace check) confirms the gap. With the suggested fix below, label and issue IDs that do not belong to the membership-checked workspace return 404, and the attacker cannot touch them. ## Suggested Fix Make every single-row label lookup take the workspace predicate; verify both `issue_id` and `label_id` belong to `workspace_id` for the association routes. ```diff --- a/src/praisonai-platform/praisonai_platform/services/label_service.py +++ b/src/praisonai-platform/praisonai_platform/services/label_service.py @@ -33,7 +33,12 @@ class LabelService: return label - async def get(self, label_id: str) -> Optional[IssueLabel]: - return await self._session.get(IssueLabel, label_id) + async def get(self, workspace_id: str, label_id: str) -> Optional[IssueLabel]: + stmt = select(IssueLabel).where( + IssueLabel.id == label_id, + IssueLabel.workspace_id == workspace_id, + ) + return (await self._session.execute(stmt)).scalar_one_or_none() - async def add_to_issue(self, issue_id: str, label_id: str) -> None: + async def add_to_issue(self, workspace_id: str, issue_id: str, label_id: str) -> None: + # Verify both ids belong to workspace_id before writing the association row. ``` Then update the route handlers in `routes/labels.py` to thread `workspace_id` through every call. The same single-key-lookup pattern is filed separately for `AgentService`, `IssueService`, `ProjectService`, and `CommentService` — each is its own exploitable IDOR.
Exploitation Scenario
A threat actor registers a free workspace on a shared praisonai-platform SaaS instance to obtain a valid membership token. Through normal API calls against their own workspace they harvest label_id values (included in list responses), then discover foreign issue_id values via sequential integer or UUID enumeration, API error message leakage, or shared activity feeds. Using their own workspace_id as the URL namespace—which passes the membership check—the attacker sends PATCH /workspaces/W_attacker/labels/{foreign_label_id} to rename a victim organization's AI agent task label (e.g., 'security-escalation') to a benign name, then sends DELETE to permanently remove it, cascade-deleting all associated issue-label rows in the victim workspace. Simultaneously, they invoke GET /workspaces/W_attacker/issues/{foreign_issue_id}/labels to enumerate the victim's full workflow taxonomy, gaining intelligence on how the target classifies and prioritizes AI agent operations—all from a single unprivileged membership token with no victim-side indication of compromise.
Weaknesses (CWE)
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:L References
Timeline
Related Vulnerabilities
CVE-2026-47392 9.9 praisonaiagents: RCE via Python sandbox bypass
Same package: praisonai GHSA-vc46-vw85-3wvm 9.8 PraisonAI: RCE via malicious workflow YAML execution
Same package: praisonai CVE-2026-39890 9.8 PraisonAI: YAML deserialization enables unauthenticated RCE
Same package: praisonai GHSA-9qhq-v63v-fv3j 9.8 PraisonAI: RCE via MCP command injection
Same package: praisonai CVE-2026-47410 9.8 praisonai-platform: hardcoded JWT → full account takeover
Same package: praisonai