Prompt Worms Part 2: I Practiced and Found 31 Vulnerabilities in the AI Agent Ecosystem

In the first part, we discussed the theory of Prompt Worms—self-replicating attacks via AI agents. OpenClaw was named the "perfect carrier." In this part, I put it into practice: downloaded the repository, delved into the code, probed the infrastructure, and found 31 vulnerabilities across 4 layers of the ecosystem. Zero sanitization on 867 lines of code, timeout instead of approval, backdoor "Easter egg" in the code, leaked password hashes in marketplace SaaS, and 14 blind spots in their own threat model. Three days, ~4,500 lines of tracing, 14 kill chains with PoC

Prompt Worms Part 2: I Tested in Practice — 31 Vulnerabilities in the AI-Agent Ecosystem

This is a continuation of the article “Prompt Worms: How Agents Became the New Virus Carriers”. In the first part, we discussed the theory: Lethal Trifecta, Persistent Memory, infection chains through Moltbook. OpenClaw was labeled the “perfect carrier.” In this part, I checked how “perfect” it truly is — delved into the source code, probed the infrastructure, found ecosystem SaaS in their marketplace, and discovered that their own threat model covers only 70% of the real attack surface.

Background: From Theory to Practice

In the first article, we presented a table — why OpenClaw is the perfect carrier for Prompt Worms:

Condition

Implementation in OpenClaw

Data Access

Full access to the file system, .env, SSH keys

Untrusted Content

Moltbook, email, Slack, Discord, web pages

External Comms

Email, API, shell commands, any tools

Persistent Memory

Built-in long-term context storage

Beautiful theory. But the question remains: how easy is it to exploit?

I downloaded the repository (~50 thousand lines of TypeScript), opened the code, and over three days followed a path I hadn’t planned:

Code → Website → Marketplace → Ecosystem SaaS → Their threat model

Each layer revealed the next. And each subsequent layer was worse than the previous one.

Layer 1: Source Code. Zero Sanitization on 867 Lines of Brain

The Only Filter

In the first article, I wrote: “extensions without moderation, malicious code executes.” Theory. Now — proof.

I traced the message path from the Telegram chat to the LLM. Four files:

dispatch.ts → envelope.ts → agent-runner-execution.ts → run.ts

At no stage — not one content check. And here is the only “sanitization” in 867 lines of brain core:

// run.ts:67-75 — EVERYTHING.
const ANTHROPIC_MAGIC_STRING_TRIGGER_REFUSAL = "...";

function scrubAnthropicRefusalMagic(prompt: string): string {
  return prompt.replaceAll(
    ANTHROPIC_MAGIC_STRING_TRIGGER_REFUSAL,
    ANTHROPIC_MAGIC_STRING_REPLACEMENT,
  );
}

One replacement of one string. For one provider. All other text goes to the LLM as is.

In the first article, we described Content Boundary Enforcement — separation of data and instructions through XML tags. OpenClaw does not do this. Data and instructions are mixed in one prompt. Prompt injection becomes not an attack, but a regular mode of operation.

SOUL_EVIL — a backdoor that doesn’t need to be injected

In the code, there is a file soul-evil.ts (line 281). It replaces the agent's "identity" based on a configurable trigger — replacing the system prompt with an alternative from the file SOUL_EVIL.md. It is designed as an "Easter egg." Implemented as a backdoor:

// soul-evil.ts — the replacement decision is logged on debug 
// (disabled in production)
log.debug(`[soul-evil] decision: ${reason}`);

Activation through configuration: soulEvil.chance: 1 — the agent is always in "evil" mode. The user does not see any difference — the same interface, the same chat.

Timeout = Approval

Remember from the first article: the agent can execute shell commands? Before that, it "asks for permission." But:

// exec-approval-manager.ts:51-61
const timer = setTimeout(() => {
  this.pending.delete(record.id);
  resolve(null);  // ⚠️ timeout = null = approval
}, timeoutMs);

If the user does not respond — the command is executed. Also: any WebSocket client can approve a request from any other client. There is no identity verification. We wrote a PoC script in 50 lines:

// Listening to exec.approval.requested → response: allow-always
// Result: One-Click RCE — all subsequent commands are auto-approved

config.patch — an omnipotent API

One endpoint allows changing any configuration field via JSON merge:

What we are patching

Effect

soulEvil.chance: 1

Activating SOUL_EVIL

