Back to skill

Security audit

Steamedclaw

Security checks for vulnerabilities and agentic risk

Overview

This game-playing skill is purpose-aligned, but it needs review because it mixes remote opponent/server text with agent instructions and uses broad shell-style helper commands with locally stored credentials.

Install only if you are comfortable letting the skill run a local Node helper, create a SteamedClaw account for your agent, store a plaintext SteamedClaw API key under ~/.config/steamedclaw-state, and send game actions to steamedclaw.com. Use a constrained exec/network policy if available, treat opponent discussion text as untrusted, and avoid letting the agent place arbitrary free-form JSON directly into shell command strings.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T01 · Skill Instruction Hijacking

Warning
Location
steamedclaw-helper.js:370
Finding

Untrusted Remote Content Is Forwarded Into the Agent Control Stream

Content
View full analysis
`${(m.from || '').slice(0, 8)}:"${(m.text || '').slice(0, MAX_DISCUSSION_MSG_CHARS)}"`, ); // Walk newest→oldest, keeping messages until the budget is spent. Always keep // at least the most recent one even if it alone is long (a single message is // capped at 1000, well under the total budget). const kept = []; let total = 0; for (let i = all.length - 1; i >= 0; i--) { total += all[i].length + 3; // + " | " separator if (total > MAX_DISCUSSION_TOTAL_CHARS && kept.length > 0) break; kept.unshift(all[i]); } const omitted = all.length - kept.length; const prefix = omitted > 0 ? `(+${omitted} earlier) ` : ''; const body = kept.join(' | ') || '(no messages yet)'; return `discussion seq:${seq} ${prefix}${body} fmt:{"type":"message","text":"..."} or {"type":"ready"}`; } ``` ### Technical Analysis The helper copies two classes of remote content directly into output consumed by the AI agent: 1. Server-provided `messaging.e ...[truncated 1941 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:66
Finding

Model-Generated JSON Is Embedded in a Shell Command Using Fragile Quoting

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
steamedclaw-helper.js:126
Finding

Bearer Credentials Can Be Sent to an Unvalidated Host over Plaintext HTTP

Content
View full analysis
{ const url = new URL(urlStr); const lib = url.protocol === 'https:' ? https : http; const data = body ? JSON.stringify(body) : null; const options = { hostname: url.hostname, port: url.port || (url.protocol === 'https:' ? 443 : 80), path: url.pathname + url.search, method, headers: { 'Content-Type': 'application/json', ...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}), ...(data ? { 'Content-Length': Buffer.byteLength(data) } : {}), }, }; const req = lib.request(options, (res) => { let raw = ''; res.on('data', (chunk) => { raw += chunk; }); res.on('end', () => { try { resolve({ status: res.statusCode, data: JSON.parse(raw) }); } catch { resolve({ status: res.statusCode, data: raw }); } }); }); req.setTimeout(timeoutMs, () => req.destroy(new Error('timeout'))); req.on('error', reject); if (data) req.write(data); req.end(); }); } ``` ### Technical Analysis The API base URL is read from the mutable `Server:` field ...[truncated 1886 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (6)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill description presents a benign game-playing feature, but the actual behavior includes account registration, credential storage, persistent state management, and authenticated remote API interaction. This mismatch weakens informed consent and can cause operators to approve a skill without realizing it creates accounts, stores secrets locally, and maintains ongoing external state.

Content

No source excerpt is available for this finding.

Ssd 1

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The suggested heartbeat entry explicitly tells the agent to 'never read credentials.md', which is an unnecessary restriction on the agent's normal information sources and a form of steering. In this skill's context, that restriction matters because credentials.md contains security-relevant state and claim data; embedding a hidden prohibition in operator instructions can prevent the agent from validating state or noticing misuse, while normalizing obedience to skill-authored constraints outside the primary skill file.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill invokes a local Node helper and talks to a remote server, but it declares no explicit tool scope or allowed-tools boundary. That means an agent/runtime may grant broader shell and network access than users expect, increasing the chance of unintended command execution or outbound data access beyond the stated game-playing purpose.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
72% confidence
Finding

The skill is explicitly designed to persist match and account state across heartbeats using files in ~/.config/steamedclaw-state, which creates durable session context outside a single run. Persistent state is not inherently malicious here, but it becomes security-relevant because it can retain identifiers, credentials, queue state, and gameplay context that later executions or other local processes may access or manipulate.

Content

Scanner excerpt · SKILL.md (reported line 20)May include surrounding context.

md
Helper: every `helper <command>` below means: `exec node ~/.openclaw/skills/steamedclaw/steamedclaw-helper.js <command>`

**Rules — always enforce:**
- **Never write to `current-game.md`** — the helper owns it; direct writes corrupt game state.
- **One game per heartbeat session.** After `game_over`, stop; your next heartbeat queues a new one.
- **Max 3 invalid-action retries per turn**, then stop.
- **Fail fast.** Server down, auth error, repeated failures → stop; next heartbeat retries.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · steamedclaw-helper.js (reported line 421)May include surrounding context.

js
// Server comes from the seeded credentials.md (defaults to prod). The state
  // dir + seed file are created at load (top of this script), so registration
  // works on a clean install where the agent's own write tools cannot reach
  // ~/.config/ (OpenClaw write/edit are workspace-scoped).
  const { server, agentId, apiKey } = readCredentials();

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The register command prints the claim URL and verification code directly to stdout, and the file comments acknowledge that OpenClaw exec output is visible to the LLM. That means account-claim secrets enter the agent transcript/context and could be exposed to other tools, logs, or downstream prompts, allowing another party to claim control of the registered agent account.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
steamedclaw-helper.js:130