CVE-2026-48169 - PraisonAI Platform cross-workspace IDOR
PraisonAI Platform versions 0.1.2 and earlier contain a workspace-isolation
cluster. Route handlers verify that the caller belongs to the workspace_id
in the URL, but service methods for issues and projects can then perform
global primary-key lookups that ignore that workspace. If an attacker has any
valid workspace membership and learns an issue or project UUID from another
workspace, the route-layer check can pass for the attacker’s workspace while
the service method reads, updates, or deletes the victim object by global ID.
The same advisory also calls out member-management routes that use only a member-level gate for privileged changes. This recipe focuses on the combined tenant-boundary fix: package upgrade, workspace-scoped service queries, service-layer authorization, and negative tests that prove one workspace cannot act on another workspace’s resources.
Affected versions
- Vulnerable package:
praisonai-platform <=0.1.2 - Fixed package:
praisonai-platform 0.1.4+ - Affected coordinate:
praisonai-platformon PyPI - Affected surface: PraisonAI Platform APIs for workspaces, issues, projects, labels, comments, agents, members, and any local fork or wrapper that verifies workspace membership in routes but performs global lookups in services
- Affected code pattern: a route validates membership for URL
workspace_id, then calls a service method such asget(id),update(id), ordelete(id)that does not also filter byworkspace_idand caller role.
Indicator-of-exposure
- The repository depends on, vendors, forks, or deploys
praisonai-platform <=0.1.2. - A PraisonAI Platform API is deployed for multiple workspaces, teams, agents, projects, issues, labels, comments, or tenants.
- Service methods use global
session.get(Model, id)or primary-key-only lookups for workspace-owned records. - Route methods accept both
workspace_idand a resource ID, checkrequire_workspace_member, then call a service method without passingworkspace_idand caller identity. - Member, workspace, project, issue, label, or comment tests cover happy-path owner/member behavior but not cross-workspace UUID swaps and low-role denial.
Quick checks:
rg -n "praisonai-platform|praisonai_platform|require_workspace_member|session\\.get\\(|\\.get\\((issue_id|project_id|label_id|comment_id)|workspace_id.*(issue_id|project_id|label_id|comment_id|user_id)|IssueService|ProjectService|MemberService|list_for_workspace|update_member_role|delete_workspace" .
python -m pip show praisonai-platform
python -m pip freeze | rg -i '^praisonai-platform=='
Windows:
rg -n "praisonai-platform|praisonai_platform|require_workspace_member|session\\.get\\(|\\.get\\((issue_id|project_id|label_id|comment_id)|workspace_id.*(issue_id|project_id|label_id|comment_id|user_id)|IssueService|ProjectService|MemberService|list_for_workspace|update_member_role|delete_workspace" .
python -m pip show praisonai-platform
python -m pip freeze | rg -i '^praisonai-platform=='
Do not validate by swapping real production tenant IDs, dumping tenant data, or probing live membership APIs. Use local fixtures with synthetic workspaces.
Remediation strategy
- Upgrade every controlled
praisonai-platformdependency, lockfile, image, deployment, SBOM, and generated dependency report to0.1.4+. - Require every service method that accesses workspace-owned data to receive
workspace_idand enforce it in the query. Avoid global primary-key lookups for tenant-owned records unless a separate ownership check immediately follows. - Move authorization into the service layer as well as the route layer. The mutating service should receive the caller identity and role, not just the target resource ID.
- Add negative tests for cross-workspace reads, updates, deletes, stats, member changes, and label/comment/project/issue operations.
- Add audit events for denied cross-workspace attempts and privileged member operations without logging bearer tokens, prompts, tenant content, or secret values.
- Review logs for suspicious UUID swapping, member-role changes, owner removals, project/issue deletion, and workspace deletion if an affected deployment was reachable.
When to use it
Use this recipe when a repository deploys, vendors, forks, wraps, or packages PraisonAI Platform across multiple workspaces, teams, agents, projects, issues, labels, comments, members, or customers. It is most useful when several route families share the same route-membership plus global-service-lookup pattern.
Use it to upgrade the package and apply a tenant-boundary fix across the cluster instead of fixing only one endpoint. Do not use it to validate by probing live tenants, dumping tenant data, or reusing customer IDs.
Inputs
- Python manifests, lockfiles, constraints, Dockerfiles, Compose files, Helm charts, Kubernetes manifests, Procfiles, systemd units, CI jobs, deployment templates, docs, SBOMs, generated reports, forks, wrappers, route code, service code, and API clients.
- Workspace-owned resource inventory: issues, projects, labels, comments, agents, members, workspaces, stats endpoints, prompts, runtime config, and agent instructions.
- Authorization evidence: route dependencies,
workspace_idpropagation, service query predicates, caller identity, caller role, member-management policy, last-owner protection, audit logging, and error-response behavior. - Synthetic cross-tenant fixtures for workspace A and B, including owners, members, projects, issues, labels, comments, dependencies, agents, and member roles.
- Operator review evidence: UUID swapping, unexpected owner/member changes, issue or project deletion, workspace deletion, stats access, and suspicious denied cross-workspace attempts.
The prompt
You are remediating CVE-2026-48169 / GHSA-gv23-xrm3-8c62, the PraisonAI
Platform cross-workspace IDOR and privilege-escalation cluster. Produce exactly
one output:
- A reviewer-ready PR/change request that upgrades affected package usage,
scopes workspace-owned service queries, fixes member-management role gates,
adds tenant-boundary regression tests, refreshes generated artifacts, and
documents operator review actions, or
- TRIAGE.md if this repository does not control an affected PraisonAI Platform
runtime, fork, wrapper, image, deployment, or dependency.
## Rules
- Scope only CVE-2026-48169 / GHSA-gv23-xrm3-8c62 and directly related
workspace scoping, tenant isolation, and member-management authorization.
- Treat bearer tokens, cookies, user IDs, workspace IDs, issue/project/label
IDs, tenant data, prompts, agent configuration, model-provider keys, audit
logs, and database rows as sensitive.
- Do not send cross-tenant probes to production, use real customer accounts,
print tokens, dump tenant tables, or broaden into unrelated PraisonAI
advisories except where the same route/service authorization boundary must
be fixed.
- Do not weaken authentication, authorization, tenant isolation, CSRF
protection, audit logging, or tests to silence the finding.
- Do not auto-merge.
## Steps
1. Inventory every PraisonAI Platform reference controlled by this repository:
requirements, pyproject files, lockfiles, constraints, Dockerfiles,
Compose files, Helm charts, Kubernetes manifests, Procfiles, systemd units,
CI jobs, deployment templates, `.env.example`, docs, SBOMs, generated
dependency reports, forks, and local API wrappers.
2. Determine every resolved `praisonai-platform` version. A target is
vulnerable if it resolves to `0.1.2` or earlier.
3. Search owned code for route/service splits involving workspace-owned data:
`require_workspace_member`, `workspace_id`, `IssueService`, `ProjectService`,
`LabelService`, `CommentService`, `MemberService`, `session.get`, `get`,
`update`, `delete`, `get_stats`, `list_for_workspace`, and
`/workspaces/{workspace_id}` routes.
4. For each route that receives `workspace_id` plus another resource ID, prove
the service query also filters by that same `workspace_id` and enforces the
caller's role for mutations.
5. If this repository only calls an externally owned PraisonAI Platform
service, stop with `TRIAGE.md` listing checked files, the external owner,
the required fixed version, and the expected tenant-boundary contract.
6. Upgrade all controlled package pins to `praisonai-platform 0.1.4+`.
Regenerate lockfiles, constraints, image metadata, SBOMs, dependency
reports, and generated docs.
7. Where the repository owns a fork, wrapper, route, or compatibility shim,
fix workspace scoping:
- service `get`, `update`, `delete`, and stats methods receive
`workspace_id`;
- queries filter by both resource ID and `workspace_id`;
- mutating methods receive caller identity and enforce caller role;
- not-found and forbidden responses do not reveal whether another
workspace's object exists;
- service-layer checks are used even when route-layer dependencies exist.
8. Fix member-management authorization in the same touched route family:
- role changes require owner authority or the documented product policy;
- members cannot promote themselves, remove owners, or delete workspaces;
- last-owner protection is enforced;
- add, update, remove, workspace update, and workspace delete routes use
explicit owner/admin dependencies instead of a default member gate.
9. Add safe local regression tests with synthetic tenants:
- workspace A member cannot read, update, delete, or get stats for
workspace B issue/project IDs;
- guessed label/comment/resource IDs cannot cross workspace boundaries;
- member cannot promote self, remove owner, or delete workspace;
- owner success paths still work;
- denied responses and audit logs omit tokens, prompts, tenant content, and
secret values.
10. Add audit logging or verify existing events for denied cross-workspace
attempts and privileged member actions. Include actor, workspace, target
resource type, target ID, decision, and request ID, but no credentials or
sensitive content.
11. Add a PR body section named `CVE-2026-48169 operator actions` that states:
- PraisonAI Platform versions before and after;
- every workspace-owned route and service reviewed;
- before/after query scoping for issues, projects, labels, comments, and
member operations;
- whether low-privilege members could read, modify, delete, promote, or
remove data before the patch;
- which logs operators should review for UUID swapping, unexpected
owner/member changes, issue/project deletion, or workspace deletion;
- which validation commands passed.
12. Run relevant validation: dependency install, lockfile checks,
tenant-boundary unit tests, API route tests, migration checks,
lint/typecheck, deployment-template rendering, container build, SBOM
refresh, dependency/security scans, and local non-secret smoke checks
available in this repository.
13. Use PR title:
`fix(sec): remediate CVE-2026-48169 in PraisonAI workspace isolation`
## Stop conditions
- No affected PraisonAI Platform runtime, package pin, fork, wrapper, image, or
deployment is controlled by this repository.
- A fixed `praisonai-platform` version cannot be consumed without a broader
platform migration.
- The repository intentionally allows cross-workspace resource access or
member-level ownership changes; document the required product/security-owner
decision in `TRIAGE.md`.
- Verification would require production cross-tenant probes, live customer
accounts, tenant-data queries, or credential disclosure.
- Validation fails for unrelated pre-existing reasons; document those failures
instead of broadening scope.
Verification - what the reviewer looks for
- No controlled lockfile, image, SBOM, or deployment resolves
praisonai-platformto0.1.2or earlier. - Workspace-owned service methods filter by
workspace_idand do not rely on global primary-key lookups for tenant authorization. - Route-layer and service-layer authorization agree on caller identity, workspace membership, and minimum role for mutations.
- Negative tests prove cross-workspace UUID swaps fail for reads, writes, deletes, stats, labels/comments, and member-management operations.
- Operator notes include log review for UUID swapping, owner/member changes, and destructive workspace/project/issue actions.
Watch for
- Updating the package while Docker images, constraints, generated reports, or
SBOMs still resolve
0.1.2. - Fixing list endpoints but leaving
get,update,delete, or stats methods as global primary-key lookups. - Route code that checks
workspace_idbut then discards it before calling the service. - Service methods that trust callers to have already authorized the operation.
- Tests that use one workspace only and cannot catch cross-workspace UUID swapping.
- Returning different error bodies that reveal whether a guessed object exists in another workspace.
Output contract
Return one of:
- A reviewer-ready PR/change request that upgrades every controlled
praisonai-platformruntime to0.1.4+, scopes workspace-owned service queries, fixes member-management role gates, enforces service-layer authorization, adds broad tenant-boundary tests, refreshes artifacts, and documents operator review actions. TRIAGE.mdwhen no affected runtime, package pin, fork, wrapper, image, deployment, route family, service layer, or dependency is controlled by the repository.
The output must list versions before/after, every workspace-owned route and service reviewed, before/after query scoping for issues/projects/labels/ comments/members, role gates, audit events, validation commands, and logs to review for UUID swapping or owner/member changes. It must not probe production tenants, reveal object existence across workspaces, expose tokens/prompts, or weaken tenant isolation.
Related recipes
- CVE-2026-47410 - PraisonAI Platform default JWT secret
- an authentication flaw in the same package family.
- CVE-2026-47416 - PraisonAI Platform workspace owner promotion
- the focused member-role escalation recipe that complements this tenant-isolation cluster.
References
- GitHub Advisory: https://github.com/advisories/GHSA-gv23-xrm3-8c62
- Vendor advisory: https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-gv23-xrm3-8c62
- NVD CVE: https://nvd.nist.gov/vuln/detail/CVE-2026-48169
- GitLab Advisory Database: https://advisories.gitlab.com/pypi/praisonai-platform/CVE-2026-48169/
- PraisonAI project: https://github.com/MervinPraison/PraisonAI