Back to skill

Security audit

D&D 5e Toolkit

Security checks for vulnerabilities and agentic risk

Overview

This D&D toolkit is purpose-aligned and disclosed, with a local resource-exhaustion bug to consider but no evidence of hidden access, persistence, credential use, or destructive behavior.

Reasonable to install for D&D utility use. Be aware that spell, monster, character, and encounter features make outbound requests to the public D&D 5e API, and avoid requesting extremely large dice rolls until input limits are added.

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

T09 · Insecure Skill Coding Practices

Warning
Location
dnd.py:33
Finding
Unbounded Dice Parameters Allow Resource Exhaustion## Vulnerability Details **File Location**: `dnd.py`, lines 33-45 **Vulnerability Type**: Uncontrolled resource consumption **Risk Level**: Medium **Vulnerable Code:** ```python # Parse XdY+Z or XdY-Z or XdY import re match = re.match(r'(\d+)d(\d+)([+-]\d+)?', dice_str.lower()) if not match: print(f"Invalid dice format: {dice_str}. Use format like '2d6', '1d20+5', '3d8-2'", file=sys.stderr) sys.exit(1) num_dice = int(match.group(1)) die_size = int(match.group(2)) modifier = int(match.group(3) or 0) rolls = [random.randint(1, die_size) for _ in range(num_dice)] ``` ### Technical Analysis The dice count is obtained directly from a user-controlled command-line argument without an upper bound. It is then passed to `range()` and used to determine the size of an eagerly allocated list. Consequently, an attacker can request an extremely large number of dice. The application will repeatedly invoke `random.randint()` and retain every generated value in memory. The resulting CPU and memory consumption can stall the process, trigger swapping, or cause termination by the operating system's out-of-memory mechanism. The dice size is also not bounded, and the expression is parsed with `re.match()` rather than requiring the entire input to conform to the expected format. These validation weaknesses should be addressed as part of the same hardening effort. ### Attack Path 1. An attacker supplies an excessively large dice expression through a prompt or direct command, such as: ```bash python3 dnd.py roll 999999999d6 ``` 2. The regular expression accepts the expression. 3. `num_dice` is set to the attacker-controlled value. 4. The list comprehension attempts to generate and retain hundreds of millions of random integers. 5. The process consumes excessive CPU and memory, potentially making the Agent or host unavailable. ### Impact Assessment Successful exploitation can cause denial of servic ...[truncated 266 chars]
Remediation
## Remediation Suggestions - Parse the complete expression using `re.fullmatch()` instead of `re.match()`. - Enforce conservative maximum values for the number of dice, die size, and modifier before performing any computation. - Reject zero or negative-equivalent values and return a controlled validation error. - Avoid allocating large roll lists when only a total is needed, or impose a strict output-size limit. - Add automated tests for malformed, zero-sized, and oversized inputs. Example hardening: ```python match = re.fullmatch(r'(\d+)d(\d+)([+-]\d+)?', dice_str.lower()) if not match: raise ValueError("Invalid dice expression") num_dice = int(match.group(1)) die_size = int(match.group(2)) modifier = int(match.group(3) or 0) if not 1 <= num_dice <= 1000: raise ValueError("Dice count must be between 1 and 1000") if not 2 <= die_size <= 10000: raise ValueError("Die size must be between 2 and 10000") if abs(modifier) > 1_000_000: raise ValueError("Modifier is too large") ```
Vulnerability Patterns
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • 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
Findings (1)

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill documentation indicates it uses an external API, which implies network access, but the manifest does not declare any tool scope such as permissions or allowed-tools. This creates an authorization and transparency gap: a host agent may grant broader-than-necessary capabilities or users may be unaware that invoking the skill can trigger outbound requests.

Static analysis

No suspicious patterns detected.