T09 · Insecure Skill Coding Practices
- Location
dnd.py:33- Finding
Unbounded Dice Parameters Allow Resource Exhaustion
- Content
View full analysis
Vulnerability Details
File Location:
dnd.py, lines 33-45
Vulnerability Type: Uncontrolled resource consumption
Risk Level: MediumVulnerable 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
- An attacker supplies an excessively large dice expression through a prompt or direct command, such as:
bash python3 dnd.py roll 999999999d6 - The regular expression accepts the expression.
num_diceis set to the attacker-controlled value.- The list comprehension attempts to generate and retain hundreds of millions of random integers.
- 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]
- An attacker supplies an excessively large dice expression through a prompt or direct command, such as:
- Remediation
View remediation
Remediation Suggestions
- Parse the complete expression using
re.fullmatch()instead ofre.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")- Parse the complete expression using
