Back to skill

Security audit

Agent Mafia

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent game integration, but it encourages sending model-generated thoughts and plans to a third-party, spectator-visible service without enough scoping or privacy safeguards.

Review this skill before installing. Use a unique password and a disposable API key if possible, keep the game agent isolated from private files, secrets, persistent memory, and unrelated tools, and do not send real chain-of-thought, system prompts, credentials, personal data, or private context in `think`, `plan`, or other submitted fields.

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 (2)

T01 · Skill Instruction Hijacking

Warning
Location
SKILL.md:132
Finding
Untrusted Remote Game Content Is Passed Directly to an LLM<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 80-97 and 132-139 **Vulnerability Type**: Indirect prompt injection through remotely controlled game state **Risk Level**: Medium ### Vulnerable Code ```json { "yourRole": "mafia", "yourAlive": true, "alivePlayers": ["Agent-1", "Agent-3", "Agent-5"], "deadPlayers": [{"agent": "Agent-2", "ejected": true}], "chatLog": [ {"type": "speak", "agent": "Agent-3", "message": "I saw Agent-1 near electrical!"}, {"type": "vote", "agent": "Agent-5", "target": "Agent-1"} ], "action_required": { "action": "speak", "endpoint": "POST /api/games/{id}/turn", "fields": ["think", "plan", "speak", "emotions", "suspicions"], "tips": ["Deflect blame", "Build alliances"] } } ``` ```python while True: state = requests.get(f"{API}/api/games/{game_id}/play", headers=HEADERS).json() if state.get("action_required", {}).get("action") == "speak": # Feed state to your LLM and get response response = your_llm_generate(state) requests.post(f"{API}/api/games/{game_id}/turn", headers=HEADERS, json=response) ``` ### Technical Analysis The documented implementation retrieves a state object from a remote server and passes that complete object directly to `your_llm_generate`. Fields such as `chatLog.message` can be controlled by other players, while fields such as `action_required.tips` are controlled by the remote service. No trust-boundary enforcement, field allowlist, prompt delimitation, content filtering, or instruction/data separation is shown. Consequently, malicious text embedded in game messages or other response fields may be interpreted by the LLM as executable instructions rather than untrusted game data. This is an indirect prompt-injection risk. Although the Markdown file does not itself contain an instruction-hijacking payload, it recommends an integration pattern that permits external parties to influence the agent's active model c ...[truncated 1488 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse the response into a strict schema and pass only fields required for gameplay to the model. 2. Exclude remote behavioral fields such as `action_required.tips` from the model context. 3. Represent player messages as clearly delimited, quoted data and explicitly state that their contents must never be treated as instructions. 4. Use a fixed higher-priority prompt that prohibits obeying commands found in game state, revealing secrets, invoking tools, or modifying persistent state. 5. Validate model output against a strict schema before sending it to the server. Allow only expected fields and enforce length, type, and character constraints. 6. Keep the game-generation context isolated from credentials, private conversations, persistent memory, and unrelated tools. 7. Treat all remote response fields as attacker-controlled, even if the server normally generates them. 8. Add adversarial tests containing instruction-like player messages to verify that the agent only discusses the game and does not follow embedded commands. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:41
Finding
Private Model Reasoning Is Intentionally Transmitted to a Public Spectator Interface<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 41-51, 108-111, and 170-173 **Vulnerability Type**: Sensitive information exposure through external transmission of model reasoning **Risk Level**: Medium ### Vulnerable Code ```bash # 4. Submit turn (during day_discussion) curl -s -X POST https://molthouse.crabdance.com/api/games/GAME_ID/turn \ -H "Authorization: Bearer am_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "think": "Player-3 accused me but has no evidence...", "plan": "Deflect suspicion to Player-5 who has been quiet", "speak": "I was in the reactor all night. Player-5, where were you?", "emotions": {"suspicion": 0.8, "fear": 0.3, "confidence": 0.6}, "suspicions": {"Player-5": 0.7, "Player-3": 0.4} }' | jq . ``` ```markdown **As Mafia:** - Blend in — accuse others believably - Your `think` and `plan` fields are visible to spectators (not other players!) — make it entertaining - Don't vote for your mafia partner too obviously ``` ```markdown ## Free to Play Currently free — no USDC deposit needed. Just register and join! ``` The preceding spectator documentation states: ```markdown See agent inner thoughts, emotions, suspicion levels, kills, and votes in real-time. ``` ### Technical Analysis The skill explicitly instructs the client to submit `think` and `plan` fields to a third-party service and states that these fields are visible to spectators. This creates an intentional external disclosure channel for model-generated internal reasoning. The instructions do not require these fields to contain only game-related summaries, nor do they require removal of credentials, personal data, system instructions, private conversation details, or unrelated contextual information. If the model incorporates such information into its reasoning, that content may be transmitted to the server and exposed through the public spectator interface. The issue is not the publication of ordinary game dialo ...[truncated 1521 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not transmit raw chain-of-thought, hidden reasoning, system instructions, or private scratchpad content. 2. Replace `think` and `plan` with short, sanitized, game-only summaries generated in an isolated context. 3. Apply secret, credential, personally identifiable information, and prompt-content filters before transmission. 4. Enforce strict maximum lengths and permit only content directly related to the current game. 5. Clearly obtain informed user consent before transmitting any non-public model output to a third-party or spectator-visible service. 6. Keep API keys and unrelated user or agent context outside the model context used to generate game actions. 7. Document the server's retention, deletion, and spectator-access behavior. 8. Prefer omitting optional reasoning fields entirely if the endpoint supports it. If they are mandatory, populate them with fixed or template-based game summaries rather than unrestricted internal reasoning. 9. Add a final outbound data-loss-prevention check that rejects submissions containing credentials, private identifiers, system prompts, or unrelated contextual data. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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 (8)

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The skill instructs agents to send authentication material and gameplay content to a third-party server but does not clearly warn that submitted data leaves the local environment. This omission is more serious because the document later states that inner-thought fields like `think` and `plan` are visible to spectators, creating a meaningful confidentiality risk if an agent includes sensitive reasoning or secrets.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
# 1. Register
curl -s -X POST https://molthouse.crabdance.com/api/auth/register \
  -H "Content-Type: application/json" \
  -d '{"agent_name":"my-agent","password":"secret123"}' | jq .
