Skip to main content

Python CVE-2026-47416

| EUVDEUVD-2026-46334 CRITICAL
Improper Privilege Management (CWE-269)
2026-05-29 https://github.com/MervinPraison/PraisonAI GHSA-c2m8-4gcg-v22g PYSEC-2026-481
9.6
CVSS 3.1 · Vendor: https://github.com/MervinPraison/PraisonAI
View

Vulnerability Assessment

Weakness
CWE
OWASP Top 10:2025
A06:2025 - Insecure Design
ASVS 5.0
V8 - Authorization Least privilege enforcement
MITRE ATT&CK

1 technique across 1 tactic: Privilege Escalation

The technique list with ATT&CK links and the kill-chain view is part of the Basic plan and up.

Act Now Prioritize within 24-48h. Why: CRITICAL severity.
Patch available 0.0% exploitation probability (EPSS)

Get an e-mail when this CVE is exploited, patched or re-scored. Free account.

Alert me

AnalysisAIv1 – Jul 27, 2026

Vertical privilege escalation in praisonai-platform allows any workspace member to set their role to owner via a single PATCH request to the members endpoint, granting full administrative control over the workspace. Affected versions include all releases prior to 0.1.4. No active exploitation has been observed, and the EPSS score of 0.03% indicates low likelihood of widespread attacks; a vendor patch is available in version 0.1.4.

Affected VersionsENISA

praisonai-platform < 0.1.4

Affected Packages

pypi praisonai-platform fix: 0.1.4

Source: OSV (Open Source Vulnerabilities)

Affects your stack

Affects 1 package in pypi

Checking this CVE against your own stacks and servers is part of the Basic plan and up.

Know when Python gets its next vulnerability

  • Watch products and get an email when something new is published
  • Check this CVE against your own stack and servers
  • Exploit and PoC references, threat intelligence from 22 sources

No credit card · 7-day full trial

Severity by source

