Interlace: The Thread Pool Every Pentester Wishes Their Tools Had Built-In
Hook
The average bug bounty hunter wastes 40+ hours per engagement waiting for single-threaded tools to scan hundreds of targets sequentially—time that could be compressed to minutes with proper parallelization.
Context
If you’ve ever run nmap against a list of 500 IP addresses, or used nikto to scan dozens of web servers, you’ve experienced the fundamental inefficiency of security tooling: most enumeration and reconnaissance tools are single-threaded. They process one target at a time, leaving your multi-core CPU mostly idle while you wait hours for scans to complete. The traditional solution has been to manually split target lists and run multiple terminal windows, use xargs with the -P flag, or write custom bash scripts with background jobs—all approaches that range from tedious to fragile.
Interlace emerged from the penetration testing community to solve this orchestration problem without requiring tool developers to rewrite their applications. Created by Michael Skelton (codingo), it acts as an intelligent wrapper that adds multi-threading capabilities to any command-line tool through variable substitution and thread pool management. The insight was elegant: instead of modifying tools to be thread-aware, create a meta-tool that handles target expansion, thread management, and execution flow while the underlying tools remain blissfully unaware they’re running in parallel.
Technical Insight
Interlace’s architecture centers on three core mechanisms: variable expansion, thread pool execution, and flow control primitives. At its simplest, you provide a command template with special variables and a target list, and Interlace expands every combination across a configurable thread pool.
The variable system supports _target_, _host_, _port_, _output_, and custom variables defined with _variable_. Here’s a basic example that runs nmap against a CIDR range using 5 threads:
interlace -t 192.168.1.0/24 -threads 5 -c "nmap -sV -oN _output_/_target_.nmap _target_"
Interlace parses the CIDR notation into individual IPs (192.168.1.1, 192.168.1.2, etc.), substitutes each into the command template, and executes them across the thread pool. The _output_ variable creates organized directory structures automatically. This basic pattern works with any tool—gobuster, nikto, testssl.sh, or custom scripts.
Where Interlace becomes genuinely powerful is its flow control system through “blockers” and “blocks.” A blocker is a synchronization point that prevents a thread from proceeding until all other threads reach the same blocker. A block is a group of sequential commands that must execute in order. Consider a realistic penetration testing workflow:
interlace -tL targets.txt -threads 10 -c "commands.txt"
Where commands.txt contains:
nmap -p- --open -oA _output_/_target_/portscan _target_
#BLOCKER
xsltproc _output_/_target_/portscan.xml -o _output_/_target_/ports.html
gobuster dir -u http://_target_ -w /usr/share/wordlists/common.txt -o _output_/_target_/gobuster.txt
nikto -h _target_ -output _output_/_target_/nikto.txt
The #BLOCKER directive ensures the port scan completes before follow-up tools run, but here’s the clever part: when target A hits the blocker, its thread doesn’t sit idle. Interlace starts working on target B in that thread. This maximizes CPU utilization while maintaining logical dependencies at the per-target level. Without the blocker, gobuster and nikto might run before nmap finishes, wasting time scanning ports that aren’t open yet.
The thread pool implementation uses Python’s concurrent.futures.ThreadPoolExecutor under the hood, with subprocess management for each command execution. Interlace monitors each subprocess’s stdout/stderr and handles timeouts at the command level through the -timeout flag. If a single target’s command hangs, only that thread is affected—other threads continue processing different targets.
For more complex scenarios, Interlace supports multi-variable expansion. You can scan multiple ports across multiple targets:
interlace -t 10.0.0.0/24 -p 80,443,8080,8443 -threads 20 \
-c "nikto -h _target_:_port_ -output _output_/_target_-_port_.txt"
This generates the cartesian product: every target combined with every port, creating hundreds of individual commands from a single template. For penetration testers working through OSCP labs or bug bounty programs with large scope, this pattern turns days of work into hours.
The proxy support (-proxy) is particularly useful for tools that need to route through Burp Suite or other intercepting proxies, and the exclusion file (-eL) lets you skip already-processed targets without manually editing input files. These aren’t flashy features, but they eliminate the small friction points that accumulate during real engagements.
Gotcha
Interlace’s greatest strength—being a wrapper around existing tools—is also its primary limitation. It has no understanding of what the commands it executes actually do or what constitutes success versus failure. If a command exits with a non-zero status code, Interlace logs it but continues execution. There’s no built-in retry logic, no circuit breaker pattern, no way to say “if this command fails, skip the dependent commands.” You’ll discover failed scans only by manually reviewing output files or parsing logs yourself.
The blocker mechanism, while powerful, can create subtle deadlocks if you’re not careful. If you have commands that themselves might hang indefinitely (not just run slowly), and you haven’t set appropriate timeouts, threads can stall at blockers waiting for a hung command to complete. Debugging complex command files with multiple blockers requires running with -v verbose mode and carefully watching execution order. There’s no dry-run mode to preview what commands will execute without actually running them—you’re testing in production. Additionally, the output directory structure Interlace creates is basic; if you need sophisticated result aggregation, correlation, or analysis, you’re building that layer yourself with post-processing scripts.
Verdict
Use if: You’re doing penetration testing, bug bounty reconnaissance, or security enumeration where you regularly run the same single-threaded tools against dozens or hundreds of targets. Interlace shines when you have existing tools you trust, large target lists, and workflows with command dependencies that benefit from blockers. It’s particularly valuable for OSCP students and professional pentesters who need to maximize efficiency during time-boxed engagements. Skip if: You’re working with tools that already have robust built-in threading (masscan, rustscan), you need sophisticated error handling and automatic retries, or you’re running simple one-off scans where the overhead of creating command templates isn’t justified. Also skip if your primary need is result aggregation and analysis rather than execution parallelization—Interlace orchestrates commands but doesn’t help you make sense of the output.