API Fuzz Testing — Malformed Inputs, Boundary Values, and Crash Detection
In this tutorial, you will learn about API Fuzz Testing. We cover key concepts, practical examples, and best practices to help you master this topic.
API fuzz testing sends unexpected, malformed, or boundary inputs to endpoints to detect crashes, hangs, memory leaks, and security vulnerabilities that normal testing misses.
What You'll Learn
- How to generate fuzzed inputs for API endpoints
- Testing type confusion, boundary values, and injection payloads
- Using Boofuzz and custom fuzzing scripts
Why It Matters
APIs that handle normal requests perfectly may crash on malformed input. Fuzz testing uncovers edge cases that lead to 500 errors, infinite loops, or security breaches before attackers find them.
Real-World Use
A file upload API crashes when sent a 2GB JSON payload. Fuzz testing reveals that the parser reads the entire body into memory without size limits. The team adds a 10MB request body limit, preventing a denial-of-service vector.
flowchart LR
A[Fuzzer] --> B[Generate Payload]
B --> C[Send to API]
C --> D[Monitor Response]
D --> E{Error/Crash?}
E -->|No| F[Next Payload]
E -->|Yes| G[Record Issue]
G --> H[Fix and Verify]
Fuzzing JSON Endpoints
Send type-confused and malformed JSON payloads.
import requests
import json
payloads = [
"not json at all",
"null",
"[]",
"{}",
'{"id": "string_instead_of_int"}',
'{"id": null}',
'{"id": [1,2,3]}',
'{"id": {"nested": "object"}}',
'{"name": "a" * 100000}',
'{"email": "<script>alert(1)</script>"}',
]
url = "https://api.example.com/users"
for i, body in enumerate(payloads):
try:
headers = {"Content-Type": "application/json"}
resp = requests.post(url, data=body, headers=headers, timeout=5)
status = resp.status_code
if status >= 500:
print(f"Payload {i}: server error {status}")
elif status >= 400:
print(f"Payload {i}: rejected with {status} (good)")
else:
print(f"Payload {i}: accepted with {status} (check impact)")
except requests.Timeout:
print(f"Payload {i}: timed out (potential hang)")
except Exception as e:
print(f"Payload {i}: exception {e}")
Expected output: All malformed payloads should return 400-level errors.
Boundary Value Testing
Test edge cases on integer and string parameters.
boundary_payloads = [
{"id": -1},
{"id": 0},
{"id": 2147483647},
{"id": 2147483648},
{"id": 99999999999999999999999},
{"name": ""},
{"name": "a"},
{"name": "a" * 256},
{"name": "a" * 65536},
{"price": -0.01},
{"price": 0},
{"price": 999999999.99},
]
for payload in boundary_payloads:
resp = requests.post(url, json=payload, timeout=5)
if resp.status_code == 500:
print(f"Server error on: {payload}")
elif resp.status_code == 413:
print(f"Payload too large: {payload}")
Expected output: API should handle boundary values with 400 or 422 status codes.
Parameter Injection Testing
Test for injection vulnerabilities in query parameters.
injection_payloads = [
"/products?category=electronics' OR '1'='1",
"/products?category=electronics; DROP TABLE products;",
"/products?category[$ne]=nonexistent",
"/products?limit=-1",
"/products?limit=0",
"/products?limit=9999999999",
"/products?offset=-1",
"/products?sort=invalid_field",
"/products?sort=",
"/products?include[]=password&include[]=ssn",
]
base = "https://api.example.com"
for path in injection_payloads:
resp = requests.get(f"{base}{path}", timeout=5)
if resp.status_code == 500:
print(f"Server error on: {path}")
elif resp.status_code == 200 and len(resp.json()) > 0:
print(f"Possible injection on: {path}")
Expected output: Injection attempts should be rejected or return empty results.
Common Mistakes
| Mistake | Why It's Wrong |
|---|---|
| Only fuzzing happy path parameters | Attackers target edge cases, not normal inputs |
| Ignoring HTTP headers | Malformed headers can trigger parser bugs |
| Not testing binary payloads | Binary content may crash text-based parsers |
| Stopping at first error | Multiple vulnerabilities may exist simultaneously |
| Forgetting to fuzz multipart uploads | File upload endpoints are common attack vectors |
| Skipping auth endpoints | Login/register endpoints handle sensitive data |
| Not monitoring server resources | Crashes may cause memory leaks without visible errors |
Practice Questions
- What is API fuzz testing? A: Sending unexpected, malformed, or boundary inputs to APIs to discover crashes and vulnerabilities.
- What is a type confusion vulnerability? A: When the API expects an integer but receives a string, object, or array, causing unexpected behavior.
- How do you fuzz a GraphQL API? A: Send malformed query strings, invalid variables, and deeply nested queries to test schema validation.
- What is a boundary value? A: An input at the edge of the acceptable range, like 0, -1, or the maximum integer value.
- What tools support API fuzzing? A: Boofuzz, Peach Fuzzer, Burp Suite Intruder, and custom Python scripts with random payload generators.
Challenge
Build a fuzz testing script that: generates 100 random JSON payloads with type-confused fields, sends them to POST /api/users, reports any 5xx responses or timeouts, checks that the server doesn't crash after all requests, and tests boundary values for all numeric and string fields in the API schema.
FAQ
What is the difference between fuzz testing and penetration testing?
Fuzz testing automates malformed input generation; penetration testing manually probes for logic vulnerabilities.
How do you fuzz a SOAP API?
Send malformed XML payloads with invalid namespaces, oversized elements, and entity expansion attacks.
What is a crash in fuzz testing?
Any response where the server returns 5xx, hangs indefinitely, or the process terminates unexpectedly.
How do you detect memory leaks during fuzzing?
Monitor the server's memory usage during fuzz testing. Steady increases indicate a leak.
What is a dictionary-based fuzzer?
A fuzzer that uses a predefined list of known bad inputs (like SQL Injection strings) rather than random data.
How do you handle Rate Limiting during fuzzing?
Spread requests across multiple IPs or slow the fuzzing rate to match the API's rate limit.
Should fuzz testing run in production?
No. Fuzz testing can crash services or corrupt data. Run it in a staging environment.
Mini Project
Create a fuzzing suite for a user management API. Test: POST /users with type-confused fields (string for int, array for string, null for required fields), GET /users with boundary values on limit and offset parameters, POST /users/login with SQL injection and NoSQL injection payloads, and DELETE /users/{id} with non-existent, negative, and string IDs. Report all 5xx errors and potential injection vulnerabilities.
What's Next
Now learn API Regression Testing strategies to ensure new changes don't break existing functionality.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro