Turbo Intruder: PortSwigger's Custom HTTP Stack for Breaking Concurrency Limits
Hook
PortSwigger built an HTTP stack from scratch that beats asynchronous Go implementations—not through better algorithms, but by deliberately breaking the rules that make normal HTTP libraries safe.
Context
Most web application fuzzing tools hit a performance ceiling quickly. Burp Intruder, the industry standard fuzzer bundled with Burp Suite, works perfectly for typical penetration testing scenarios—a few thousand requests with variable payloads, clear result displays, and reliable HTTP handling. But when you need to send millions of requests to exploit a race condition, run multi-day brute force attacks without memory leaks, or intentionally send malformed HTTP that crashes standard parsers, Burp Intruder becomes the wrong tool.
The problem isn't just speed. Standard HTTP libraries—including Burp Suite's own networking layer—prioritize correctness, connection reuse, and RFC compliance. They buffer appropriately, handle edge cases gracefully, and prevent you from shooting yourself in the foot. These are features for normal engineering work, but they become constraints when you're trying to exploit timing windows measured in microseconds or test how servers handle protocol violations. Turbo Intruder exists because sometimes you need a tool that treats performance and protocol manipulation as first-class requirements, even at the cost of ease of use and safety.
Technical Insight
Turbo Intruder's core innovation is its custom HTTP engine written in Kotlin, designed specifically for high-throughput fuzzing scenarios that break conventional libraries. Unlike standard HTTP clients that abstract away connection management, Turbo Intruder gives you low-level control through Python scripting that manipulates requests at the socket level.
The architecture separates the high-performance Kotlin engine from Python-based attack logic. You write Python scripts that define how requests are generated, modified, and evaluated, while the engine handles the actual network operations. Here's a basic example that demonstrates the scripting approach:
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=5,
requestsPerConnection=100,
pipeline=False)
for word in open('/path/to/wordlist.txt'):
engine.queue(target.req, word.rstrip())
def handleResponse(req, interesting):
if req.status == 200 and len(req.response) > 1000:
table.add(req)
This script queues thousands of requests with different payloads, but the real power emerges when you need complex logic. The RequestEngine parameters expose low-level networking controls: concurrentConnections determines how many TCP connections stay open simultaneously, while requestsPerConnection controls HTTP connection reuse. Setting pipeline=False disables HTTP pipelining, but enabling it can dramatically improve throughput for servers that support it.
For race condition exploitation, Turbo Intruder includes single-packet attack capabilities that send multiple HTTP requests in a single TCP packet. This minimizes timing variance that normally exists between requests:
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=1,
engine=Engine.BURP2)
# Build requests that will be sent simultaneously
attack = target.req
engine.queue(attack, gate='race1')
engine.queue(attack, gate='race1')
engine.queue(attack, gate='race1')
# Release all requests in single packet
engine.openGate('race1')
The gate mechanism holds requests in memory until you explicitly release them with openGate(), then transmits them with minimal time delta. This technique is particularly effective against time-of-check-time-of-use (TOCTOU) vulnerabilities where you need to hit a narrow race window—perhaps a coupon code that should only work once, or a file upload race that allows privilege escalation.
The memory efficiency comes from streaming result processing rather than accumulating all responses. The handleResponse callback fires for each response as it arrives, letting you filter interesting results in real-time:
def handleResponse(req, interesting):
# Automatic diffing - mark responses that differ significantly
if interesting:
table.add(req)
# Custom filtering logic
if 'admin' in req.response and req.status != 404:
table.add(req)
# Extract and chain requests
if 'token=' in req.response:
token = re.search(r'token=([^&]+)', req.response).group(1)
next_req = target.req.replace('TOKEN', token)
engine.queue(next_req)
This streaming approach means Turbo Intruder maintains flat memory usage even during billion-request attacks that run for days. Burp Intruder, by contrast, accumulates all results in memory, making extended attacks impractical.
The custom HTTP stack also handles malformed requests that would fail in standard libraries. You can inject invalid headers, break Content-Length specifications, or send requests that violate HTTP specifications to test server parser robustness. The engine passes your requests through without validation, making it useful for protocol-level security research that deliberately probes edge cases in server implementations.
Gotcha
Turbo Intruder's documentation explicitly warns that it's significantly harder to use than Burp Intruder, and this isn't marketing modesty—it's a real barrier. There's no point-and-click payload configuration, no visual payload position markers, and no built-in payload processing rules. You must write Python scripts, understand connection pooling implications, and debug your own attack logic. PortSwigger provides example scripts in the repository, but adapting them to your specific scenario requires programming competence and understanding of HTTP at a lower level than most pentesters need.
The custom HTTP stack, while faster, is also less reliable than Burp Suite's battle-tested networking layer. You'll encounter edge cases where Turbo Intruder mishandles responses, fails to parse unusual server behaviors correctly, or produces results that need manual verification. The tool trades robustness for speed and flexibility—an acceptable tradeoff for advanced users running targeted attacks, but frustrating when you just need reliable results for a client report. Additionally, the single-host optimization means you can't efficiently scan multiple targets; trying to use Turbo Intruder for broad reconnaissance across many hosts will perform worse than simpler tools designed for that use case.
Verdict
Use if: You're exploiting race conditions that require microsecond-level timing control, running multi-million request attacks where standard tools exhaust memory, need to send intentionally malformed HTTP requests for protocol fuzzing, or require complex multi-step attack sequences with custom signing logic that built-in tools can't handle. It's also essential when you've already identified a vulnerability that requires brute-forcing millions of values and need something faster than conventional tools. Skip if: You're doing routine web application testing where Burp Intruder's ease of use outweighs speed concerns, aren't comfortable writing Python scripts to control attack logic, need to scan multiple hosts rather than intensively fuzzing a single target, or want a tool with extensive documentation and community support for troubleshooting. For most pentest engagements, Burp Intruder or ffuf will serve you better with less complexity.