Vendor (https://github.com/MervinPraison/PraisonAI) PRIMARY 9.6 CRITICAL
AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N

Primary rating from Vendor (https://github.com/MervinPraison/PraisonAI) · only source for this CVE.

CVSS VectorVendor: https://github.com/MervinPraison/PraisonAI

Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Changed
Confidentiality
High
Integrity
High
Availability
None

DescriptionCVE.org

Summary

Type: Vertical privilege escalation. The PATCH /workspaces/{workspace_id}/members/{user_id} endpoint is gated by require_workspace_member(workspace_id), which defaults to min_role="member" and is never overridden by the route. The handler then calls MemberService.update_role(workspace_id, user_id, body.role) which sets the target member's role to whatever the request body specifies, with no check that the caller has owner-or-admin privilege, no check that the new role is not higher than the caller's own, and no check that the caller is not silently promoting themselves. File: src/praisonai-platform/praisonai_platform/api/routes/workspaces.py, lines 115-127; services/member_service.py, lines 55-69; api/deps.py, lines 54-73. Root cause: require_workspace_member exists with a min_role parameter (deps.py:58) but FastAPI's Depends(require_workspace_member) cannot pass arguments, so every route uses the default "member". The route then passes the URL-supplied user_id and the body-supplied role directly to MemberService.update_role, which contains zero permission checks: it loads the member by composite key and assigns member.role = new_role. A user with the lowest possible privilege ("member") thus sets their own role to "owner" with one HTTP PATCH, completing a member-to-owner privilege escalation in a single request.

Affected Code

File 1: src/praisonai-platform/praisonai_platform/api/routes/workspaces.py, lines 115-127.

python
@router.patch("/{workspace_id}/members/{user_id}", response_model=MemberResponse)
async def update_member_role(
    workspace_id: str,
    user_id: str,
    body: MemberUpdate,
    user: AuthIdentity = Depends(require_workspace_member),
# <-- BUG: defaults to min_role="member"; no role gate
    session: AsyncSession = Depends(get_db),
):
    member_svc = MemberService(session)
    member = await member_svc.update_role(workspace_id, user_id, body.role)
# <-- writes any role to any member
    if member is None:
        raise HTTPException(status_code=404, detail="Member not found")
    return MemberResponse.model_validate(member)

File 2: src/praisonai-platform/praisonai_platform/services/member_service.py, lines 55-69.

python
async def update_role(
    self,
    workspace_id: str,
    user_id: str,
    new_role: str,
) -> Optional[Member]:
    """Update a member's role."""
    if new_role not in VALID_ROLES:
# only validates the *value*, not the *caller's right*
        raise ValueError(f"Invalid role: {new_role}. Must be one of {VALID_ROLES}")
    member = await self.get(workspace_id, user_id)
    if member is None:
        return None
    member.role = new_role
# <-- BUG: no caller-role check, no target-vs-caller hierarchy check
    await self._session.flush()
    return member

File 3: src/praisonai-platform/praisonai_platform/api/deps.py, lines 54-73.

python
async def require_workspace_member(
    workspace_id: str,
    user: AuthIdentity = Depends(get_current_user),
    session: AsyncSession = Depends(get_db),
    min_role: str = "member",
# <-- default that no route overrides
) -> AuthIdentity:
    member_svc = MemberService(session)
    has = await member_svc.has_role(workspace_id, user.id, min_role)
    if not has:
        raise HTTPException(status_code=403, detail="Not a member of this workspace or insufficient role")
    user.workspace_id = workspace_id
    return user

Why it's wrong: require_workspace_member was clearly designed to be tunable per-route - the min_role parameter is right there - but Depends(require_workspace_member) in FastAPI cannot pass arguments to a dependency, so every route resolves to the default "member". The author's intent is also evident in MemberService.has_role (member_service.py:80-96), which implements an owner > admin > member hierarchy that this endpoint should be enforcing. The endpoint uses none of it. The VALID_ROLES = {"owner", "admin", "member"} enum check (member_service.py:62) only validates the *new role string is recognised*, not that the *caller has the right to assign it*. As a result, a member can write {"role": "owner"} to their own membership row and become owner in one PATCH.

Exploit Chain

  1. Attacker registers an account and joins (or is invited to) any workspace W as a "member" (the lowest privilege tier - typically anyone can be added by an owner during onboarding, or self-joins via an invite link). State: attacker has a JWT, is a Member(workspace_id=W, user_id=attacker, role="member").
  2. Attacker sends PATCH /workspaces/W/members/<attacker_user_id> with Authorization: Bearer <attacker_jwt> and body {"role": "owner"}. State: control flow enters update_member_role.
  3. require_workspace_member(W, attacker) runs. Its default min_role="member" is satisfied because the attacker is a member. The dependency returns the attacker's identity. State: route handler proceeds with no further role gate.
  4. MemberService.update_role(W, attacker, "owner") runs. VALID_ROLES accepts "owner". self.get(W, attacker) returns the attacker's existing member row. The next line, member.role = "owner", mutates the attacker's role in place. await self._session.flush() commits. State: attacker is now Member(workspace_id=W, user_id=attacker, role="owner").
  5. Attacker re-issues GET /auth/me (or any owner-gated endpoint) and is now treated as workspace owner. State: full administrative control of the workspace, including the ability to add/remove members, change settings, delete the workspace, and exfiltrate everything via the agent/issue/project/comment IDORs that were filed as separate advisories.
  6. Final state: starting from the lowest workspace privilege, the attacker holds owner of the workspace within one HTTP request. The same primitive also lets the attacker DEMOTE the legitimate owner by sending PATCH /workspaces/W/members/<owner_user_id> with {"role": "member"} - owner lockout in two requests total.

Security Impact

Severity: sec-critical. CVSS 9.1: network attack, low complexity, low privileges (the lowest tier on the platform), no user interaction, scope changed (the privilege boundary the attacker crosses is the workspace owner, a different security principal), high confidentiality and integrity (full workspace control), no availability claim (the attacker can also DELETE the workspace via the companion delete_workspace advisory, but that is a separate finding). Attacker capability: with one workspace-member token plus one PATCH request, the attacker becomes workspace owner. From there: add/remove any user as owner, change every workspace setting (including the settings JSON blob), demote the legitimate owner to "member", or chain into the companion delete_workspace advisory to wipe the workspace entirely. In multi-tenant SaaS deployments where any signup yields a member-level account in some default workspace, this is effectively pre-auth. Preconditions: praisonai-platform is deployed multi-tenant (more than one workspace exists OR the deployment grants member access on signup); the attacker has any membership token in the target workspace. Differential: source-inspection-verified end-to-end. The asymmetry between require_workspace_member's min_role parameter (which exists, defaults to "member", and is never overridden) and MemberService.has_role's clearly tiered owner > admin > member hierarchy (which exists but is never invoked with anything but the default) is the smoking gun. With the suggested fix below, the route resolves with min_role="owner", the attacker's member-level token fails the gate at the dependency, and the privilege escalation never reaches the service layer.

Suggested Fix

The fix has two parts. First, the route must resolve require_workspace_member with min_role="owner" (or at least "admin"). Second, MemberService.update_role should refuse to set a target's role higher than the caller's own role, so that an admin cannot accidentally produce another owner.

diff
--- a/src/praisonai-platform/praisonai_platform/api/routes/workspaces.py
+++ b/src/praisonai-platform/praisonai_platform/api/routes/workspaces.py
@@ -115,11 +115,16 @@
+def _require_owner(workspace_id: str, user, session):
+    return require_workspace_member(workspace_id, user, session, min_role="owner")
+
 @router.patch("/{workspace_id}/members/{user_id}", response_model=MemberResponse)
 async def update_member_role(
     workspace_id: str,
     user_id: str,
     body: MemberUpdate,
-    user: AuthIdentity = Depends(require_workspace_member),
+    user: AuthIdentity = Depends(_require_owner),
     session: AsyncSession = Depends(get_db),
 ):
     member_svc = MemberService(session)
+    if not await member_svc.has_role(workspace_id, user.id, "owner"):
+        raise HTTPException(status_code=403, detail="Only owners can change member roles")
     member = await member_svc.update_role(workspace_id, user_id, body.role)

Defence-in-depth in the service layer:

diff
--- a/src/praisonai-platform/praisonai_platform/services/member_service.py
+++ b/src/praisonai-platform/praisonai_platform/services/member_service.py
@@ -55,7 +55,7 @@
-    async def update_role(self, workspace_id: str, user_id: str, new_role: str) -> Optional[Member]:
+    async def update_role(self, workspace_id: str, caller_id: str, user_id: str, new_role: str) -> Optional[Member]:
         """Update a member's role."""
+        if not await self.has_role(workspace_id, caller_id, "owner"):
+            raise PermissionError("Only owners can update member roles")
         if new_role not in VALID_ROLES:
             raise ValueError(...)

The companion endpoints add_member, remove_member, delete_workspace, and update_workspace exhibit the same Depends(require_workspace_member) default-min-role pattern and are filed as their own advisories so each gets a separate CVE.

Executive ViewAI

Why It Matters

Praisonai-platform prior to version 0.1.4 contains a critical privilege escalation vulnerability allowing any workspace member to become owner, gaining full administrative control. This could lead to unauthorized data access, system manipulation, and business disruption. Leadership should prioritize patching to protect workspace integrity and user trust.

Recommended Action

Within 24 hours, identify all instances running praisonai-platform versions below 0.1.4 and begin emergency patching. Within 7 days, apply the vendor-released patch (version 0.1.4) to all affected systems after testing. Within 30 days, verify patch deployment, review access logs for signs of exploitation, and enforce least-privilege practices to mitigate future risks.

Business Impact: Severe
Compensating Controls

Apply vendor patch.

Threat Intelligence Overview

EPSS Score
0.0%
Top 90% exploitable
Threat Intel
1
1 source
Data Quality
5 sources
Confidence: Medium

How this decision was reached

The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.

SignalValue
Severity CRITICAL
CISA KEV No
Public POC No
EPSS 0.0%
Patch available Yes
Active threat No
Deciding rule
CRITICAL severity
What every action level means
Emergency Immediate action required. Criteria: CRITICAL + in CISA KEV (actively exploited) without patch, OR CRITICAL + EPSS > 30% without patch, OR CRITICAL + active threat signals without patch.
Act Now Prioritize within 24-48h. Criteria: in KEV with patch available, OR CRITICAL + public POC, OR HIGH + EPSS > 10%, OR CRITICAL + active threat, OR any CRITICAL severity.
This Week Schedule remediation this week. Criteria: HIGH severity (CVSS 7.0-8.9). Patch within normal change window.
This Month Plan within 30 days. Criteria: MEDIUM severity (CVSS 4.0-6.9), lower exploitation probability. Include in regular patch cycle.
Monitor Track and reassess. Criteria: LOW severity (CVSS 0.1-3.9), minimal exploitation risk. No immediate action needed.

SSVC AssessmentENISA

SSVC Decision· derived
Scheduled
Exploitation· derived
None
System Exposure· derived
Open
Automatable· derived
No
Human Impact
Very High

Priority Score

48
Low Medium High Critical
KEV: 0
EPSS: 0
CVSS: +48
PoC: 0
Weaponized: 0
Threat intel: 0
Gov advisory: 0

Attack Technique

Privilege escalation occurs when an attacker leverages flaws in access control mechanisms to gain permissions beyond what they were originally granted.

More in Python

View all
CVE-2025-24016 CRITICAL POC
9.9 Feb 10

Wazuh SIEM platform versions 4.4.0 through 4.9.0 contain an unsafe deserialization vulnerability in the DistributedAPI t

CVE-2025-27520 CRITICAL POC
9.8 Apr 04

BentoML version 1.4.2 and earlier contains an unauthenticated remote code execution vulnerability through insecure deser

CVE-2025-2945 CRITICAL POC
9.9 Apr 03

pgAdmin 4 contains critical remote code execution vulnerabilities in the Query Tool download and Cloud Deployment endpoi

CVE-2013-5093 MEDIUM POC
6.8 Sep 27

The renderLocalView function in render/views.py in graphite-web in Graphite 0.9.5 through 0.9.10 uses the pickle Python

CVE-2025-32375 CRITICAL POC
9.8 Apr 09

BentoML is a Python library for building online serving systems optimized for AI apps and model inference. Rated critica

CVE-2014-0224 HIGH POC
7.4 Jun 05

OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0.1h does not properly restrict processing of ChangeCiph

CVE-2024-21644 HIGH POC
7.5 Jan 08

pyLoad download manager version prior to 0.5.0b3.dev77 exposes the Flask SECRET_KEY through an unauthenticated endpoint.

CVE-2026-33017 CRITICAL POC
9.3 Mar 17

Langflow (a visual LLM pipeline builder) contains a critical unauthenticated code execution vulnerability (CVE-2026-3301

CVE-2017-9462 HIGH POC
8.8 Jun 06

In Mercurial before 4.1.3, "hg serve --stdio" allows remote authenticated users to launch the Python debugger, and conse

CVE-2026-49869 CRITICAL POC
10.0 Jun 26

Unauthenticated remote code execution affects Kestra OSS (the open-source event-driven orchestration platform) prior to

CVE-2026-39987 CRITICAL POC
9.3 Apr 08

Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/

CVE-2024-21645 MEDIUM POC
5.3 Jan 08

pyLoad is the free and open-source Download Manager written in pure Python. Rated medium severity (CVSS 5.3), this vulne

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy