CVE-2026-47418 - PraisonAI Platform project IDOR

PraisonAI Platform versions before 0.1.4 contain a project-level cross-workspace authorization flaw. Project routes check that the caller is a member of the workspace_id in the URL, but service methods can then look up, update, delete, or return statistics for project_id by global primary key. If a member of workspace A learns a project UUID from workspace B, the route can authorize workspace A while the service acts on workspace B’s project.

This recipe targets the project-specific fix, not just the generic dependency bump. Multi-tenant agent platforms often store roadmaps, agent work queues, issue aggregates, and customer-sensitive operational context inside projects, so the PR needs workspace-scoped service queries and negative tenant-boundary tests for reads, writes, deletes, and stats.

Affected versions

  • Vulnerable package: praisonai-platform <0.1.4
  • Fixed package: praisonai-platform 0.1.4+
  • Affected coordinate: praisonai-platform on PyPI
  • Affected surface: GET, PATCH, DELETE, and stats routes for /workspaces/{workspace_id}/projects/{project_id} and local forks or wrappers with the same route/service split
  • Affected code pattern: route code validates membership for URL workspace_id, then calls project service methods such as get(project_id), update(project_id, ...), delete(project_id), or get_stats(project_id) without also filtering by workspace_id.

Indicator-of-exposure

  • The repository depends on, vendors, forks, wraps, or deploys praisonai-platform <0.1.4.
  • The deployment supports multiple workspaces, projects, issues, agents, or tenants.
  • Project service methods use session.get(Project, project_id) or another primary-key-only lookup for workspace-owned project records.
  • Route handlers receive both workspace_id and project_id, check require_workspace_member, and then discard workspace_id before calling the service.
  • Tests use only one workspace or only happy-path owner/member fixtures, so they cannot catch a cross-workspace project ID swap.

Quick checks:

rg -n "praisonai-platform|praisonai_platform|ProjectService|project_id|get_stats|require_workspace_member|session\\.get\\(Project|workspace_id.*project_id|/projects" .
python -m pip show praisonai-platform
python -m pip freeze | rg -i '^praisonai-platform=='

Windows:

rg -n "praisonai-platform|praisonai_platform|ProjectService|project_id|get_stats|require_workspace_member|session\\.get\\(Project|workspace_id.*project_id|/projects" .
python -m pip show praisonai-platform
python -m pip freeze | rg -i '^praisonai-platform=='

Do not validate by swapping production workspace or project IDs. Use local fixtures with synthetic tenants and non-sensitive project records.

Remediation strategy

  • Upgrade every controlled praisonai-platform dependency, constraints file, lockfile, image, deployment artifact, SBOM, and generated dependency report to 0.1.4+.
  • Require project service methods to receive workspace_id and filter by both Project.id and Project.workspace_id.
  • Enforce caller role for mutating project operations in the service layer as well as the route layer. Reads, writes, deletes, and stats should all bind the project to the authorized workspace.
  • Normalize forbidden/not-found behavior so denied cross-workspace requests do not reveal whether the foreign project exists.
  • Add local regression tests for cross-workspace project read, update, delete, stats, and any issue/project aggregate path that exposes project metadata.
  • Add audit events for denied cross-workspace project access without logging bearer tokens, cookies, prompts, project content, tenant data, or secrets.

When to use it

Use this recipe when a repository deploys, vendors, forks, wraps, or packages PraisonAI Platform project APIs for multi-workspace or customer environments. It is most important when routes accept both workspace_id and project_id, then project services read, update, delete, or return stats by global project ID.

Use it to upgrade the package and bind every project operation to the authorized workspace at the service layer. Do not use it to swap production workspace or project IDs while validating exposure.

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, project services, API clients, and project aggregate helpers.
  • Project-owned data paths: project get/update/delete/stats, project issue aggregates, metadata, status, title, description, lead, icon, labels, comments, agents, and any joins through project records.
  • Authorization evidence: URL workspace_id, project_id, route dependencies, service query predicates, caller identity, caller role, mutation policy, not-found/forbidden behavior, and audit logging.
  • Synthetic tenant-boundary fixtures for two or more workspaces with distinct owners, members, projects, issues, labels, comments, and aggregate stats.
  • Operator evidence for UUID-swapping review: unexpected project reads, edits, deletes, stats access, issue aggregate access, and suspicious denied cross-workspace attempts.

The prompt

You are remediating CVE-2026-47418 / GHSA-943m-6wx2-rc2j, a PraisonAI
Platform project IDOR where workspace membership is checked for one workspace
but project service methods act on a globally looked-up project from another
workspace. Produce exactly one output:

- A reviewer-ready PR/change request that upgrades affected package usage,
  scopes project service queries by workspace, adds negative tenant-boundary
  tests for project read/write/delete/stats paths, 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-47418 / GHSA-943m-6wx2-rc2j and directly related project
  tenant-boundary checks.
- Treat bearer tokens, cookies, user IDs, workspace IDs, project IDs, issue
  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 project tables, or broaden into unrelated PraisonAI
  advisories except where shared project service helpers 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, wrappers, and local API routes.
2. Determine every resolved `praisonai-platform` version. A target is
   vulnerable if it resolves to a version earlier than `0.1.4`.
3. Search owned code for project route/service splits:
   `ProjectService`, `project_id`, `workspace_id`, `require_workspace_member`,
   `session.get(Project`, `get_stats`, `update_project`, `delete_project`,
   `list_for_workspace`, and routes under
   `/workspaces/{workspace_id}/projects`.
4. For each route that receives both `workspace_id` and `project_id`, prove the
   service query also filters by the 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 project-isolation 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 project scoping:
   - service `get`, `update`, `delete`, and stats methods receive
     `workspace_id`;
   - queries filter by both `Project.id` and `Project.workspace_id`;
   - mutating methods receive caller identity and enforce caller role;
   - not-found and forbidden responses do not reveal whether another
     workspace's project exists;
   - issue and aggregate helpers that join through project data preserve the
     same workspace predicate.
8. Add safe local regression tests with synthetic tenants:
   - workspace A member cannot read workspace B project by UUID;
   - workspace A member cannot update workspace B project title, description,
     status, lead, icon, or metadata;
   - workspace A member cannot delete workspace B project;
   - workspace A member cannot retrieve workspace B project stats or aggregate
     issue counts;
   - owner success paths still work for projects inside the caller's
     workspace;
   - denied responses and audit logs omit tokens, prompts, tenant content, and
     secret values.
9. Add or verify audit events for denied cross-workspace project attempts.
   Include actor, authorized workspace, requested project ID, decision, and
   request ID, but no credentials or project content.
10. Add a PR body section named `CVE-2026-47418 operator actions` that states:
    - PraisonAI Platform versions before and after;
    - every project route and service method reviewed;
    - before/after query predicates for `get`, `update`, `delete`, and stats;
    - whether low-privilege members could read, modify, delete, or infer
      foreign project data before the patch;
    - which logs operators should review for UUID swapping, unexpected project
      edits, project deletion, and suspicious stats access;
    - which validation commands passed.
11. 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.
12. Use PR title:
    `fix(sec): remediate CVE-2026-47418 in PraisonAI projects`.

## 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 project access; document
  the product/security-owner decision required 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-platform below 0.1.4.
  • Project service methods filter by workspace_id and do not rely on global primary-key lookup for tenant authorization.
  • Route-layer and service-layer authorization agree on caller identity, workspace membership, and minimum role for project mutations.
  • Negative tests prove cross-workspace project ID swaps fail for reads, updates, deletes, stats, and related issue aggregates.
  • Operator notes include log review for project UUID swapping, unexpected edits, project deletions, and suspicious stats access.

Watch for

  • Updating the package while Docker images, constraints, generated reports, or SBOMs still resolve a vulnerable version.
  • Fixing project list routes while leaving get, update, delete, or stats methods as global primary-key lookups.
  • Route code that checks workspace_id but then discards it before calling project services.
  • Service methods that trust callers to have already authorized the operation.
  • Tests with only one workspace fixture.
  • Error responses that disclose whether a guessed foreign project exists.

Output contract

Return one of:

  • A reviewer-ready PR/change request that upgrades every controlled praisonai-platform runtime to 0.1.4+, scopes project service queries by workspace_id, enforces caller role for mutations, normalizes denied responses, adds tenant-boundary tests for read/update/delete/stats paths, refreshes artifacts, and documents operator review actions.
  • TRIAGE.md when no affected runtime, package pin, fork, wrapper, image, deployment, project route, service layer, or dependency is controlled by the repository.

The output must list versions before/after, every project route and service reviewed, before/after query predicates, mutation role gates, denied-response behavior, tests added, audit events, validation commands, and logs to review for project UUID swapping. It must not probe production tenants, dump project tables, disclose tokens/prompts, or weaken tenant isolation.

References