Fuzzing Input Generator
Overview
Generate comprehensive fuzz testing inputs to uncover bugs, crashes, and security vulnerabilities by systematically testing functions with edge cases, invalid inputs, and randomized data.
Workflow
1. Analyze the Target Function
Understand what needs to be fuzzed:
Identify input types:
- Strings (text, paths, URLs, etc.)
- Numbers (integers, floats)
- Booleans
- Collections (lists, dicts, sets)
- Structured data (JSON, XML)
- Files or binary data
- Combinations of above
Understand expected behavior:
- What are valid inputs?
- What should happen with invalid inputs?
- Are there documented constraints?
- What error handling exists?
Extract function signature:
def process_user_input(name: str, age: int, email: str) -> dict:
"""Process user registration data."""
# Analyze: expects string, int, string
# Constraints: name non-empty, age > 0, email format
2. Select Fuzzing Strategy
Choose appropriate fuzzing approaches:
Edge Case Fuzzing
Test boundary conditions and special values:
- Empty inputs
- Very large inputs
- Minimum/maximum values
- Zero, negative numbers
- Special characters
- Null/None values
Invalid Input Fuzzing
Test with malformed or incorrect data:
- Wrong types
- Invalid formats
- Out-of-range values
- Malformed structures
- Encoding issues
Random Valid Fuzzing
Generate random but technically valid inputs:
- Random strings of various lengths
- Random numbers in valid ranges
- Random but well-formed structures
- Valid but unusual combinations
Security Fuzzing
Test for vulnerabilities:
- Injection attacks (SQL, command, XSS)
- Path traversal
- Buffer overflows
- Format string attacks
- Unicode exploits
3. Generate Fuzz Test Code
Create Python test functions with fuzzing inputs.
Basic Template
import pytest
import random
import string
def fuzz_<function_name>():
"""Fuzz test for <function_name>."""
# Edge cases
edge_cases = [
# Add specific edge case inputs
]
# Invalid inputs
invalid_inputs = [
# Add invalid inputs
]
# Random valid inputs
def generate_random_valid():
# Generate random but valid input
pass
# Test edge cases
for input_data in edge_cases:
try:
result = function_under_test(input_data)
# Check result or at least that it doesn't crash
except Exception as e:
# Document or assert expected exceptions
pass
# Test invalid inputs
for input_data in invalid_inputs:
# Similar testing pattern
pass
# Test random inputs
for _ in range(100):
random_input = generate_random_valid()
# Test with random input
4. Generate Input Categories
Create comprehensive input sets for each parameter type. See fuzzing-patterns.md for extensive patterns.
String Inputs
def generate_string_fuzz_inputs():
"""Generate fuzz inputs for string parameters."""
return [
# Empty and whitespace
"",
" ",
" ",
"\t",
"\n",
"\r\n",
# Length edge cases
"a", # Single char
"a" * 100, # Medium
"a" * 10000, # Long
"a" * 1000000, # Very long
# Special characters
"!@#$%^&*()",
"'",
"\"",
"\\",
"<script>alert(1)</script>",
# Unicode
"🔥",
"你好",
"مرحبا",
# Injection patterns
"'; DROP TABLE users--",
"../../../etc/passwd",
"${var}",
# Format strings
"%s%s%s",
"{0}{1}{2}",
# Null bytes
"\x00",
"test\x00test",
]
Number Inputs
def generate_number_fuzz_inputs():
"""Generate fuzz inputs for numeric parameters."""
return [
# Integers
0,
1,
-1,
2**31 - 1, # Max 32-bit int
-2**31, # Min 32-bit int
2**63 - 1, # Max 64-bit int
-2**63, # Min 64-bit int
# Floats
0.0,
-0.0,
float('inf'),
float('-inf'),
float('nan'),
1e308, # Near max float
1e-308, # Near min float
0.1 + 0.2, # Precision issue
# Edge cases
None,
"123", # String number
"not a number",
[],
{},
]
Structured Data Inputs
def generate_json_fuzz_inputs():
"""Generate fuzz inputs for JSON/dict parameters."""
return [
# Empty
{},
[],
None,
# Type confusion
{"number": "123"},
{"bool": "true"},
{"array": "[]"},
# Deep nesting
{"a": {"b": {"c": {"d": {"e": "deep"}}}}},
[[[[["nested"]]]]],
# Large structures
{f"key{i}": i for i in range(1000)},
[i for i in range(10000)],
# Special keys
{"": "empty key"},
{"key with spaces": "value"},
{"key.with.dots": "value"},
# Mixed types
{"str": "text", "num": 123, "bool": True, "null": None, "arr": [1, 2]},
# Invalid JSON strings
"{invalid}",
'{"unclosed": ',
'{"key": undefined}',
]
5. Write Complete Test Functions
Generate executable test code:
Example 1: String Processing Function
import pytest
import random
import string
def test_fuzz_process_username():
"""Fuzz test for username processing."""
def process_username(username: str) -> str:
"""Function under test."""
if not username:
raise ValueError("Username cannot be empty")
if len(username) > 50:
raise ValueError("Username too long")
return username.strip().lower()
# Edge case inputs
edge_cases = [
"", # Empty
" ", # Space only
"a", # Single char
"A" * 50, # Max length
"A" * 51, # Over max
" user ", # Surrounding spaces
"User123", # Mixed case
"user@name", # Special chars
"user\nname", # Newline
"🔥user", # Unicode
"\x00user", # Null byte
]
# Invalid inputs
invalid_inputs = [
None,
123,
[],
{},
True,
]
# Test edge cases
for username in edge_cases:
try:
result = process_username(username)
assert isinstance(result, str)
assert len(result) <= 50
except ValueError as e:
# Expected for empty or too long
assert "empty" in str(e) or "too long" in str(e)
except Exception as e:
pytest.fail(f"Unexpected exception for '{username}': {e}")
# Test invalid types
for username in invalid_inputs:
try:
result = process_username(username)
pytest.fail(f"Should reject invalid type: {type(username)}")
except (TypeError, AttributeError):
pass # Expected
# Random fuzzing
for _ in range(100):
length = random.randint(0, 100)
chars = string.ascii_letters + string.digits + " !@#$"
random_username = ''.join(random.choice(chars) for _ in range(length))
try:
result = process_username(random_username)
# Verify properties that should always hold
if random_username.strip():
assert result.islower()
assert len(result) <= 50
except ValueError:
# Expected for empty or too long
pass