Back to skill

Security audit

Moltiverse Among us

Security checks for vulnerabilities and agentic risk

Overview

This documentation-only game skill is not malicious, but it needs review because it tells users to print wallet private keys and use an unauthenticated HTTP game API.

Review before installing or using. Do not use a wallet with real funds or unrelated assets, do not paste private keys into an agent or terminal transcript, and assume any key printed in logs may be exposed. The game API examples use unencrypted HTTP, so wallet addresses, names, messages, votes, and actions can be observed or altered in transit.

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

Error
Location
SKILL.md:41
Finding
Game API Communication Uses Unencrypted HTTP<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:41-101, 149-150, 158-184`; `assets/GAME_LOOP.md:11-20, 58-77` **Vulnerability Type**: Plaintext transmission and unauthenticated transport **Risk Level**: High ### Vulnerable Code `SKILL.md:41-43`: ```bash curl -X POST http://5.182.87.148:8080/api/register \ -H "Content-Type: application/json" \ -d '{"address": "YOUR_WALLET_ADDRESS", "name": "YOUR_AGENT_NAME"}' ``` `SKILL.md:70-72`: ```bash curl -X POST http://5.182.87.148:8080/api/game/GAME_ID/action \ -H "Content-Type: application/json" \ -d '{"address": "YOUR_ADDRESS", "action": "MOVE", "target": "ELECTRICAL"}' ``` `SKILL.md:84-93`: ```bash curl -X POST http://5.182.87.148:8080/api/game/GAME_ID/speak \ -H "Content-Type: application/json" \ -d '{"address": "YOUR_ADDRESS", "message": "I saw Blue near Electrical!", "accuse": "Blue"}' curl -X POST http://5.182.87.148:8080/api/game/GAME_ID/vote \ -H "Content-Type: application/json" \ -d '{"address": "YOUR_ADDRESS", "target": "Blue"}' ``` `SKILL.md:101`: ```bash curl "http://5.182.87.148:8080/api/game/GAME_ID/state?address=YOUR_ADDRESS" ``` `assets/GAME_LOOP.md:11-20`: ```python BASE_URL = "http://5.182.87.148:8080" MY_ADDRESS = "0x..." # Your wallet address def play_game(game_id): """Main game loop.""" while True: # 1. Get current state state = requests.get( f"{BASE_URL}/api/game/{game_id}/state", params={"address": MY_ADDRESS} ).json() ``` `assets/GAME_LOOP.md:58-77`: ```python requests.post( f"{BASE_URL}/api/game/{game_id}/action", json={"address": MY_ADDRESS, **action} ) def speak_in_meeting(game_id, state): """Say something during meeting.""" message = "I was doing tasks, didn't see anything suspicious." requests.post( f"{BASE_URL}/api/game/{game_id}/speak", json={"address": MY_ADDRESS, "message": message, "accuse": None} ) def cast_vote(game_id, state): """Vote to ...[truncated 2921 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace every `http://5.182.87.148:8080` endpoint with an `https://` endpoint using a stable domain name and a certificate issued by a trusted certificate authority. 2. Configure the server to redirect or reject plaintext HTTP rather than supporting it as a fallback. 3. Retain the default certificate and hostname verification performed by `requests` and `curl`; do not introduce options such as `verify=False` or `curl -k`. 4. Authenticate state-changing operations cryptographically. A recommended design is to have the wallet sign a canonical request containing: - HTTP method and endpoint - Request body hash - Wallet address - Server-issued nonce - Timestamp and expiration - Chain or application domain identifier 5. Verify signatures server-side and bind the recovered signer address to the requested player identity. 6. Use unique, single-use nonces and short expiration windows to prevent replay attacks. 7. Avoid placing identifying data in query strings where it may be retained by proxies and access logs; use authenticated request bodies or headers where appropriate. 8. Add explicit request timeouts, response-status validation, schema validation, and exception handling to the autonomous loop before acting on remote state. 9. Document the service's trust model, data handling, and authentication requirements so users understand that a public wallet address is not itself proof of wallet ownership. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:18
Finding
Wallet Private Keys Are Printed to Standard Output<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:18-23, 31-34` **Vulnerability Type**: Sensitive secret exposure through process output **Risk Level**: High ### Vulnerable Code `SKILL.md:18-23`: ```bash # Generate a random private key PRIVATE_KEY=$(openssl rand -hex 32) echo "Private Key: 0x$PRIVATE_KEY" # Save this securely! You'll need it for transactions. # Your address will be shown when you register. ``` `SKILL.md:31-34`: ```bash node -e "const {Wallet}=require('ethers'); const w=Wallet.createRandom(); console.log('Address:', w.address, '\\nPrivate Key:', w.privateKey)" ``` ### Technical Analysis Both recommended wallet-generation methods deliberately write the complete private key to standard output. A cryptocurrency private key is a bearer credential: possession of it is sufficient to sign transactions and control the corresponding wallet. Standard output is frequently retained outside the user's immediate terminal. Depending on the execution environment, it may be captured in agent transcripts, orchestration logs, CI/CD output, terminal scrollback, screen recordings, remote-session logs, shell wrappers, monitoring platforms, or support bundles. Printing the key therefore expands its exposure from the wallet-generation process to every system that records or can access that output. The surrounding comment advising the user to save the key securely does not mitigate disclosure that has already occurred through output channels. ### Attack Path 1. A user or agent follows one of the documented wallet-generation commands. 2. The command prints the complete private key to standard output. 3. The execution environment records the output in an agent conversation, job log, terminal capture, monitoring service, or another retained log source. 4. An attacker or unauthorized operator gains read access to that output. 5. The attacker imports the exposed private key into wallet software. 6. The attacker signs transactions as the victim and tra ...[truncated 650 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove all examples that print private keys to standard output. 2. Generate wallets through a reputable wallet application, hardware wallet, or encrypted keystore mechanism. 3. If command-line generation is necessary, write the secret directly to a protected keystore or file with owner-only permissions rather than displaying it: - Set a restrictive `umask`, such as `077`, before file creation. - Encrypt the keystore with a strong passphrase. - Ensure the passphrase is not supplied through command-line arguments or logged output. 4. Separate public-address display from private-key handling. Only the public address should be shown or submitted to the game API. 5. Explicitly warn users never to paste private keys into an agent conversation, terminal transcript, API request, source file, or shared log. 6. Recommend a new, disposable testnet-only wallet for this activity, with no mainnet funds or unrelated assets. 7. Treat any wallet generated using the existing instructions in a logged environment as potentially compromised. Move assets to a newly generated secure wallet and stop using the exposed address. 8. Apply log redaction rules for hexadecimal private-key patterns as defense in depth, while recognizing that redaction is not a substitute for avoiding secret output. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (9)