gateway.auth.token: "attacker"

Replacing authentication

channels.*.allowFrom: ["*"]

Opening all channels

plugins.extraPaths: ["/tmp/evil"]

Loading malicious plugin

agents.defaults.memorySearch.extraPaths

Indexing arbitrary paths

No field-level ACL. No audit log.

Total vulnerabilities in code: 12

#

Vulnerability

Severity

1

Zero-sanitization pipeline (DM→LLM)

🔴 Critical

2

SOUL_EVIL backdoor engine

🔴 Critical

3

Timeout-as-approval (RCE)

🔴 Critical

4

Config injection → system takeover

🔴 Critical

5

Plugin system: jiti JIT arbitrary exec

🔴 Critical

6

Default-open command gating

🟠 High

7

Plaintext credential storage

🟠 High

8

Memory exfiltration + injection

🟠 High

9

System prompt injection surfaces

🟠 High

10

Hook system: silent agent mutation

🟠 High

11

Fast-lane privilege escalation

🟠 High

12

BOOT.md persistent backdoor

🟠 High

5 Critical, 7 High. All with PoC. Chains from DM to Full Compromise — from 3 to 5 hops.

Layer 2: Infrastructure. CORS * and open API marketplace

After the code — it makes sense to look at what lives in production. Three domains:

openclaw.ai — CORS wildcard

Access-Control-Allow-Origin: *    ← Any domain can make requests
Content-Security-Policy:           ← ABSENT
X-Frame-Options:                   ← ABSENT

This is static on Vercel. But CORS * + absence of X-Frame-Options = clickjacking.

docs.openclaw.ai — CSP with unsafe-eval

The documentation on Mintlify returns:

Content-Security-Policy: worker-src * blob: data: 'unsafe-eval' 'unsafe-inline'

unsafe-eval means: if an XSS point is found — eval(), Function(), setTimeout(string) work. CSP does not protect.

Also — files /llms.txt and /llms-full.txt are advertised: full dump of documentation (~1.3 MB), including credential storage paths, config examples, Gateway architecture. One GET request — and the attacker has a complete map of the system.

clawhub.ai — the find that changed everything

ClawHub — a skills marketplace for OpenClaw. The API works without authentication:

GET https://clawhub.ai/api/search?q=email

Returns a complete catalog of community skills with descriptions, ratings, versions. No auth, no rate limiting.

And here is what was returned in the output:

{
  "slug": "sendclaw",
  "displayName": "SendClaw - Bot creates own email address & sends without human permission"
}

“Bot creates email address and sends without human permission?”

Remember the Lethal Trifecta from the first article? External Comms — the third condition. If this skill actually works, we just found an autonomous email-sending mechanism within the OpenClaw ecosystem. This turns the theoretical Prompt Worm into a practical threat: an infected agent can not only poison the memory of neighboring agents but also send malicious emails to real people.

I went to check.

Layer 3: SendClaw. Mass mailing that doesn’t work

5 minutes — 3 accounts

SendClaw (5Ducks) — a live SaaS at sendclaw.com. Express.js backend on Replit. I registered three accounts in 5 minutes:

  • No email verification

  • No CAPTCHA

  • No rate limiting

  • Sequential User ID: 99 → 100 → 101 (≈100 users on the entire platform)

Password hash leak

The very first request GET /api/user returned:

{
  "id": 99,
  "username": "sentinel-test",
  "password": "533652d523a3c4daf...b30e80",
  "email": "[email protected]",
  "isAdmin": false
}

Password hash leaks during registration, login, and profile requests. All three accounts — confirmed.

The promised mailing

I tried to log in via Gmail OAuth:

GET /api/gmail/auth?userId=99
→ Error 400: redirect_uri_mismatch

Gmail OAuth is completely broken. Google rejects the Client ID due to an incorrect redirect URI.

The endpoint POST /api/send-gmail exists but is not working. The endpoints for daily outreach batch return HTTP 500 on any request.

Discrepancy: what is advertised vs what works

Promise (on ClawHub)

Reality

“Bot creates own email address”

Does not create — requires OAuth authorization of your Gmail

“Sends without human permission”

Does not send — OAuth is broken

“Email outreach automation”

The only working endpoint is AI chat for strategy

“Daily outreach batches”