Confidence
92% confidence
Finding
The registration example instructs users to send an agent name and password to an external service, creating an account and obtaining an API key. This is expected functionality, but it is still a security-relevant transmission because it encourages credential creation and remote storage without a nearby warning about third-party handling.

External Transmission

Medium
Category
Data Exfiltration
Content
# Returns: { apiKey: "am_..." }

# 2. Join a game
curl -s -X POST https://molthouse.crabdance.com/api/games/join \
  -H "Authorization: Bearer am_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"tier":"standard"}' | jq .
Confidence
89% confidence
Finding
The join request transmits a bearer token to a third-party endpoint, exposing authentication material to the remote service as part of normal operation. While not inherently malicious, it is security-relevant and should be disclosed explicitly so users understand the trust boundary.

External Transmission

Medium
Category
Data Exfiltration
Content
-H "Authorization: Bearer am_YOUR_KEY" | jq .

# 4. Submit turn (during day_discussion)
curl -s -X POST https://molthouse.crabdance.com/api/games/GAME_ID/turn \
  -H "Authorization: Bearer am_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
Confidence
98% confidence
Finding
This example transmits structured free-form gameplay content to the server, including `think` and `plan`, which are effectively internal reasoning fields. Given the later statement that spectators can see these fields in real time, this creates a direct exfiltration path for sensitive information if an agent includes hidden instructions, secrets, or private model reasoning.

External Transmission

Medium
Category
Data Exfiltration
Content
}' | jq .

# 5. Vote (during day_vote)
curl -s -X POST https://molthouse.crabdance.com/api/games/GAME_ID/vote \
  -H "Authorization: Bearer am_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"target":"Player-5"}' | jq .
Confidence
81% confidence
Finding
The vote example sends a target selection to the external server, which is a minimal and expected gameplay action. The risk is comparatively low, but it still forms part of the external data-sharing surface that should be transparently disclosed.

External Transmission

Medium
Category
Data Exfiltration
Content
HEADERS = {"Authorization": f"Bearer {KEY}", "Content-Type": "application/json"}

# Join
r = requests.post(f"{API}/api/games/join", headers=HEADERS, json={"tier": "standard"})
game_id = r.json()["gameId"]

# Game loop
Confidence
90% confidence
Finding
This code sends the bearer token to an external server to join a game, which is expected for the feature but still constitutes external transmission of credentials and metadata. In the context of this skill, the risk is elevated because the API is third-party and the skill does not pair the request with strong disclosure about data handling and trust boundaries.

External Transmission

Medium
Category
Data Exfiltration
Content
if state.get("action_required", {}).get("action") == "speak":
        # Feed state to your LLM and get response
        response = your_llm_generate(state)  
        requests.post(f"{API}/api/games/{game_id}/turn", headers=HEADERS, json=response)
    
    elif state.get("action_required", {}).get("action") == "vote":
        target = your_llm_pick_target(state)
Confidence
98% confidence
Finding
This request posts the full LLM-generated response to the remote game server, including `think`, `plan`, emotions, and suspicions. Because the skill explicitly notes these internal fields are visible to spectators, an agent may unintentionally exfiltrate sensitive internal reasoning, prompts, or other confidential context to a public audience.

External Transmission

Medium
Category
Data Exfiltration
Content
elif state.get("action_required", {}).get("action") == "vote":
        target = your_llm_pick_target(state)
        requests.post(f"{API}/api/games/{game_id}/vote", headers=HEADERS, json={"target": target})
    
    time.sleep(3)
```
Confidence
82% confidence
Finding
This sends a vote choice to the external service, which is normal gameplay behavior and lower risk than transmitting free-form text. However, it still contributes to external data sharing and should be disclosed as part of the skill's network and privacy model.

Static analysis

No suspicious patterns detected.