criticalCVSS 10Vulnerability

GHSA-3xx2-mqjm-hg9x

## 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:<CompanyB>}`, 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`: ```ts router.get("/agents/:id/keys", async (req, res) => { assertBoard(req); // <-- only checks actor.type === "board" const id = req.params.id as string; const keys = await svc.listKeys(id); res.json(keys); }); router.post("/agents/:id/keys", validate(createAgentKeySchema), async (req, res) => { assertBoard(req); // <-- same const id = req.params.id as string; const key = await svc.createApiKey(id, req.body.name); // ... activity log ... res.status(201).json(key); // returns cleartext `token` }); router.delete("/agents/:id/keys/:keyId", async (req, res) => { assertBoard(req); // <-- same const keyId = req.params.keyId as string; const revoked = await svc.revokeKey(keyId); if (!revoked) { res.status(404).json({ error: "Key not found" }); return; } res.json({ ok: true }); }); ``` `assertBoard` in `server/src/routes/authz.ts:4-8` is intentionally narrow: ```ts export function assertBoard(req: Request) { if (req.actor.type !== "board") { throw forbidden("Board access required"); } } ``` It does **not** consult `req.actor.companyIds` or `req.

Properties

ghsa_id
GHSA-3xx2-mqjm-hg9x
severity
critical
summary
Paperclip: Cross-tenant agent API key IDOR in `/agents/:id/keys` routes allows full victim-company compromise
cvss_score
10
cve_id
GHSA-3xx2-mqjm-hg9x
cvss_vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H
is_ghsa_only
true
ghsa_published
2026-04-16T22:49:46Z
source_url
https://github.com/advisories/GHSA-3xx2-mqjm-hg9x
ghsa_updated
2026-04-16T22:49:48Z

Related Entities (4)

VULNERABLE_TO (1)

[Software]npm/@paperclipai/server

AFFECTS (1)

[Software]npm/@paperclipai/server

HAS_WEAKNESS (1)

[Weakness]Authorization Bypass Through User-Controlled Key

REPORTED_BY (1)

[Source]GitHub Advisory Database

Explore deeper with Ninja Signal's threat intelligence graph

GHSA-3xx2-mqjm-hg9x (CVSS 10) — Ninja Signal Threat Intelligence | Ninja Signal