/daily-outreach/batch/* → HTTP 500

This is the key point of the entire story.

In the first article, I described a scary scenario: an infected agent sends a prompt worm via email. SendClaw is advertised on ClawHub precisely as a tool for this — “sends without human permission.” If this skill worked, it would be a ready delivery mechanism for Prompt Worms.

But it does not work. A bug in the OAuth configuration has saved users from themselves.

A bug that saved from vulnerability

The OAuth state parameter contains raw userId without a signature:

/api/gmail/auth?userId=99 → state=99
/api/gmail/auth?userId=1  → state=1

If OAuth worked, this would be a direct OAuth CSRF: replace the state in the callback → link your Gmail to someone else's account → send emails in someone else's name. The chain:

Attacker → /api/gmail/auth?userId=VICTIM
→ Google OAuth (state=VICTIM)
→ Callback with authorization code
→ Gmail token linked to VICTIM
→ POST /api/send-gmail (on behalf of VICTIM)

Broken OAuth → the chain does not close. Bug ≠ protection. If someone fixes the redirect URI tomorrow — the CSRF chain will work immediately.

12 vulnerabilities in SendClaw

#

Findings

Severity

1

Password hash leakage

🔴 Critical

2

Unrestricted registration

🔴 Critical

3

Sequential predictable IDs

🔴 Critical

4

OAuth CSRF via raw userId

🔴 Critical

5

Broken Gmail OAuth (core non-functional)

🔴 Critical

6

Admin panel exposure

🟠 High

7

Batch endpoint DoS (500 crash)

🟠 High

8

Account lockout anomaly

🟠 High

9

Dual auth inconsistency

🟠 High

10

Multi-tenant exposure

🟡 Medium

11

Infrastructure fingerprinting

🟡 Medium

12

Partial mass assignment block

🟡 Medium

Layer 4: Threat Model. 37 threats and 14 blind spots

Already after all findings, I discovered that OpenClaw published an official threat model. 37 threats × 8 MITRE ATLAS tactics × 6 attack chains × 5 trust boundaries.

This is the first public threat model for an AI-agent platform. And it is honest — they acknowledge:

— “Pattern detection only, no blocking”
— “Skills execute with full agent privileges”
— “Tokens stored in plaintext, don't expire”
— “No rate limiting”

What is covered in their model

Their focus is on Skill Supply Chain (ClawHub) and Prompt Injection. These are the right priorities. They document 6 attack chains, including “Malicious Skill Full Kill Chain” and “Prompt Injection to RCE”.

What is NOT covered

Everything we found at the protocol level:

Our Findings

In their Threat Model?

exec.approval.resolve without client verification

operator.admin scope overload

Credentials in cleartext WebSocket frame

Nonce without HMAC — replay attack

SOUL_EVIL backdoor engine

config.patch without ACL

Timeout-as-approval

Loopback auth bypass

Memory flush autonomous writes

Plugin loader (jiti) arbitrary exec

SendClaw: broken OAuth + hash leak

ClawHub: unauthenticated API

CORS * on openclaw.ai

CSP unsafe-eval on docs

14 out of 14 of our critical findings are not reflected in the official model.

The model covers ~70% of the actual attack surface. The remaining 30% consists of protocol-level and infrastructure-level vulnerabilities that make the attacks described in the model trivially exploitable.

How This Relates to Prompt Worms

Let's return to the first article. We outlined 4 conditions for Prompt Worm:

Condition

Status after audit

✅ Data Access

Confirmed: memory-search.ts with extraPaths, access to the file system

✅ Untrusted Content

Confirmed: zero-sanitization pipeline, content from any channels

✅ External Comms

Confirmed: shell commands via timeout-approval, email via skills

✅ Persistent Memory

Confirmed: memory-flush.ts writes to disk without user review

All 4 conditions are not just "met" — they have no protections whatsoever. In the first article, we suggested protection through Content Boundary Enforcement and Memory Sanitization. OpenClaw has implemented neither of these.

Prompt Worm Kill Chain — complete chain

In the first article, we described a theoretical chain through Moltbook. Here's how it works with real code:

function scrubAnthropicRefusalMagic(prompt) { ... }

This is the only line of defense between the DM from Telegram and the shell command on your server. In SENTINEL we have 187 detection engines. Because a single regex is not a security layer. It’s a comment in the code.

Responsible Disclosure

  • OpenClaw: Contact [email protected]. Findings documented.

  • SendClaw (5Ducks): Public security contact absent (which in itself is a red flag for a SaaS handling email credentials).

Comments

    Also read