The Agent You Import Is the Payload

The Agent You Import Is the Payload

The most dangerous agent vulnerability this week did not involve a model. No prompt injection, no jailbreak, no tool-call confusion, no verifier that got outsmarted. An unauthenticated attacker makes six HTTP requests to a Paperclip instance and gets a shell as the server’s OS user. The payload is not an exploit binary — it is a YAML file that describes an “agent.”

CVE-2026-41679 carries a CVSS 3.1 base score of 10.0CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H — for Paperclip, the open-source Node.js server and React UI for orchestrating teams of AI agents as a virtual company. The GitHub advisory (GHSA-68qg-g8mg-6pr7), published April 10, 2026 and credited to Sagi Layani of Oasis Security, describes it without ceremony: “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.” Oasis published the full research writeup and technical report on August 5, 2026, which is what put this in the news cycle this week.

The interesting part is not the score. It is where the chain lives: an agent platform whose configuration format is a code-execution boundary, defended by authorization checks that were opt-in per route.

The six-call chain

Paperclip models an organization as companies of agents. Companies can be imported from portable bundles — YAML files that define agents and the adapters they run on. The process adapter takes a command and args and calls spawn() directly, with zero sandboxing. Importing an agent, in other words, is semantically equivalent to loading a program. The platform just never enforced that equivalence. From the advisory, the chain is:

  1. Sign up. Open registration is the default — PAPERCLIP_AUTH_DISABLE_SIGN_UP defaults to false in server/src/config.ts:169-173 — and email verification is hardcoded off in server/src/auth/better-auth.ts:89-93. The environment variable isn’t documented in the deployment guide, so operators don’t know the switch exists.
  2. Sign in and capture the session cookie.
  3. Create a CLI auth challenge — unauthenticated, no actor check at server/src/routes/access.ts:1638-1659 — which returns a pre-generated boardApiToken.
  4. Self-approve it. The approval handler at access.ts:1687-1704 checks that the caller is a board user, but never checks that the approver is the person who created the challenge. One signup yields a persistent, board-level API key.
  5. Import a malicious company. The direct company-creation endpoint correctly requires instance admin (companies.ts:260-264). The import endpoint does not: for new_company mode it only calls assertBoardassertInstanceAdmin isn’t even imported in that file. The bundle’s .paperclip.yaml configures a process adapter agent whose command is bash -c "id > /tmp/pwned.txt && ...", passed through to spawn() unvalidated by the import service.
  6. Wake the agent. POST /api/agents/<id>/wakeup checks assertCompanyAccess, which passes — the attacker owns the company they just created. Paperclip spawns the command as the server user.

The NVD record confirms the arithmetic: “The chain consists of six API calls”. CISA’s SSVC assessment flags it automatable: yes, technicalImpact: total, with a public proof of concept; there is no indication of in-the-wild exploitation in the record.

Three failures, one pattern

The RCE chains four independent flaws, and Oasis’s writeup documents two more findings in the same disclosure — GHSA-xfqj-r5qw-8g4j (CVSS 8.3) and GHSA-x8hx-rhr2-9rf7 (CVSS 9.6). Together they are a taxonomy of implicit trust assumptions:

  • “A self-issued credential is safe enough.” The CLI challenge self-approval turns an unauthenticated signup into board-level access. The assumption that the approver and creator are different people was never encoded. (CWE-287, CWE-862)
  • “Every sensitive route will enforce its own checks.” Authorization was opt-in at the route level: unauthenticated requests get an actor of type none and pass through to next(), so one missed assertion means an open endpoint. The 8.3 advisory catalogs the misses: GET /api/heartbeat-runs/:runId/issues (the only endpoint in activity.ts without assertCompanyAccess), unauthenticated CLI challenge creation, and — the gift that keeps on giving — GET /api/skills/paperclip, which returns the full agent heartbeat procedure: every API endpoint and its parameters, the env-var names and header formats agents authenticate with, and the complete coordination protocol. Unauthenticated recon that doubles as a map to the internal API. (CWE-306)
  • “Loopback means the local user.” In the default local_trusted development mode, every request is auto-authenticated as instance admin (server/src/middleware/auth.ts:24-27), and the Host-header guard that could stop rebinding is only active in authenticated + private modes. The 9.6 advisory shows the consequence: a domain with two A records — attacker server and 127.0.0.1 — plus an attacker-controlled webpage, and a developer who merely visits the page gets arbitrary command execution on their machine via DNS rebinding. No clicks, no credentials. The advisory notes the guard is conceptually a one-line fix: validate Host against localhost/127.0.0.1/[::1] in local_trusted mode too.

