How User-Agent Strings Are Managed in Holehe Modules: Centralized JSON and Per-Module Randomization
Holehe manages User-Agent strings through a centralized JSON dictionary in holehe/localuseragent.py that modules import via wildcard and sample randomly to mimic realistic browser fingerprints.
The open-source OSINT tool Holehe (maintained by megadose) takes a deliberate approach to HTTP header management. Rather than hardcoding User-Agent strings across its ~800 modules, the project centralizes all values in a single source file. This design ensures consistency while allowing each module to randomize requests and blend in with legitimate traffic.
Centralized User-Agent Storage in localuseragent.py
All User-Agent strings live in holehe/localuseragent.py, which defines a JSON object named ua containing browser-family groupings.
# holehe/localuseragent.py
import json
ua = json.loads('''{
"browsers": {
"chrome": [
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.1 Safari/537.36",
…
],
"firefox": [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0",
…
],
"safari": [
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Safari/605.1.15",
…
],
"iOS": [
"Mozilla/5.0 (iPhone; CPU iPhone OS 13_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Mobile/15E148 Safari/604.1",
…
]
}
}''')
The structure supports four browser families: chrome, firefox, safari, and iOS. Each contains multiple realistic strings representing different platforms and versions.
Module-Level Implementation Pattern
Every Holehe module follows the same three-step pattern for User-Agent management.
Step 1: Wildcard Import
Modules import the entire localuseragent namespace:
# Example: holehe/modules/transport/blablacar.py
from holehe.localuseragent import *
import random
This wildcard approach gives direct access to ua without repetitive import statements across hundreds of files.
Step 2: Random Selection
Modules use random.choice() to select from their preferred browser family:
# holehe/modules/transport/blablacar.py (line 12)
headers = {
'User-Agent': random.choice(ua["browsers"]["firefox"]),
...
}
Each request thus carries a different User-Agent, preventing signature-based blocking.
Step 3: Request Construction
The selected string joins other headers in the final request configuration.
Browser Family Selection Strategy
Holehe modules strategically choose browser families to match expected client behavior on target services:
| Module Category | Typical Browser Choice | Rationale |
|---|---|---|
| Software/tech services | Chrome | Matches dominant desktop browser market share |
| Social media platforms | Firefox | Diversifies fingerprint; avoids over-representing Chrome |
| Mobile-centric services | iOS | Mimics authentic mobile app traffic |
Advanced Pattern: Persistent User-Agent Variables
Some modules deviate from inline random.choice() calls to reuse a single User-Agent across multiple related requests. The Tumblr module demonstrates this technique:
# holehe/modules/social_media/tumblr.py (lines 11-20)
usrag = random.choice(ua["browsers"]["iOS"])
...
"User-Agent": usrag
By storing the randomized iOS UA in usrag, the module maintains session consistency—critical for services that correlate consecutive requests from the same "device."
Complete Implementation Examples
Standard Chrome Selection
from holehe.localuseragent import *
import random, requests
def check_service(email):
url = "https://example.com/api"
headers = {
"User-Agent": random.choice(ua["browsers"]["chrome"]),
"Accept": "application/json",
}
resp = requests.get(url, headers=headers)
return resp.json()
iOS Session Persistence (Tumblr-Style)
from holehe.localuseragent import *
import random, requests
def tumblr_profile(username):
usrag = random.choice(ua["browsers"]["iOS"])
url = f"https://www.tumblr.com/api/read/json?type=post&filter=raw&num=10&username={username}"
headers = {"User-Agent": usrag}
resp = requests.get(url, headers=headers)
return resp.json()
Key Source Files
holehe/localuseragent.py— Central JSON dictionary of browser-specific User-Agent stringsholehe/modules/transport/blablacar.py— Standard Firefox UA randomizationholehe/modules/social_media/tumblr.py— Customusragvariable with iOS persistence
Summary
- Single source of truth: The
uadictionary inlocaluseragent.pycentralizes all User-Agent strings - Wildcard imports provide clean module-level access without import proliferation
- Per-request randomization via
random.choice()prevents fingerprinting - Strategic browser selection matches target service expectations
- Session persistence variables support multi-request workflows when needed
Frequently Asked Questions
Can I add custom User-Agent strings to Holehe?
Yes. Edit holehe/localuseragent.py and append strings to the appropriate browser list within the ua JSON structure. All modules will automatically access new entries through the existing wildcard import pattern.
Why does Holehe use wildcard imports instead of explicit imports?
Wildcard imports from localuseragent eliminate repetitive import statements across ~800 modules. The trade-off—namespace pollution—is acceptable because ua is the only exported name and collision risk is minimal in this controlled codebase.
How does random User-Agent selection improve OSINT effectiveness?
Services tracking request signatures see varied browser fingerprints instead of a single automated pattern. This reduces detection likelihood and prevents IP-based blocking triggered by consistent header signatures.
What happens if a module doesn't specify a browser family?
All modules explicitly select a family (chrome, firefox, safari, or iOS). The codebase contains no fallback default; each module author deliberately chooses based on the target service's typical user base.
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 →