> your AI agent picks dependencies from memory; give it dated facts — try starlog.dev ↗ vet your agent's deps ↗ vibe-coding is fine. vibe-importing isn’t. — try starlog.dev ↗ vibe-importing isn’t fine ↗ your agent has never seen your private packages — try starlog.dev ↗ facts for private packages ↗ a linter for the dependencies your AI agent picks — try starlog.dev ↗ a linter for agent deps ↗

Back to Articles

dirsearch: How Smart Wordlist Handling Makes or Breaks Web Path Discovery

[ View on GitHub ]

dirsearch: How Smart Wordlist Handling Makes or Breaks Web Path Discovery

Hook

Most security scanners waste 80% of their HTTP requests on paths that will never exist. The difference between finding a /backup.zip file and missing it entirely often comes down to how your tool handles three characters: .zip.

Context

Web applications expose countless entry points—admin panels, backup files, configuration endpoints, API routes—that developers never intended to be public. Traditional security testing relies on manual exploration or simple spidering, but both approaches miss hidden paths that aren't linked from the visible application. This gap created an entire category of brute-force directory enumeration tools.

Early tools like DirBuster simply concatenated wordlists with target URLs, firing requests until something returned a 200 status code. This worked, but it was wasteful. If you wanted to find both /admin.php and /admin.bak, you needed separate wordlist entries for each extension combination. As web stacks diversified—mixing PHP, Python, Node.js, static files, and backups—wordlists exploded in size, and scan times became impractical. dirsearch emerged in 2014 with a different approach: intelligent wordlist manipulation that separates paths from extensions, dramatically reducing redundancy while increasing coverage.

Technical Insight

Concurrent Execution

Extension Modes

target URL, wordlist, extensions

parse %EXT% templates

generate path variants

distribute paths

HTTP requests

responses + status codes

filter by status/size

save results

discovered directories

new base paths

pause/resume state

CLI Input Handler

Wordlist Engine

Extension Processor

Path Queue

Multi-threaded Request Engine

Target Web Server

Response Filter

Reporting Module

Output Formats

Recursive Scanner

Session Manager

System architecture — auto-generated

The core architectural decision in dirsearch revolves around its wordlist engine. Instead of treating each line as a static string, it parses wordlists for the %EXT% keyword, which acts as a template variable for extension substitution. This seemingly simple feature fundamentally changes how path discovery works.

Consider a wordlist entry like admin%EXT%. When you run dirsearch with -e php,bak,txt, the engine doesn't just test /admin.php, /admin.bak, and /admin.txt. It also tests /admin with no extension, because web servers often serve files without extensions or use content negotiation. Here's what that looks like in practice:

# Traditional approach - requires separate wordlist entries
dirsearch -u https://target.com -w wordlist.txt
# wordlist.txt must contain:
# admin.php
# admin.bak
# admin.txt
# admin

# dirsearch approach - one entry generates all variants
dirsearch -u https://target.com -w wordlist.txt -e php,bak,txt
# wordlist.txt contains:
# admin%EXT%
# Automatically tests: /admin, /admin.php, /admin.bak, /admin.txt

The engine takes this further with two extension modes: force-extensions (-f) and overwrite-extensions (-O). Force-extensions adds your specified extensions to every path, regardless of whether it already has one. This catches scenarios where developers append extensions to already-named files, like config.json.bak. Overwrite-extensions replaces any existing extension with your list, useful when you know the technology stack but want to find variants.

The multi-threaded request engine uses a producer-consumer pattern. A generator thread reads the wordlist and produces URL variants based on extension rules, feeding them into a queue. Worker threads (default 30, configurable up to 100+) consume from this queue, sending HTTP requests and handling responses. Each worker maintains its own HTTP session with connection pooling, reducing the overhead of TCP handshakes for sequential requests to the same host.

Filtering is where dirsearch differentiates itself from simpler scanners. Wildcard detection runs automatically at scan start, sending requests to non-existent paths to fingerprint the server's 404 behavior. Many applications return 200 status codes with custom error pages instead of proper 404s. dirsearch detects this by analyzing response sizes and contents, then filters out matching responses during the actual scan:

# Example of exclusion chaining
dirsearch -u https://target.com \
  -e php,html,js \
  -x 403,404,500 \
  --exclude-sizes 1234,5678 \
  --exclude-texts "not found" \
  --exclude-regex "error[0-9]+" \
  --skip-on-status 429

This command excludes responses by status code, content size, body text, regex patterns, and even pauses scanning when rate limiting (429) is detected. Each filter type operates as a middleware layer in the response processing pipeline, applied before results reach the output module.

The session management system serializes scan state to disk, storing the current position in the wordlist, accumulated results, and configuration. When you Ctrl+C a scan, dirsearch writes a session file that captures everything needed to resume. This is critical for scans that take hours or days:

# Start a scan (interrupts with Ctrl+C)
dirsearch -u https://target.com -e php -w huge-wordlist.txt

# Resume from exact position
dirsearch --session-file session.txt

The recursive mode deserves special attention. When dirsearch finds a directory (indicated by 301/302 redirects or configured status codes), it can automatically queue that directory for scanning with the same wordlist. This creates a breadth-first traversal of the discovered directory tree, bounded by configurable depth limits to prevent infinite recursion on sites with dynamic routing.

Gotcha

The biggest limitation is one dirsearch shares with all brute-force tools: you're only as good as your wordlist. If your wordlist doesn't contain api-v2 and the target uses that exact naming convention, you'll never find those endpoints. The extension system helps with coverage, but path selection remains fundamentally a guessing game. You need domain knowledge—common CMS paths, framework conventions, backup patterns—encoded into your wordlists.

Performance becomes problematic at scale. A 100,000-line wordlist with 5 extensions generates 500,000+ HTTP requests. At 30 threads, that's still thousands of seconds of wall time, and aggressive threading triggers rate limiting or WAF blocks. The --delay and --max-rate options help, but they create a fundamental tension: scan faster and get blocked, or scan slower and wait hours for results. There's no intelligence here—dirsearch doesn't learn from responses to optimize subsequent requests. It just marches through the wordlist mechanically.

The tool is also protocol-bound. It only discovers paths by requesting them via HTTP/HTTPS. It won't parse JavaScript files to find API endpoints, won't analyze HTML forms for parameter names, and won't read sitemaps or robots.txt to seed the wordlist. You need to chain dirsearch with other tools (like JSParser or LinkFinder) to get comprehensive coverage. This isn't a flaw per se—it's a deliberate focus on doing one thing well—but it means dirsearch is always part of a toolkit, never a standalone solution.

Verdict

Use dirsearch if you need mature, reliable path enumeration with fine-grained control over extensions and filtering. It excels in bug bounty scenarios where you're testing diverse targets with different tech stacks, thanks to its wordlist flexibility and session management for long scans. The standalone binaries make it trivial to deploy on VPS instances without dependency hell. It's the right choice when you need proven tooling that won't surprise you mid-engagement. Skip if you're scanning single-page applications where paths are dynamically generated (React Router, Vue Router), or if you need passive discovery methods that don't generate thousands of requests. Also skip if raw speed is your priority over features—gobuster or feroxbuster will finish faster on straightforward scans. dirsearch trades some performance for operational flexibility, which matters more in real-world testing than benchmarks suggest.