The fourth flaw is the substrate all three assumptions run on: the process adapter spawns commands with no sandbox, and import service passes adapterConfig through unvalidated. Every one of these boundaries was crossable because the platform’s security model treated configuration as data instead of code.

The boundary was never the model

Here is the uncomfortable part for anyone who assumed agent security would be decided by model behavior: the model was irrelevant to this attack. Paperclip’s agents are driven by LLMs, but the RCE path — import a bundle, wake an agent, run a command — never touches an inference call. The process adapter executes what the YAML says, because that is its job. The failure is not a prompt getting through; it is an authorization model that let an unauthenticated stranger author executable configuration.

The same trust-domain failure shows up from the other side in AWS’s own Strands advisory (CVE-2026-18394, Bulletin 2026-069-AWS, published July 31). Strands Agents is AWS’s open-source SDK for building AI agents, and its http_request tool exposed a proxies parameter in the input schema controllable by the LLM. Operators could bind a credential to an allowlist of approved hostnames via HTTP_REQUEST_TOKEN_CONFIG — but a crafted prompt, delivered through untrusted web content the agent reads (indirect prompt injection), could set proxies to an attacker-controlled endpoint. The allowlist check passes on the request URL, the credential is attached, and the request is routed through the attacker’s proxy on the first hop, disclosing the credential in cleartext in the Authorization header. AWS’s workaround is telling: don’t bind credentials while the tool is available to an agent that processes untrusted content.

Paperclip and Strands are the same bug in two costumes. In Paperclip, the untrusted actor controls the command because agent config is executable and import was under-authorized. In Strands, the untrusted actor controls the route because the proxy parameter lived inside the model’s own tool schema. Both are cases of a security control and the thing it guards against occupying the same trust domain: an allowlist the model can influence is not an allowlist, and an import endpoint the unauthenticated can reach is a shell.

What operators should change

Paperclip patched in the 2026.416.0 release (the GitHub advisory lists the affected npm versions as < 2026.410.0), and Oasis’s recommendations extend beyond upgrading:

  1. Treat agent configuration as code. An import is a deploy, an adapter is an exec, a wakeup is a run. Apply review, testing, and approval to bundles the way you would to a Dockerfile — because that is what they are.
  2. Disable open registration by default. The fix for the RCE’s root cause is the same list Oasis gives: flip PAPERCLIP_AUTH_DISABLE_SIGN_UP to default-on, require email verification, and reject CLI-challenge self-approval.
  3. Default-deny the API surface. The advisory’s own suggestion is the durable fix: reject actor type none at the middleware level for all routes except an explicit public allowlist (health, sign-in, webhooks), instead of trusting each handler to assert.
  4. Host-validate loopback modes. Enable the hostname guard for local_trusted so DNS rebinding dies with it.
  5. Don’t put controls where the agent can reach them. Credential allowlists and routing knobs belong out-of-band — environment and infrastructure configuration, not tool input schemas — as the Strands fix (HTTP_PROXY/HTTPS_PROXY, LLM control removed) demonstrates.

The deeper lesson is about where the “AI” actually sits in the attack surface. The agent platforms being stood up this year are web applications whose most dangerous endpoints happen to spawn processes described by YAML. When the identity model around those endpoints fails, the results look like every web-app CVE of the last decade — except the payload format is now an agent definition, and the box being rooted runs your agent infrastructure. The verifier in this loop was authorization, and authorization was optional.

Patch, rotate, and audit every imported company bundle on the instance. Then look at your own import pipeline — the one that ingests “agent configs” from anyone — and ask whether it has an assertInstanceAdmin on the semantically identical path. The next 10.0 is one missing check away.

Sources

Keep reading