Security Digest · Critical advisory (no CVE assigned)

GHSA-3xx2-mqjm-hg9x: Paperclip: Cross-tenant agent API key IDOR in `/agents/:id/keys` routes allows full victim-company compromise

Summary The GET, POST, and DELETE handlers under /agents/:id/keys in the Paperclip control-plane API only call assertBoard(req), which verifies that the caller has a board-type session but does not verify that the caller has access to the company owning the target agent.

CVSS 9.9 Critical GitHub-reviewed · critical

Should you act?

  • Only if you depend on one of the packages below, directly or transitively, in a vulnerable version. Check your lockfile with npm audit (or: npm ls <package>).
  • No CVE has been assigned, so it will not appear in CVE-based scanners that ignore GitHub advisories. npm audit, pip-audit and Dependabot do read GitHub advisories.

Affected packages

EcosystemPackageVulnerableFirst fixed
npm@paperclipai/server< 2026.416.02026.416.0

Details

Summary

The GET, POST, and DELETE handlers under /agents/:id/keys in the Paperclip control-plane API only call assertBoard(req), which verifies that the caller has a board-type session but does not verify that the caller has access to the company owning the target agent. A board user whose membership is limited to Company A can therefore list, create, or revoke agent API keys for any agent in Company B by supplying the victim agent's UUID in the URL path. The POST handler returns the newly-minted token in cleartext, which authenticates subsequent requests as {type:"agent", companyId: }, giving the attacker full agent-level access inside the victim tenant — a complete cross-tenant compromise.

Details

The three vulnerable routes are defined in server/src/routes/agents.ts:2050-2087:

assertBoard in server/src/routes/authz.ts:4-8 is intentionally narrow:

It does not consult req.actor.companyIds or req.actor.isInstanceAdmin. Company-scoping is handled by a separate helper, assertCompanyAccess(req, companyId) (same file, lines 18-31), which the key-management routes never call.

The service layer is also unauthenticated. In server/src/services/agents.ts:580-629:

Neither the agent id on POST/GET nor the key id on DELETE is cross-checked against the caller's company membership.

CVSS: 9.9 (v3.1) CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H

Sources and references

  1. GitHub Advisory GHSA-3xx2-mqjm-hg9x github.com
  2. github.com github.com

Critical npm advisories · Today’s Security Digest