Back to Articles

Chaospy: A Python CLI for Mining Bug Bounty Program Intelligence from ProjectDiscovery's Chaos

[ View on GitHub ]

Chaospy: A Python CLI for Mining Bug Bounty Program Intelligence from ProjectDiscovery's Chaos

Hook

While most security researchers manually browse bug bounty platforms or write custom scrapers, a 176-star Python tool has been quietly automating subdomain reconnaissance across BugCrowd, HackerOne, and Intigriti with a single command.

Context

Bug bounty hunting and security reconnaissance require one critical starting point: knowing what assets are in scope. Before tools like ProjectDiscovery's Chaos emerged, researchers had to manually visit each bug bounty platform, compile program lists, and extract subdomain information from scope descriptions—a tedious process that wasted hours of productive testing time. ProjectDiscovery addressed this with Chaos, a centralized dataset aggregating bug bounty program information and associated subdomains.

However, even with Chaos available, researchers faced a choice: use the web interface for manual lookups or interact directly with the API using curl commands and custom scripts. Neither approach was ideal for security professionals who needed to quickly filter programs by specific criteria (platform, reward status, recent updates) and bulk-download subdomain lists for their reconnaissance pipelines. Chaospy bridges this gap by providing a focused, command-line interface that transforms Chaos API interactions into simple, filterable queries—letting hunters spend less time on data collection and more time finding vulnerabilities.

Technical Insight

Chaospy's architecture is deliberately minimal: it's a Python CLI wrapper that makes HTTP requests to ProjectDiscovery's Chaos API endpoints and handles response parsing. The tool doesn't maintain its own database or cache—it's a real-time query interface that transforms command-line arguments into API calls.

The core filtering mechanism maps CLI flags to API parameters. When you run a command like chaospy --platform bugcrowd --bounty true, the tool constructs a GET request to Chaos with query parameters filtering for BugCrowd programs that offer monetary rewards. Here's a conceptual example of how this filtering architecture likely works:

import requests
import argparse

def build_query_params(args):
    params = {}
    if args.platform:
        params['platform'] = args.platform
    if args.bounty:
        params['bounty'] = str(args.bounty).lower()
    if args.swag:
        params['swag'] = str(args.swag).lower()
    if args.new:
        params['filter'] = 'new'
    elif args.updated:
        params['filter'] = 'updated'
    return params

def fetch_programs(params):
    response = requests.get(
        'https://chaos.projectdiscovery.io/api/programs',
        params=params,
        headers={'Authorization': f'Bearer {API_KEY}'}
    )
    return response.json()

def download_subdomains(program_name):
    response = requests.get(
        f'https://chaos.projectdiscovery.io/api/subdomains/{program_name}'
    )
    with open(f'{program_name}_subdomains.txt', 'w') as f:
        for subdomain in response.json().get('subdomains', []):
            f.write(subdomain + '\n')

This design pattern—transforming CLI arguments into API parameters—keeps the codebase lean. There's no complex state management or local data storage. Each invocation is stateless, making the tool predictable and easy to integrate into shell scripts or CI/CD pipelines.

The real value proposition is in the filtering combinations. A bug bounty hunter preparing for a weekend testing session might run: chaospy --platform hackerone --bounty true --updated to find recently updated HackerOne programs with paid rewards. This single command replaces what would otherwise be multiple web page visits, manual filtering, and copy-pasting subdomain lists. The tool outputs program metadata and optionally downloads all associated subdomain files into the current directory.

Chaospy also likely implements batch operations. When you filter for multiple programs, it iterates through the results and makes individual subdomain download requests. This is where the tool's simplicity could become a bottleneck—without concurrent requests or rate limiting awareness, bulk downloads might be slow or trigger API throttling. A more sophisticated implementation would use Python's asyncio or concurrent.futures for parallel downloads:

import concurrent.futures

def download_all_programs(programs, max_workers=5):
    with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
        futures = {executor.submit(download_subdomains, p['name']): p for p in programs}
        for future in concurrent.futures.as_completed(futures):
            program = futures[future]
            try:
                future.result()
                print(f"Downloaded: {program['name']}")
            except Exception as e:
                print(f"Failed {program['name']}: {e}")

The tool's authentication handling is another key architectural decision. Chaos requires an API key for access, which Chaospy likely expects as an environment variable or configuration file. This approach keeps credentials out of command history but requires users to handle key management—a reasonable trade-off for security tools where users are already accustomed to managing API tokens.

One elegant aspect of Chaospy's design is its focus on output portability. Subdomain lists are saved as plain text files, one domain per line—the universal format expected by nearly every reconnaissance tool in the security ecosystem. This means Chaospy's output can be directly piped into tools like httpx, nuclei, or ffuf without transformation, making it a natural first step in automated reconnaissance workflows.

Gotcha

Chaospy's biggest limitation is its complete dependency on ProjectDiscovery's Chaos API. If the API changes endpoints, modifies response schemas, or implements breaking authentication changes, Chaospy becomes non-functional until updated. With 176 stars but unclear maintenance status, there's no guarantee updates will happen promptly. This is the classic risk of wrapper tools—they inherit all upstream fragility without adding resilience layers.

The tool also appears to lack sophisticated error handling for common API failure scenarios. What happens when you hit rate limits? Does it retry with exponential backoff, or does it fail immediately? If a program exists but has no subdomain data, does it skip gracefully or throw errors? The README doesn't address these operational realities, which means you'll discover them during production use—potentially in the middle of a timed bug bounty competition. Additionally, there's no mention of caching or incremental updates. If you're monitoring programs for new subdomains, you'll re-download entire lists every time, wasting bandwidth and API quota. A more robust tool would store checksums or timestamps to detect changes and only download deltas.

Verdict

Use if: You're a bug bounty hunter or penetration tester who regularly works with Chaos data and prefers command-line workflows over web interfaces. Chaospy excels at quick, filtered bulk downloads when you need to grab subdomain lists for multiple programs matching specific criteria (platform, bounty status, recent updates) without clicking through web pages. It's perfect for incorporating into shell scripts that kick off reconnaissance pipelines, especially if you're already comfortable managing API keys and handling basic Python tool maintenance. Skip if: You need reliability guarantees, comprehensive error handling, or features beyond basic subdomain downloads. If you're new to bug bounty hunting, start with the official Chaos web interface to understand the data model before jumping to CLI tools. Also skip this if you require active maintenance and support—with unclear update frequency, you might find yourself maintaining a fork when the Chaos API inevitably evolves. For production reconnaissance pipelines requiring high availability, consider more comprehensive tools like Subfinder or Amass that aggregate multiple data sources and won't break if a single API provider changes.

// ADD TO YOUR README
[![Featured on Starlog](https://starlog.is/api/badge/developer-tools/moaaz-0x-chaospy.svg)](https://starlog.is/api/badge-click/developer-tools/moaaz-0x-chaospy)