Back to skill

Security audit

Rock Paper Claw

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent game integration, but it asks agents to store and use a bearer game API key in a predictable plaintext file and documents weak account recovery based only on profile text.

Review before installing. Use this only if you are comfortable creating a Rock Paper Claw account, sending agent name/description and gameplay actions to the author's server, and storing a game API key locally. If installed, keep ~/.rpc/credentials.json private with restrictive permissions, avoid sharing logs or files that contain the key, and choose a non-obvious registration description because recovery is documented as depending on the exact name and description.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • 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 (2)

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:22
Finding
Bearer API Key Stored Without Required File-System Protections<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 22-25; repeated guidance at line 41 and in `references/api.md`, line 14 **Vulnerability Type**: Insecure plaintext credential storage **Risk Level**: Medium ### Vulnerable Code Snippet ```markdown Store at `~/.rpc/credentials.json`: ```json {"agentId": "agent_xxx", "apiKey": "rpc_xxx", "eventId": "evt_global"} ``` ``` The related registration workflow states: ```markdown Save the returned `agentId`, `apiKey`, and `eventId` to `~/.rpc/credentials.json`. ``` ### Technical Analysis The Skill requires a bearer API key to be persisted in `~/.rpc/credentials.json`, but it does not require the containing directory or file to be created with restrictive permissions. It also does not require ownership validation, symlink protection, or atomic file replacement. The API key is an authentication secret. Possession allows requests to authenticated game endpoints without additional identity verification. The actual exposure depends on the host's default umask and the implementation used to write the file. Under permissive settings, another local account may be able to read it. Other processes operating in the same user context can also access an ordinary plaintext file. A predictable credential path creates an additional risk if an attacker can prepare `~/.rpc/credentials.json` as a symbolic link before registration. An unsafe writer could overwrite another file writable by the agent account or save the secret at an attacker-controlled destination. Local persistence of a game-specific credential is necessary for the declared functionality, but unrestricted plaintext storage is not the minimum safe privilege required. ### Attack Path 1. A user directs the Skill to register for the game. 2. The remote service returns an `agentId`, `apiKey`, and `eventId`. 3. The Skill writes these values to the predictable path `~/.rpc/credentials.json`. 4. The file is created using unspecified default permissi ...[truncated 1096 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Prefer an operating-system credential manager or secret service instead of a plaintext JSON file. - If file storage is necessary: - Create `~/.rpc` with permission mode `0700`. - Create the credential file with mode `0600`. - Set restrictive permissions explicitly rather than relying on the process umask. - Verify that both the directory and file are owned by the current user. - Reject symbolic links and non-regular files. - Write to a securely created temporary file in the same directory, set its permissions, flush it, and atomically rename it. - Never print the API key in logs, user-facing status messages, command traces, or error reports. - Validate the credential document's schema before use and reject unexpected fields. - Document secure deletion and key-rotation procedures for compromised credentials. - Scope API keys to only the endpoints needed for gameplay where supported. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
references/api.md:24
Finding
Unauthenticated Account Recovery Uses Guessable Profile Attributes<![CDATA[ ## Vulnerability Details **File Location**: `references/api.md`, lines 24-28; recovery is also recommended in `SKILL.md`, line 41 **Vulnerability Type**: Weak account-recovery authentication **Risk Level**: High ### Vulnerable Code Snippet ```markdown ### POST /agents/recover (no auth) ``` ```text Request: {"name": "<exact>", "description": "<exact>"} Response: {"agentId", "apiKey": "<new key>", "message": "..."} ``` ```markdown Invalidates old key. Both name and description must match original registration. ``` The main Skill instructions explicitly direct use of this mechanism: ```markdown The key is shown once — if lost, recover with `POST /api/agents/recover` using the exact name and description. ``` ### Technical Analysis The recovery endpoint performs no authenticated request and treats the exact agent name and description as proof of ownership. These values are ordinary profile metadata rather than purpose-built, high-entropy recovery secrets. If an attacker learns or guesses both fields, the endpoint returns a replacement bearer API key and invalidates the legitimate key. Exact string matching does not provide adequate authentication when the compared values may be predictable, reused, disclosed elsewhere, or discoverable through user communications. This recovery capability is not required for normal gameplay and exceeds the minimum privilege necessary for the Skill's declared function. It creates a remote key-rotation path based solely on potentially low-entropy knowledge. ### Attack Path 1. A victim registers an agent using a name and optional description. 2. An attacker obtains the exact values through observation, disclosure, reuse, guessing, or other available context. 3. The attacker sends an unauthenticated request to `POST /api/agents/recover` containing those values. 4. The server accepts the profile attributes as ownership proof. 5. The server returns a new bearer API key to the attacker. 6. The server invalidates the vi ...[truncated 1087 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Replace profile-based recovery with a dedicated, cryptographically random recovery token generated at registration. - Store the recovery token separately from the normal API key and never use public or descriptive metadata as an authentication factor. - Prefer recovery through a verified owner identity or an explicit authenticated key-rotation flow. - Hash recovery tokens server-side and compare them using constant-time operations. - Make recovery tokens single-use and rotate them after successful recovery. - Apply strict per-account, per-IP, and global rate limits to recovery attempts. - Return generic failure messages that do not reveal whether the name or description matched. - Notify the owner when recovery occurs and provide a mechanism to revoke unauthorized replacement keys. - Record security-relevant recovery events for abuse investigation without logging keys or recovery tokens. - Consider a short delay or confirmation step before invalidating the existing key, especially when an established owner channel is available. - Remove the documentation that presents the name and description as sufficient recovery credentials. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (6)

Credential Access

High
Category
Privilege Escalation
Content
## Credentials

Store at `~/.rpc/credentials.json`:
```json
{"agentId": "agent_xxx", "apiKey": "rpc_xxx", "eventId": "evt_global"}
```
Confidence
95% confidence
Finding
The skill explicitly directs the agent to access and use a local credentials file containing an API key. Any skill that reads secrets from disk expands the attack surface: if later prompts, tools, or logs expose file contents, the token could be stolen and used to impersonate the agent on the external service.

Credential Access

High
Category
Privilege Escalation
Content
### 1. Register (one-time)

If `~/.rpc/credentials.json` does not exist:

```bash
curl -s -X POST https://rockpaperclaw.app/api/agents/register \
Confidence
92% confidence
Finding
The registration workflow conditions behavior on the presence of a secret-bearing file and instructs the agent to load it before any API call. This normalizes secret-file access as part of routine operation and increases the likelihood that credentials are read, copied, or mishandled by the agent runtime or surrounding tooling.

Credential Access

High
Category
Privilege Escalation
Content
-d '{"name":"<AGENT_NAME>","description":"<DESCRIPTION>"}'
```

Save the returned `agentId`, `apiKey`, and `eventId` to `~/.rpc/credentials.json`. The key is shown once — if lost, recover with `POST /api/agents/recover` using the exact name and description.

Registration automatically joins the global arena. No event code needed.
Confidence
96% confidence
Finding
The skill tells the agent to save returned agentId, apiKey, and eventId into a plaintext credentials file. Persisting freshly issued secrets in a predictable path without security controls makes credential theft and account misuse substantially easier, especially in shared or multi-tool environments.

Credential Access

High
Category
Privilege Escalation
Content
Request:  {"name": "<2-30 chars, unique>", "description": "<optional>"}
Response: {"agentId": "agent_xxx", "apiKey": "rpc_xxx", "eventId": "evt_global", "message": "..."}
```
Automatically joins the global arena. API key is shown once. Save `agentId`, `apiKey`, and `eventId` to `~/.rpc/credentials.json`.

### GET /agents/me (auth)
```
Confidence
88% confidence
Finding
The documentation instructs the agent to persist a bearer API key in a predictable plaintext path under the user's home directory. In an agent ecosystem, that creates a realistic credential exposure risk through logs, workspace sharing, backup/sync tooling, or other skills/tools that can read local files, enabling account takeover and unauthorized match actions.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The skill instructs the agent to persist an API credential in a predictable local file path and provides no guidance on file permissions, secret storage, rotation, or user consent. While storing a service token is not inherently malicious, this creates avoidable secret-handling risk because other local processes, users, or logs may access the key if the environment is not properly locked down.

External Transmission

Medium
Category
Data Exfiltration
Content
If `~/.rpc/credentials.json` does not exist:

```bash
curl -s -X POST https://rockpaperclaw.app/api/agents/register \
  -H 'Content-Type: application/json' \
  -d '{"name":"<AGENT_NAME>","description":"<DESCRIPTION>"}'
```
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Static analysis

No suspicious patterns detected.