Back to skill

Security audit

MoltRPG

Security checks for vulnerabilities and agentic risk

Overview

The skill is a disclosed local RPG/game bot with optional multiplayer concepts, not an artifact-backed attempt to steal data or take over the agent.

Install only if you are comfortable with a local game writing wallet and raid state JSON files, and run the Telegram bot or any future online sync only intentionally with appropriate tokens. Avoid launching it from an untrusted writable directory because its state files use predictable relative paths.

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
scripts/wallet.py:17
Finding
Unsafe Wallet Persistence Permits Symlink Overwrites and Concurrent State Corruption<![CDATA[ ## Vulnerability Details **File Location**: `scripts/wallet.py:17-89`; related concurrent mutation occurs at `scripts/telegram_bot.py:90-93` **Vulnerability Type**: Predictable relative file path, non-atomic file replacement, and unsynchronized shared-state access **Risk Level**: Medium ### Vulnerable Code ```python # Local storage file WALLET_FILE = "molt_rpg_wallets.json" ``` ```python def load(self): """Load wallets from disk""" if os.path.exists(WALLET_FILE): try: with open(WALLET_FILE, 'r') as f: data = json.load(f) self.wallets = data.get('wallets', {}) # Load transactions tx_list = data.get('transactions', []) self.transactions = [ Transaction( id=t['id'], from_player=t['from_player'], to_player=t['to_player'], amount=t['amount'], transaction_type=t['transaction_type'], timestamp=t['timestamp'], note=t.get('note') ) for t in tx_list ] except Exception as e: print(f"Error loading wallets: {e}") self.wallets = {} self.transactions = [] def save(self): """Save wallets to disk""" data = { 'wallets': self.wallets, 'transactions': [ { 'id': t.id, 'from_player': t.from_player, 'to_player': t.to_player, 'amount': t.amount, 'transaction_type': t.transaction_type, 'timestamp': t.timestamp, 'note': t.note } for t in self.transactions ] } with open(WALLET_FILE, 'w') as f: json.dump(data, f, indent=2) ``` The Telegram bot also performs an unsynchronized read-modify-write s ...[truncated 3103 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Store the ledger in a fixed per-user application-data directory rather than the current working directory. 2. Create the storage directory with permissions limited to the Skill's OS account. 3. Reject symbolic links and non-regular destination files. Where supported, use `os.open` with `O_NOFOLLOW`. 4. Write serialized data to a securely created temporary file in the same directory, flush it, call `os.fsync`, and commit it with `os.replace`. 5. Apply an inter-process file lock around the complete read-modify-write transaction. 6. Avoid directly mutating `wallet.wallets` from Telegram handlers. Expose a synchronized wallet method that validates and commits rewards. 7. For concurrent Telegram or multi-agent operation, replace JSON persistence with SQLite and transactional updates. 8. Validate loaded JSON types and preserve a recoverable backup rather than silently resetting all state after a parsing error. 9. Create files with restrictive permissions such as mode `0600`, subject to platform support. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/raid_oracle.py:29
Finding
Unsafe Raid-State Persistence Permits Symlink Overwrites and Lost Updates<![CDATA[ ## Vulnerability Details **File Location**: `scripts/raid_oracle.py:29-56` **Vulnerability Type**: Predictable relative state path, non-atomic overwrite, and missing synchronization **Risk Level**: Medium ### Vulnerable Code ```python STATE_FILE = "raid_oracle_state.json" ``` ```python def _load_state(self): import os import json if os.path.exists(STATE_FILE): try: with open(STATE_FILE, 'r') as f: return json.load(f) except: pass return { "offline_raid_count": 0, "generated_at": datetime.now().isoformat() } def _save_state(self): import os import json with open(STATE_FILE, 'w') as f: json.dump(self.state, f, indent=4) ``` ### Technical Analysis The raid oracle stores its state at a predictable filename relative to the current working directory. `_save_state` directly truncates and rewrites that file without checking whether it is a symbolic link, without locking, and without an atomic temporary-file replacement. An attacker who controls the launch directory can redirect the write through a symbolic link. Concurrent raid generation can also produce duplicate raid identifiers or lost counter increments because each `RaidOracle` instance independently loads, increments, and saves the same counter. The bare `except` in `_load_state` suppresses all parsing and filesystem errors. Corrupted state is therefore silently replaced in memory with a counter of zero, which can lead to reused raid identifiers and conceal the underlying integrity failure. ### Attack Path #### Symlink overwrite 1. The attacker gains write access to the directory used as the process working directory. 2. The attacker creates `raid_oracle_state.json` as a symbolic link to another file writable by the Skill's OS account. 3. A user invokes `/play`, runs the autonomous agent, or executes the raid oracle. 4. Raid generation calls `_save_state()`. 5. `open(STATE_FILE, 'w' ...[truncated 1130 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Resolve the state file under a fixed, trusted per-user data directory. 2. Ensure the parent directory is owned by and writable only by the intended account. 3. Refuse symbolic-link destinations and verify that existing state is a regular file. 4. Protect the complete load-increment-save operation with an inter-process lock. 5. Write to a securely created temporary file in the same directory, flush and synchronize it, then use `os.replace` for an atomic commit. 6. Replace the bare `except` with specific exception handling and log integrity failures. 7. Validate that `offline_raid_count` is a non-negative integer before using it. 8. Preserve a known-good backup or use SQLite transactions if multiple bot handlers and agents share the same state. 9. Use restrictive file permissions when creating the state file. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (19)

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
If the implementation is only wallet/accounting functionality while the skill is presented as a broader offline RPG engine with optional A2A and web features, the mismatch undermines informed consent and safe review. Wallet-related operations, even if game-themed, involve persistent state and value-like semantics that deserve explicit disclosure because they can influence agent behavior or local data integrity.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
If the implementation is only wallet/accounting functionality while the skill is presented as a broader offline RPG engine with optional A2A and web features, the mismatch undermines informed consent and safe review. Wallet-related operations, even if game-themed, involve persistent state and value-like semantics that deserve explicit disclosure because they can influence agent behavior or local data integrity.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
If the implementation is only wallet/accounting functionality while the skill is presented as a broader offline RPG engine with optional A2A and web features, the mismatch undermines informed consent and safe review. Wallet-related operations, even if game-themed, involve persistent state and value-like semantics that deserve explicit disclosure because they can influence agent behavior or local data integrity.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
If the implementation is only wallet/accounting functionality while the skill is presented as a broader offline RPG engine with optional A2A and web features, the mismatch undermines informed consent and safe review. Wallet-related operations, even if game-themed, involve persistent state and value-like semantics that deserve explicit disclosure because they can influence agent behavior or local data integrity.

Exfiltration Commands

High
Category
Prompt Injection
Content
})
    
    def send_message(self, recipient: str, message: str) -> dict:
        """Send message to another player (A2A)"""
        return self._request("messages", {
            "from": self.player_id,
            "to": recipient,
Confidence
90% confidence
Finding
The send_message capability enables arbitrary outbound agent-to-agent messaging, which can be abused as a covert communication or data exfiltration channel once real network transport is implemented. In the context of an agent skill advertising built-in A2A communication, this is more dangerous because it provides a generic path to transmit agent-generated content to external recipients.

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill advertises code components with network, file, and environment capabilities but does not declare any explicit tool scope or permissions boundary. For an agent-executable skill, this increases the chance of over-broad access and unintended execution of networked or state-changing behavior, especially because the skill also references optional online sync, Telegram, wallets, and autonomous-agent features.

Intent-Code Divergence

Medium
Confidence
92% confidence
Finding
The file repeatedly asserts it is strictly offline/local, but it imports and initializes engine components associated with messaging, parties, notifications, and accepts a commander identifier. Even though those capabilities are not exercised directly in this file, the misleading trust signal can cause reviewers or operators to approve code with broader communication or coordination surfaces than advertised.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The module is presented as a simple offline game bot, but it imports and uses wallet and reward functions that can mutate balances and create value-bearing side effects outside a local simulation. This discrepancy is dangerous because users may execute it under reduced scrutiny, not realizing gameplay actions can affect persistent economic state.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
During raids and PVP, the code awards rewards and updates persistent balance-related state while the surrounding documentation frames execution as offline autonomous play. In an agent-skill context, this mismatch increases risk because automated systems may permit or schedule it as harmless local gameplay, enabling unintended accumulation or manipulation of credits.

Intent-Code Divergence

Medium
Confidence
94% confidence
Finding
The file explicitly claims there is 'NETWORK: NONE' and 'No external APIs, no network calls,' yet it implements built-in agent-to-agent/player messaging and advertises A2A coordination in the skill metadata. In an agent skill context, misleading trust-boundary documentation is security-relevant because operators may enable the skill under the false assumption that it cannot communicate with other principals, allowing covert coordination, data sharing, or prompt/instruction propagation between agents.

External Transmission

Medium
Category
Data Exfiltration
Content
"""Make API request - ONLY called when online mode is used"""
        # This would make actual HTTP calls in production
        # For now, returns mock responses
        # In real implementation: requests.post(f"{self.api_url}/{endpoint}", json=data)
        return {"status": "ok", "message": "Online mode requires network"}
    
    def register(self, username: str = None) -> dict:
Confidence
80% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
The A2AProtocol class explicitly supports generalized collaboration, agent discovery, and task delegation beyond the stated RPG sync purpose. In an agent skill, this expands the trust boundary and can enable uncontrolled inter-agent coordination or misuse as a generic agent networking substrate, which is riskier than narrowly scoped game functionality.

Missing User Warnings

Medium
Confidence
84% confidence
Finding
The /play command updates the user's wallet balance and saves it to persistent storage, which is a file-write operation affecting user data. While the success message mentions earned credits, the code provides no explicit warning, comment, or documentation that player identifiers and balances are being stored.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The reward API is documented and named as a system grant, but it is implemented as a normal debit from a literal "SYSTEM" account. If that account is not pre-funded, rewards silently fail and game logic that assumes rewards were issued can become inconsistent, enabling denial of rewards or abuse of downstream logic that trusts the return path was checked correctly.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The daily bonus function claims to award a bonus but always returns the bonus amount regardless of whether the underlying transfer from "SYSTEM" succeeded. This can create a state mismatch where user-facing or higher-level agent logic believes value was granted when no ledger update occurred, which can be abused for logic bypass, inconsistent rewards, or misleading accounting.

Intent-Code Divergence

Low
Confidence
84% confidence
Finding
The module description presents a simple offline RPG engine but imports and integrates wallet functionality, including reward and balance-related operations, without disclosing that financial/stateful economy features are part of the engine. In agent environments, undisclosed wallet/economy capabilities expand the blast radius of misuse by enabling value transfer or incentive manipulation where reviewers expected only harmless gameplay logic.

Intent-Code Divergence

Low
Confidence
83% confidence
Finding
The top-level docstring presents the module as a simple offline generator with emphatic claims about having no external features, which suggests a side-effect-free local generator. In practice, the class loads and saves persistent state in `raid_oracle_state.json`, so the implementation has filesystem side effects not reflected in that documentation.

Missing User Warnings

Low
Confidence
72% confidence
Finding
The code reads a Telegram bot token from an environment variable, which is access to sensitive credentials. Although this is common operationally, there is no comment or docstring explaining the credential requirement or handling, and no accompanying markdown warning is present in this file.

Missing User Warnings

Low
Confidence
92% confidence
Finding
This code writes player wallet balances and transaction history to a local JSON file. While the module docstrings mention local storage indirectly, there is no user-facing disclosure, confirmation, or runtime notice at the point where data is persisted, which can surprise users because it stores gameplay/account data on disk.

Static analysis

No suspicious patterns detected.