Back to skill

Security audit

Minecraft Monitor

Security checks for vulnerabilities and agentic risk

Overview

This skill is a straightforward Minecraft server status checker, with limited risks from trusting responses from the server being checked.

Reasonable to install for manual Minecraft server checks. Use caution when pointing it at untrusted servers, especially in automated monitoring, because a hostile endpoint could hang or exhaust the checker process or print misleading terminal output.

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/minecraft-status.py:31
Finding
Unbounded parsing of attacker-controlled protocol response lengths<![CDATA[ ## Vulnerability Details **File Location**: `scripts/minecraft-status.py`, lines 31-43 and 67-80 **Vulnerability Type**: Improper input validation and uncontrolled resource consumption **Risk Level**: Medium ### Vulnerable Code ```python def decode_varint(sock): """Decode a Minecraft varint from socket.""" num = 0 shift = 0 while True: byte = sock.recv(1) if not byte: raise IOError("Connection closed") byte = byte[0] num |= (byte & 0x7F) << shift if not (byte & 0x80): break shift += 7 return num ``` ```python def read_status_response(sock): """Read server status response.""" # Packet length length = decode_varint(sock) # Packet ID should be 0x00 packet_id = decode_varint(sock) # Response length response_len = decode_varint(sock) # Response data (JSON) response = b"" while len(response) < response_len: response += sock.recv(response_len - len(response)) return json.loads(response.decode('utf-8')) ``` ### Technical Analysis The parser trusts length fields supplied by the remote Minecraft server. `decode_varint()` does not enforce Minecraft's five-byte maximum for a 32-bit VarInt. A server can therefore continuously send bytes with the continuation bit set, causing the integer and shift count to grow while consuming CPU. More critically, `response_len` is used without any upper bound to control how much response data is read and retained. Repeated immutable byte-string concatenation can also result in excessive copying and poor memory performance. The response loop does not check whether `sock.recv()` returns `b""`. A clean connection closure before the declared body length is received consequently causes the loop to repeatedly append an empty byte string without making progress. Because reads from an already closed socket continue returning `b""`, the configured socket timeout does not necessarily termin ...[truncated 1412 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Reject VarInts longer than five bytes, as required for Minecraft 32-bit VarInts. - Define a conservative maximum packet and JSON response size, such as 1 MiB, and reject zero, negative, inconsistent, or oversized lengths. - Detect `recv()` returning `b""` and immediately raise a connection-closed exception. - Read data through a bounded helper that guarantees either exactly the requested number of bytes or a controlled failure. - Accumulate chunks in a list or `bytearray` and join once, rather than repeatedly concatenating immutable byte strings. - Validate the packet ID and ensure the declared packet length is consistent with the contained fields. - Close the socket through a context manager or `finally` block so malformed responses cannot leave resources open. Example hardening pattern: ```python MAX_VARINT_BYTES = 5 MAX_RESPONSE_SIZE = 1024 * 1024 def decode_varint(sock): value = 0 for index in range(MAX_VARINT_BYTES): raw = sock.recv(1) if not raw: raise IOError("Connection closed while reading VarInt") byte = raw[0] value |= (byte & 0x7F) << (7 * index) if not byte & 0x80: return value raise ValueError("VarInt exceeds five bytes") def recv_exact(sock, size): if size < 0 or size > MAX_RESPONSE_SIZE: raise ValueError("Invalid response length") chunks = [] remaining = size while remaining: chunk = sock.recv(min(remaining, 65536)) if not chunk: raise IOError("Connection closed before response completed") chunks.append(chunk) remaining -= len(chunk) return b"".join(chunks) ``` ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/minecraft-status.py:121
Finding
Terminal control-sequence injection through remote server metadata<![CDATA[ ## Vulnerability Details **File Location**: `scripts/minecraft-status.py`, lines 121-128 and 163-177 **Vulnerability Type**: Improper neutralization of terminal control characters **Risk Level**: Low ### Vulnerable Code ```python # Player count if 'players' in data: players = data['players'] result['players_online'] = players.get('online', 0) result['players_max'] = players.get('max', 0) if 'sample' in players and players['sample']: result['player_list'] = [p['name'] for p in players['sample']] # MOTD (message of the day) if 'description' in data: motd = data['description'] if isinstance(motd, dict): motd = motd.get('text', '') result['motd'] = motd ``` ```python if 'player_list' in status and status['player_list']: print(f" Online: {', '.join(status['player_list'][:5])}" + (f" ... +{len(status['player_list'])-5} more" if len(status['player_list']) > 5 else "")) if 'motd' in status and status['motd']: motd = status['motd'].strip() if motd: print(f" MOTD: {motd[:80]}{'...' if len(motd) > 80 else ''}") ``` ### Technical Analysis Player names and MOTD content are received from an untrusted remote server and printed directly to the user's terminal. Limiting the MOTD to 80 Python characters does not neutralize embedded ANSI escape sequences, carriage returns, backspaces, newlines, or other terminal control characters. A malicious server can use these characters to alter colors, move the cursor, clear previous output, overwrite status text, create deceptive terminal content, or corrupt logs that consume the command output. The precise effects depend on the terminal emulator and downstream log viewer. The same issue applies to sampled player names, which are joined and printed without normalization or type and character validation. ### Attack ...[truncated 1163 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Treat all server-provided strings as untrusted. - Remove ANSI CSI, OSC, and related escape sequences before displaying values. - Remove or visibly escape C0 and C1 control characters, including carriage return, newline, backspace, and escape. - Validate that player names and MOTD values are strings before formatting them. - Apply output-length limits after sanitization so escape-sequence removal cannot produce misleading truncation behavior. - For machine-readable or logging modes, serialize values with JSON escaping or `repr()` rather than printing raw text. - Consider separating human-readable output from a structured JSON output mode. A basic defensive helper could render control characters inert: ```python import re ANSI_ESCAPE = re.compile( r"\x1b(?:\[[0-?]*[ -/]*[@-~]|\][^\x07]*(?:\x07|\x1b\\))" ) def sanitize_terminal_text(value, limit=80): if not isinstance(value, str): value = str(value) value = ANSI_ESCAPE.sub("", value) value = "".join( ch if ch.isprintable() else f"\\x{ord(ch):02x}" for ch in value ) return value[:limit] ``` Use this helper on the MOTD and every player name before passing them to `print()`. ]]>
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

Static analysis

No suspicious patterns detected.