How Holehe Generates Random User Agents for OSINT Requests

Holehe generates random User-Agent headers by selecting from a static collection of realistic Chrome browser signatures stored in holehe/localuseragent.py, using Python's random.choice() to vary the identifier for each outgoing HTTP request.

Holehe, the popular email-based OSINT (Open Source Intelligence) tool, implements User-Agent rotation to prevent detection and blocking by target services during account enumeration checks. Rather than generating synthetic browser identifiers algorithmically, holehe relies on a curated local database of authentic Chrome User-Agent strings. This approach ensures that each HTTP request appears to originate from a different legitimate browser instance, significantly reducing the tool's fingerprint.

User Agent Storage in holehe/localuseragent.py

Holehe maintains its collection of browser signatures in holehe/localuseragent.py, which serves as a centralized repository for HTTP header spoofing. This file contains a JSON-structured dictionary named ua that groups User-Agent strings by browser type, currently featuring an extensive list of authentic Chrome signatures.

The UA Dictionary Structure

The ua dictionary organizes strings hierarchically under browser categories. Accessing ua["browsers"]["chrome"] returns a list containing numerous realistic Chrome User-Agent strings collected from actual browser versions. This static approach eliminates external dependencies while ensuring the identifiers remain current and believable to web service defenses.

Random Selection Implementation

Individual modules throughout the holehe codebase import this dictionary and utilize Python's built-in random module to select entries unpredictably for each request.

The Selection Process

When preparing HTTP requests, modules execute a two-step process: first importing the ua dictionary from the local file, then applying random.choice() to select from the Chrome browser list. This implementation ensures that consecutive requests to the same target service carry different User-Agent headers, mimicking the behavior of disparate users.

from holehe.localuseragent import ua
import random

# Select a random Chrome User-Agent string

headers = {"User-Agent": random.choice(ua["browsers"]["chrome"])}

Practical Usage in Holehe Modules

The random User-Agent generation integrates directly into the request preparation logic found throughout holehe/modules/. Each module responsible for querying external services implements this pattern to maintain operational stealth.

Basic Implementation Example

The following pattern demonstrates how holehe modules incorporate the random User-Agent selection into their HTTP request workflow:

from holehe.localuseragent import ua
import random
import requests

def random_ua():
    """Return a random Chrome User-Agent string."""
    return random.choice(ua["browsers"]["chrome"])

# Use it when making a request

url = "https://example.com"
resp = requests.get(url, headers={"User-Agent": random_ua()})
print(resp.status_code)

Module-Level Integration

Inside specific OSINT modules, such as those located in holehe/modules/social_media/, the implementation remains consistent. The module imports the ua dictionary, constructs headers with a randomly selected Chrome signature, and passes these headers to the HTTP client:


# Inside a holehe module (simplified)

from holehe.localuseragent import ua
import random, requests

def check_account(email):
    headers = {"User-Agent": random.choice(ua["browsers"]["chrome"])}
    r = requests.post("https://service.com/api", data={"email": email}, headers=headers)
    return r.json()

This consistent implementation across the codebase ensures that every module benefits from the same level of request obfuscation without requiring redundant code or external API calls.

Summary

  • Holehe stores authentic browser signatures in holehe/localuseragent.py within a dictionary named ua, specifically under ua["browsers"]["chrome"].
  • The tool uses random.choice() to select a different Chrome User-Agent string for each HTTP request, preventing pattern detection.
  • Modules import the ua dictionary directly and apply the random selection during header construction.
  • This static-list approach provides reliability and performance advantages over dynamic generation or external User-Agent services.

Frequently Asked Questions

Where does holehe store its User-Agent strings?

Holehe stores its collection of User-Agent strings in holehe/localuseragent.py. This file contains a JSON-formatted dictionary named ua that organizes browser signatures by category, with an extensive list of Chrome User-Agent strings available under the chrome key.

Which browser does holehe mimic with its User-Agent rotation?

According to the source code in holehe/localuseragent.py, holehe currently focuses on Chrome browser signatures. The ua["browsers"]["chrome"] list contains numerous realistic Chrome User-Agent strings that the tool randomly selects from to mimic legitimate Chrome traffic.

How does holehe select a specific User-Agent for each request?

Holehe uses Python's random.choice() function to select entries from the pre-loaded list. Each time a module prepares an HTTP request, it calls random.choice(ua["browsers"]["chrome"]) to pick a different User-Agent string, ensuring variability between requests.

Why does holehe use a static list instead of generating User-Agent strings dynamically?

The static list approach in holehe/localuseragent.py ensures that all User-Agent strings are authentic browser signatures that have been verified to work with target services. This method eliminates the risk of generating invalid or malformed identifiers that could trigger security filters, while also avoiding external dependencies that might compromise operational security or availability.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →