Listen to this Post
The vulnerability exists in Paperclip’s authenticated mode where three API endpoints (POST /api/agents/:id/keys, GET /api/agents/:id/keys, DELETE /api/agents/:id/keys/:keyId) only call `assertBoard(req)` but never call assertCompanyAccess(req, companyId). This allows any authenticated board user – even a freshly signed-up account with zero company memberships and no admin role – to generate a plaintext `pcp_` agent API token for any agent belonging to any other company on the same instance. The token creation function (createApiKey) binds the token to the victim agent’s `companyId` server-side. Later, when the attacker uses this token as a Bearer credential, the `actorMiddleware` resolves it to an actor with `type: “agent”` and the victim’s companyId, causing every downstream `assertCompanyAccess` check to pass. Consequently, the attacker gains full read/write access to the victim tenant’s issues, approvals, agent configurations, and can even pause, terminate, or delete any agent via sibling handlers (/agents/:id/pause, /resume, /terminate, DELETE /agents/:id) that share the same assertBoard-only flaw. The root cause is the absence of agent fetching and company membership verification in the `/keys` handlers (lines 2050-2087 in server/src/routes/agents.ts), contrasting with the correct pattern shown in /agents/:id/wakeup. The 2026.410.0 patch (GHSA-68qg-g8mg-6pr7) fixed an import bypass but did not cover these routes. Trigger conditions are default: PAPERCLIP_DEPLOYMENT_MODE=authenticated, open sign-up, and at least one agent in another company. The attacker only needs the victim agent ID, which leaks through activity feeds and sidebar endpoints. The PoC successfully returns a token and then uses it to retrieve victim company data.
dailycve form:
Platform: Paperclip authenticated mode
Version: 2026.411.0-canary.8
Vulnerability : Cross-tenant token minting
Severity: Critical
date: 2026-04-16
Prediction: 2026-04-30
What Undercode Say:
Enumerate victim agent IDs (example from sidebar)
curl -s -H "Cookie: $MALLORY_SESSION" http://target:3102/api/agents?limit=100
Mint token for victim agent
VICTIM_AGENT="agt_abc123"
curl -s -X POST http://target:3102/api/agents/$VICTIM_AGENT/keys \
-H "Cookie: $MALLORY_SESSION" -H "Content-Type: application/json" \
-d '{"name":"poc"}' | jq -r '.token'
Use stolen token to read victim company data
STOLEN="pcp_8be3a5198e9ccba0ac7b3341395b2d3145fe2caa1b800e25"
VICTIM_CO="comp_xyz"
curl -s -H "Authorization: Bearer $STOLEN" \
http://target:3102/api/companies/$VICTIM_CO/issues
Exploit:
Attacker signs up via /api/auth/sign-up/email, obtains session cookie, then POSTs to `/api/agents/[victim-agent-id]/keys` without any company membership. The server returns a plaintext API token. Using that token as Bearer, the attacker can call any endpoint gated by `assertCompanyAccess` (e.g., GET /api/companies/[victim-id]/issues, POST /api/agents/[victim-id]/pause). The token remains valid until manually revoked.
Protection from this CVE
Apply the suggested fix: modify `server/src/routes/agents.ts` to fetch the agent and call `assertCompanyAccess(req, agent.companyId)` in each `/keys` handler. Also audit all assertBoard-only handlers (/pause, /resume, /terminate, DELETE /agents/:id) and add company access checks. As a workaround, disable open sign-up (PAPERCLIP_AUTH_DISABLE_SIGN_UP=true) or run in non-authenticated mode if multi-tenancy is not required. Upgrade once a patched version (>=2026.411.1) is released.
Impact
Confidentiality: HIGH – attacker reads any tenant’s issues, approvals, agent configs (including adapter URLs, model settings). Integrity: HIGH – attacker creates persistent agent tokens that authorize mutations (issue updates, self-wakeup with malicious payloads). Availability: HIGH – attacker can pause, terminate, or delete any agent in any company. The bug is reachable by any signed-up user with default settings, and the stolen token persists across sessions.
🎯Let’s Practice Exploiting & Learn Patching For Free:
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

