Understanding the Difference Between Register, Login, and Password Recovery Methods in Holehe Modules
Holehe modules use three distinct interaction patterns—register, login, and password recovery—to verify email existence across 150+ services without exposing sensitive credentials.
The Holehe OSINT tool (megadose/holehe) identifies whether an email address is registered on various platforms by exploiting public-facing endpoints. Each module declares a method constant that dictates its behavior: attempting account creation, authentication, or password reset flows. The core engine dispatches these methods uniformly, while individual modules handle service-specific nuances.
How Module Methods Work in Holehe
Holehe's architecture separates orchestration from implementation. The core engine (holehe/core.py) loads modules dynamically, inspects their method attribute, and executes their check() function. The module itself contains all HTTP logic, response parsing, and error handling. This design allows contributors to add new services without modifying core code.
All three methods follow an identical async signature:
async def check(email: str, client: httpx.AsyncClient) -> dict:
# Module-specific HTTP request and response analysis
return {"email": email, "status": "...", "method": "..."}
The method constant (defined at module level) informs the core how results should be categorized and reported.
The Three Method Types Explained
Register Method
Purpose: Detect existing accounts by attempting to create a new one with the target email.
Register modules exploit a common API pattern: services reject registration when an email is already in use. The module sends a registration request and interprets "email already taken" responses as confirmation of account existence.
Typical workflow:
- Build registration payload (email, username placeholder, password).
POSTto the service's signup endpoint.- Parse response for existence indicators like
"already registered"or HTTP 409.
Advantage: No valid credentials required; purely passive detection.
Login Method
Purpose: Confirm account existence through authentication endpoints.
Login modules submit the target email with an intentionally invalid password. Services respond differently for "email not found" versus "password incorrect"—the latter confirms the email exists. Some modules also detect successful session establishment for accounts without password protection or with leaked credentials.
Typical workflow:
- Construct login request with email and dummy password.
POSTto authentication endpoint.- Analyze error messages, redirects, or session cookies.
Advantage: Can distinguish between non-existent accounts and wrong-password scenarios, providing higher confidence in results.
Password Recovery Method
Purpose: Trigger "forgot password" flows to verify email registration.
Password recovery modules interact with publicly accessible reset mechanisms. Services typically respond with generic confirmations like "reset email sent" or return masked versions of the registered email (e.g., t***@gmail.com). Either response confirms account existence without requiring authentication.
Typical workflow:
- Submit email to password reset endpoint.
- Parse JSON or HTML response for success indicators.
- Extract masked email or confirmation message when available.
Advantage: Generally lower rate-limiting and blocking risk than login attempts; legally safer as it uses intended user workflows.
Code Examples from the Holehe Repository
Register Module: Twitter
File: holehe/modules/social_media/twitter.py
method = "register"
async def check(email: str, client):
headers = {
"User-Agent": "Mozilla/5.0",
"Authorization": "Bearer AAAAAAAAAAAAAAAAAAAA...",
"Content-Type": "application/json"
}
data = {
"email": email,
"flow_name": "signup",
"flow_data": {"requested_variant": "email"}
}
resp = await client.post(
"https://api.twitter.com/1.1/users/email_available.json",
headers=headers,
json=data
)
result = resp.json()
if not result.get("valid", False) and result.get("taken", False):
return {
"email": email,
"status": "registered",
"exists": True,
"method": "register"
}
return {"email": email, "status": "available", "exists": False}
The Twitter module queries an internal API endpoint that validates email availability during signup. A taken: true response definitively confirms account existence.
Login Module: Facebook
File: holehe/modules/social_media/facebook.py
method = "login"
async def check(email: str, client):
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
data = {
"email": email,
"pass": "INVALID_PASSWORD_FOR_ENUMERATION",
"login": "1"
}
resp = await client.post(
"https://www.facebook.com/login.php",
headers=headers,
data=data,
allow_redirects=False
)
# Facebook redirects to checkpoint or home on valid email with wrong password
# "login_error" in response indicates unrecognized email
if "login_error" in resp.text or resp.status_code == 200:
return {
"email": email,
"status": "not_found",
"exists": False,
"method": "login"
}
# 302 redirect or "checkpoint" indicates valid credentials exist
return {
"email": email,
"status": "login_requires_password",
"exists": True,
"method": "login"
}
Facebook's login flow distinguishes between unrecognized emails (stays on login page with error) and valid emails with wrong passwords (redirects to checkpoint or recovery). The module exploits this behavioral difference.
Password Recovery Module: Odnoklassniki
File: holehe/modules/social_media/odnoklassniki.py
method = "password recovery"
async def check(email: str, client):
headers = {
"User-Agent": "Mozilla/5.0",
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded"
}
data = {
"st.email": email,
"st.friend": "",
"st.phone": ""
}
resp = await client.post(
"https://ok.ru/dk?cmd=anonymRecoveryStart&st.cmd=anonymRecoveryStart",
headers=headers,
data=data
)
try:
result = resp.json()
except ValueError:
return {"email": email, "status": "error", "exists": False}
# Masked email in response confirms account exists
masked_email = result.get("maskedLogin")
if masked_email:
return {
"email": email,
"status": "recovery_sent",
"exists": True,
"masked_email": masked_email,
"method": "password recovery"
}
# "EMAIL_NOT_FOUND" or similar indicates no account
if result.get("error", "").upper() == "EMAIL_NOT_FOUND":
return {"email": email, "status": "not_found", "exists": False}
return {"email": email, "status": "unknown", "exists": False}
Odnoklassniki's recovery endpoint returns the masked registered email when found, providing explicit confirmation without requiring authentication.
Core Engine Dispatch Logic
The central orchestration in holehe/core.py loads modules and normalizes their execution:
# Simplified excerpt from holehe/core.py
async def run_module(module, email: str, client: httpx.AsyncClient) -> dict:
"""Execute a single module and standardize its output."""
method = getattr(module, "method", "unknown")
result = await module.check(email, client)
# Enrich with metadata
result["module"] = module.__name__.split(".")[-1]
result["method"] = method
result["category"] = categorize_method(method) # register/login/recovery
return result
def categorize_method(method: str) -> str:
"""Normalize method strings for reporting."""
method_lower = method.lower()
if "register" in method_lower:
return "registration"
if "login" in method_lower:
return "authentication"
if "recovery" in method_lower or "reset" in method_lower:
return "password_recovery"
return "unknown"
This abstraction allows modules to evolve independently while providing consistent output formatting for CLI and programmatic consumers.
Why Method Selection Matters
Detection reliability varies by service. Some platforms aggressively rate-limit login attempts but permit registration checks. Others expose password recovery without authentication, making it the only viable vector.
Legal and ethical considerations differ. Password recovery flows are designed for public access and typically include CAPTCHAs or rate limiting that respects normal user behavior. Login attempts with invalid credentials may violate terms of service more explicitly in some jurisdictions.
Result granularity impacts investigations. Register methods identify account existence directly. Login methods can additionally reveal account status (active, suspended, requiring 2FA). Recovery methods sometimes expose partial email masking or associated phone numbers.
Summary
-
registermodules confirm accounts by attempting signup and intercepting "already exists" errors. -
loginmodules use invalid passwords to distinguish between non-existent accounts and existing ones with wrong credentials. -
password recoverymodules exploit reset flows that confirm registration through success messages or masked email returns. -
All three implement an identical
check(email, client)interface consumed byholehe/core.py. -
Method selection depends on service behavior, rate limits, and detection reliability requirements.
-
The modular architecture enables community contributions without core engine modifications.
Frequently Asked Questions
How does Holehe determine which method to use for a specific service?
Each module hardcodes its method constant based on the contributor's analysis of which endpoint provides reliable enumeration. The core engine does not auto-select; it executes whatever the module declares. Contributors choose methods by testing service responses and selecting the most stable indicator of account existence.
Can a single service module implement multiple methods?
No—Holehe's architecture expects one method per module. Services with multiple viable endpoints are typically implemented as separate modules (e.g., twitter_register.py vs twitter_recovery.py) or the contributor selects the most reliable single approach. The method constant must be a string, not a list.
Why do some modules fail while others succeed for the same email?
Services implement different anti-automation protections. Login endpoints often have stricter rate limiting and CAPTCHA requirements than registration or recovery endpoints. Additionally, geographic IP restrictions and session fingerprinting affect some methods more than others. The method type directly influences success probability against specific targets.
Is the password recovery method always the safest option?
Generally yes for avoidance of rate limits, but not universally. Some services email account holders when recovery is triggered, potentially alerting targets to investigation. Others require additional verification (SMS, backup codes) that modules cannot complete, resulting in inconclusive results. Method safety depends on the specific service's implementation and the investigator's threat model.
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 →