How Holehe Handles User-Agent Rotation: Implementation Guide
Holehe rotates user-agent strings by maintaining a centralized JSON dictionary of browser fingerprints in holehe/localuseragent.py and randomly selecting entries via random.choice() for every HTTP request.
Holehe, an open-source OSINT tool developed by megadose, checks email addresses against hundreds of services to uncover associated accounts. To avoid detection and rate-limiting during these reconnaissance operations, Holehe implements a data-driven user-agent rotation strategy that presents a different browser fingerprint to each target service.
Where User-Agent Strings Are Stored in Holehe
The foundation of Holehe’s rotation system resides in holehe/localuseragent.py. This file contains a JSON-encoded dictionary loaded at import time into a variable named ua:
# holehe/localuseragent.py
ua = json.loads('''{ … }''')
The dictionary organizes realistic user-agent strings by browser type, including Chrome, Firefox, and Safari. By centralizing this data, Holehe ensures that all service modules draw from the same curated pool of fingerprints, maintaining consistency across the codebase while allowing for diverse client impersonation.
How the Rotation Mechanism Works
The user-agent rotation follows a purely data-driven pipeline consisting of four distinct phases: centralized storage, module import, random selection, and header injection.
Step 1: Centralized Data Source
The ua dictionary in holehe/localuseragent.py acts as the single source of truth. It contains nested keys for different browsers, allowing modules to target specific client types when necessary. This structure eliminates hardcoded strings scattered throughout the codebase.
Step 2: Module-Level Imports
Every service module under holehe/modules/ imports the user-agent pool directly. Most modules use explicit imports to access the dictionary:
from holehe.localuseragent import ua
This pattern ensures that when the module executes, it has immediate access to the full repertoire of browser fingerprints without redundant network calls or file I/O operations.
Step 3: Random Selection Per Request
When constructing an HTTP request, the module selects a user-agent string at random from the desired browser category. The implementation uses Python’s standard random.choice() method:
import random
headers = {
"User-Agent": random.choice(ua["browsers"]["chrome"]),
# Additional headers...
}
This selection occurs for every individual request, meaning sequential checks against the same service will present different browser signatures, effectively mimicking organic traffic patterns.
Step 4: Header Injection
The randomly selected string is injected into the request headers dictionary alongside other necessary HTTP headers. This constructed headers object is then passed to the HTTP client (typically requests) to complete the masquerading process.
User-Agent Rotation in Practice: The Facebook Module
The implementation pattern is consistent across all service modules. In holehe/modules/social_media/facebook.py, the code constructs requests as follows:
import random
from holehe.localuseragent import ua
import requests
def check_facebook(email):
headers = {
"User-Agent": random.choice(ua["browsers"]["chrome"]),
"Accept": "text/html,application/xhtml+xml",
}
response = requests.get(
f"https://www.facebook.com/login.php?email={email}",
headers=headers
)
# Response analysis logic...
return response.status_code
The same pattern appears in holehe/modules/social_media/twitter.py and holehe/modules/social_media/instagram.py, demonstrating the repository-wide adoption of this rotation strategy. By reusing the ua dictionary across modules, Holehe maintains a lightweight footprint while maximizing operational security.
Summary
- Centralized storage: All user-agent strings live in
holehe/localuseragent.pyas a JSON dictionary loaded into theuavariable. - Import pattern: Service modules import
uadirectly to access the fingerprint pool without redundant operations. - Random selection: Each request uses
random.choice()to select a fresh user-agent from browser-specific categories. - Detection evasion: Per-request rotation prevents services from identifying Holehe traffic through static browser signatures.
Frequently Asked Questions
How does Holehe select which user-agent to use for each request?
Holehe uses Python’s random.choice() function to select a string from the ua["browsers"] dictionary categories. This selection happens at runtime for every HTTP request, ensuring each connection presents a different browser fingerprint to the target service.
Where are the user-agent strings defined in the Holehe repository?
The strings are defined in holehe/localuseragent.py. This file contains a JSON object parsed via json.loads() into a dictionary named ua, which organizes user-agents by browser type such as Chrome, Firefox, and Safari.
Why does Holehe use random user-agent rotation instead of static strings?
Static user-agent strings create predictable fingerprints that services can easily flag for rate-limiting or blocking. By rotating randomly from a pool of realistic browser signatures stored in holehe/localuseragent.py, Holehe distributes requests across diverse client profiles, reducing the risk of detection during automated OSINT operations.
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 →