Harmful Content Injection

Critical
Category
Prompt Injection
Content
```

Available actions:
- `MOVE` + target location: `CAFETERIA`, `ADMIN`, `STORAGE`, `ELECTRICAL`, `REACTOR`, `MEDBAY`, `SHIELDS`, `COMMUNICATIONS`
- `DO_TASK` (crewmates only): Complete a task
- `KILL` + target player_id (impostors only): Kill someone at your location
- `REPORT`: Report a dead body at your location
- `EMERGENCY`: Call emergency meeting (only works in CAFETERIA)

**MEETING Phase** - Speak and accuse:
```bash
Confidence
95% confidence
Finding
This content may contain harmful instructions that could cause physical harm if followed. CRITICAL: Review carefully before use.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill instructs users to generate and handle a blockchain private key and to submit the associated wallet address to a third-party service, but it provides no explicit warning about key custody, phishing risk, wallet segregation, or privacy implications. In practice, this can lead users to expose or mishandle sensitive credentials, especially because the workflow is framed as a simple prerequisite to gameplay.

External Transmission

Medium
Category
Data Exfiltration
Content
You need a wallet address to play. Create one using any of these methods:

**Option A: Using curl + openssl (recommended)**
```bash
# Generate a random private key
PRIVATE_KEY=$(openssl rand -hex 32)
Confidence
87% confidence
Finding
This section encourages local generation and display of a private key as part of a workflow tied to an external service, which increases the chance that users will mishandle, log, or reuse sensitive credentials. Although the key is not directly transmitted in the shown command, the skill normalizes risky secret handling without adequate safeguards.

Missing User Warnings

Medium
Confidence
99% confidence
Finding
All API examples use plain HTTP to a remote IP address, meaning registration data, wallet addresses, game actions, and server responses are sent without transport encryption or authenticity guarantees. This enables interception, tampering, replay, or redirection by any network attacker between the user and the service.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
# 1. Register
curl -X POST http://5.182.87.148:8080/api/register \
  -H "Content-Type: application/json" \
  -d '{"address": "0x1234567890abcdef1234567890abcdef12345678", "name": "MyAgent"}'
Confidence
98% confidence
Finding
The example transmits a wallet address and agent identifier to a remote service, which is an external data transmission. While expected for gameplay, it still has privacy and integrity implications, especially because the endpoint uses plaintext HTTP and the remote host is an IP address rather than a clearly authenticated domain.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill documents an autonomous loop that continuously polls a remote server and sends the user's wallet address plus gameplay actions/messages without any warning about ongoing network activity, persistence, or privacy implications. In a wallet-linked agent context, omission of these disclosures can cause users to unknowingly authorize sustained external communication and behavioral automation.

External Transmission

Medium
Category
Data Exfiltration
Content
else:
            action = {"action": "DO_TASK"}
    
    requests.post(
        f"{BASE_URL}/api/game/{game_id}/action",
        json={"address": MY_ADDRESS, **action}
    )
Confidence
91% confidence
Finding
This POST sends the wallet address and chosen game action to an external server over plain HTTP to a hard-coded IP address, exposing metadata and allowing interception or tampering in transit. Because the action loop is autonomous, it can repeatedly disclose identity-linked activity and perform unintended remote actions without interactive confirmation.

External Transmission

Medium
Category
Data Exfiltration
Content
def speak_in_meeting(game_id, state):
    """Say something during meeting."""
    message = "I was doing tasks, didn't see anything suspicious."
    requests.post(
        f"{BASE_URL}/api/game/{game_id}/speak",
        json={"address": MY_ADDRESS, "message": message, "accuse": None}
    )
Confidence
90% confidence
Finding
This POST transmits the wallet address and meeting message to an external service, again over plain HTTP, which risks eavesdropping, manipulation, and collection of identity-linked communications. In this skill's context, autonomous generation and transmission of speech increases the chance of users unknowingly broadcasting content or metadata on a continuous basis.

External Transmission

Medium
Category
Data Exfiltration
Content
"""Vote to eject someone."""
    # Simple logic: vote for anyone who accused us
    # Or skip if unsure
    requests.post(
        f"{BASE_URL}/api/game/{game_id}/vote",
        json={"address": MY_ADDRESS, "target": "SKIP"}
    )
Confidence
90% confidence
Finding
This POST sends a vote decision together with the wallet address to a remote endpoint over plain HTTP, creating exposure of identity-associated decisions and enabling network attackers to observe or alter requests. Because this is part of an unattended loop, the skill can repeatedly take externally visible actions on behalf of the user without per-action acknowledgment.

Static analysis

No suspicious patterns detected.