How Holehe Handles User Agents and Avoids Detection
Holehe mitigates detection by rotating realistic browser User-Agent headers on every HTTP request through a centralized JSON dictionary and per-module random selection.
Holehe is an open-source email OSINT (Open Source Intelligence) framework by megadose designed to enumerate account registrations across hundreds of online services. To avoid triggering rate limits or bot detection mechanisms during bulk scanning operations, the tool implements a dynamic user agent management system. This analysis examines how Holehe handles user agents and avoids detection through its distributed header injection architecture.
Centralized User-Agent Store
The localuseragent.py Module
The foundation of Holehe's evasion strategy resides in holehe/localuseragent.py, which defines a JSON-encoded dictionary named ua. This structure contains realistic browser strings for Chrome, Firefox, Safari, and iOS platforms that mimic genuine user traffic. The module loads these strings at runtime using json.loads(), making them available as a shared resource across the entire codebase.
The ua dictionary is organized by browser categories, allowing modules to select context-appropriate signatures depending on the target service's expected audience.
Per-Request Randomization Strategy
Individual service modules import the ua dictionary and invoke random.choice() to select a new user agent for every distinct HTTP request. For example, in holehe/modules/transport/blablacar.py, the request headers are constructed as follows:
from holehe.localuseragent import ua
import random
headers = {'User-Agent': random.choice(ua["browsers"]["firefox"])}
This pattern appears in over 100 locations throughout the holehe/modules/ directory, ensuring no two consecutive requests share the same browser fingerprint. By distributing the selection logic across individual modules rather than using a central interceptor, Holehe ensures that even parallel requests to different services carry unique signatures.
Privacy-Enhancing Headers
Beyond user agent rotation, certain modules append additional privacy signals to mimic legitimate browser behavior. The DNT: 1 (Do Not Track) header appears in medical and privacy-sensitive modules such as Sevencups, signaling settings consistent with genuine privacy-conscious users. These supplementary headers complement the user agent rotation by presenting a holistic browser profile that matches expected human traffic patterns.
HTTP Client Architecture
Shared AsyncClient with Variable Headers
Holehe leverages httpx.AsyncClient for asynchronous HTTP requests, instantiated centrally in holehe/core.py. While the client instance persists across requests to optimize connection pooling and TCP reuse, each module generates a fresh headers dictionary containing a randomly selected user agent before calling the client.
This architecture balances performance with evasion: the underlying TCP connection remains stable to reduce latency, while each HTTP request carries distinct headers that prevent pattern recognition by web application firewalls.
Practical Implementation Example
The following pattern demonstrates how Holehe modules combine these techniques in practice:
from holehe.localuseragent import ua
import random
import httpx
async def check_service(email: str, client: httpx.AsyncClient):
# Randomize user agent for this specific request
headers = {
"User-Agent": random.choice(ua["browsers"]["chrome"]),
"DNT": "1" # Privacy signal
}
# Shared client ensures connection reuse
response = await client.get(
"https://target-service.com/api/check",
headers=headers
)
return response.json()
This implementation ensures that the shared httpx.AsyncClient maintains persistent connections while each request presents a unique browser identity.
Summary
- Centralized storage: Realistic browser strings are maintained in
holehe/localuseragent.pyas a JSON dictionary loaded at runtime. - Randomized selection: Over 100 modules use
random.choice(ua["browsers"][...])to inject a uniqueUser-Agentheader per request. - Client efficiency: A shared
httpx.AsyncClientinholehe/core.pypersists connections while headers vary per request. - Additional obfuscation: Optional DNT: 1 headers in certain modules mimic privacy-conscious user behavior.
Frequently Asked Questions
How does Holehe select user agents for each request?
Holehe modules import the ua dictionary from holehe/localuseragent.py and call random.choice() on browser-specific sublists (e.g., ua["browsers"]["firefox"]) to select a string immediately before making an HTTP request.
Does Holehe reuse the same user agent across multiple sites?
No. Because each of the 100+ modules independently selects a random user agent when constructing request headers, consecutive requests to different services carry distinct browser signatures.
What additional headers does Holehe use to avoid detection?
Certain modules include the DNT: 1 header to signal "Do Not Track" preferences, aligning the request profile with privacy-conscious human users and reducing bot detection risk.
Where does Holehe store its list of user agents?
The user agent strings are stored as a JSON-encoded dictionary in holehe/localuseragent.py, which is imported and accessed by service modules across the holehe/modules/ directory tree.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →