Back to Articles

Rayder: A Minimalist Orchestrator for Bug Bounty Reconnaissance Workflows

[ View on GitHub ]

Rayder: A Minimalist Orchestrator for Bug Bounty Reconnaissance Workflows

Hook

Bug bounty hunters run the same chains of subdomain enumeration, DNS resolution, and HTTP probing tools dozens of times per day—yet most still cobble together fragile shell scripts or rely on memory to execute these workflows consistently.

Context

Security reconnaissance workflows are uniquely repetitive yet parameterized. A typical subdomain enumeration pipeline might chain together subfinder, dnsx, httpx, nuclei, and waymore—always in the same order, but against different target domains. The traditional approaches fall short: shell scripts become maintenance nightmares with hardcoded values scattered throughout; Makefiles weren't designed for parameterized execution; and full automation platforms like Ansible bring heavyweight abstractions that obscure what's really just sequential command execution.

Rayder emerged from this gap, built by security researcher Devansh Batham who recognized that bug bounty workflows needed something between bash scripts and enterprise orchestration. The tool targets the specific use case of running CLI security tools with variable targets, requiring minimal configuration overhead while providing just enough structure to make workflows reproducible and shareable. Written in Go, it leverages the language's concurrency primitives to add parallel execution capabilities that would require significant boilerplate in shell scripts.

Technical Insight

At its core, Rayder parses YAML workflow definitions that contain two primary elements: variables and modules. Each module represents a logical grouping of shell commands that execute sequentially, while modules themselves can run in parallel if configured. The variable substitution system uses double curly braces—familiar to anyone who's used templating engines—allowing values to be defined globally in the YAML or overridden via command-line arguments.

Here's a practical example of a Rayder workflow file for subdomain reconnaissance:

vars:
  domain: "{{domain}}"
  wordlist: "/opt/wordlists/subdomains.txt"
  output_dir: "./recon/{{domain}}"
  threads: "50"

modules:
  - name: "passive_enum"
    silent: false
    steps:
      - "mkdir -p {{output_dir}}"
      - "subfinder -d {{domain}} -o {{output_dir}}/subfinder.txt"
      - "assetfinder --subs-only {{domain}} | tee {{output_dir}}/assetfinder.txt"
      - "cat {{output_dir}}/subfinder.txt {{output_dir}}/assetfinder.txt | sort -u > {{output_dir}}/passive_subs.txt"
  
  - name: "dns_resolution"
    silent: false
    steps:
      - "dnsx -l {{output_dir}}/passive_subs.txt -o {{output_dir}}/resolved.txt -threads {{threads}}"
  
  - name: "http_probing"
    silent: false
    steps:
      - "httpx -l {{output_dir}}/resolved.txt -o {{output_dir}}/live_hosts.txt -threads {{threads}} -status-code -title"

You'd execute this with: rayder -w recon_workflow.yaml -var domain=example.com -var threads=100, overriding the default thread count at runtime. Rayder reads the YAML, performs variable interpolation, then executes each module's steps sequentially—but can run multiple modules simultaneously if you specify parallel execution.

The architecture is deliberately simple. Rayder doesn't maintain state between runs, doesn't provide result databases, and doesn't attempt to parse tool outputs. It's a pure orchestrator that shells out to whatever tools you specify. This design decision keeps the codebase minimal (under 1000 lines of Go) while making it completely agnostic to which security tools you're chaining together. The Go implementation allows it to compile to a single static binary with no runtime dependencies—critical for security researchers who often work from fresh VPS instances or Docker containers.

The parallel execution feature deserves attention because it's where Rayder adds real value over shell scripts. When you set parallel: true at the workflow level, Rayder spawns goroutines for each module, allowing independent reconnaissance tasks to run concurrently. For example, you might run passive subdomain enumeration, certificate transparency log scraping, and Google dorking in parallel since they don't depend on each other's outputs. This can cut workflow execution time from 30 minutes to 10 minutes for comprehensive reconnaissance.

However, the parallelism is coarse-grained. You can't specify that module C depends on modules A and B but can run in parallel with module D. It's either fully sequential or fully parallel at the workflow level, which means you often need to split complex workflows into multiple YAML files—one for parallel-safe modules, another for the sequential dependency chain.

The variable system supports a useful pattern for multi-target workflows. You can maintain a master workflow YAML with placeholder variables, then feed different targets via command-line arguments or even wrap Rayder calls in a simple loop:

while read domain; do
  rayder -w recon.yaml -var domain="$domain" -var output_dir="./results/$domain"
done < targets.txt

This approach lets security teams standardize their reconnaissance methodology across researchers—everyone runs the same YAML workflow, ensuring consistent coverage and reducing the "but it works on my machine" problem when sharing reconnaissance findings.

Gotcha

Rayder's simplicity becomes a limitation when you need error handling sophistication. If subfinder crashes midway through a module, Rayder doesn't provide built-in retry logic, and subsequent commands in that module continue executing with potentially incomplete input. There's no conditional execution—you can't say "only run httpx if dnsx found resolved domains." You'll find yourself wrapping commands in shell conditionals ([ -s file.txt ] && httpx ...) which defeats some of the declarative YAML clarity.

The lack of inter-module dependencies means you can't build a proper directed acyclic graph (DAG) of tasks. Real-world reconnaissance workflows often have complex dependencies: DNS resolution must wait for subdomain enumeration, but port scanning and screenshot capture can happen in parallel once you have live hosts. Rayder forces you to either run everything sequentially (slow) or manually split workflows into multiple files that you chain together with shell scripts (defeating the purpose). Tools like Taskfile and Make handle this with explicit dependency declarations, making them more suitable for workflows where task interdependencies are complex.

Verdict

Use if: You're a bug bounty hunter or penetration tester who runs similar chains of CLI reconnaissance tools repeatedly with different targets, values declarative configuration over shell script complexity, and your workflows have simple sequential or fully-parallel execution patterns. Rayder excels at making security workflows reproducible and shareable across teams without requiring heavy tooling knowledge. Skip if: Your workflows require conditional logic based on previous command outputs, need sophisticated error handling and retry mechanisms, have complex task dependency graphs where some tasks depend on others while different tasks can run in parallel, or you're working outside the security domain where general-purpose task runners like Taskfile provide better abstraction. Also skip if you're comfortable with shell scripting and GNU parallel—you probably don't need the YAML layer.