How the Holehe Login Detection Method Works: Email Verification via Simulated Authentication

Holehe detects email registration status by simulating login attempts against target services, analyzing HTTP responses and JSON payloads to determine account existence without requiring valid passwords.

Holehe is an open-source email investigation framework developed by megadose/holehe that verifies whether an email address is registered across hundreds of web services. The Login detection method serves as the primary mechanism for this verification, implementing service-specific authentication flows that attempt to access accounts using the target email address. This approach standardizes email verification across diverse platforms while handling the unique anti-CSRF protections, token requirements, and response formats of each individual service.

The Four-Step Login Detection Pattern

Every Holehe module implementing the Login detection method follows a consistent asynchronous pattern defined in individual service modules. The workflow operates through four distinct phases:

  1. Token and Session Acquisition – Modules fetch initial pages to extract anti-CSRF tokens, XSRF headers, or client identifiers required by the target service.
  2. Request Construction – Builders assemble HTTP POST (or occasionally GET) requests to authentication endpoints, embedding the target email address and minimal dummy data.
  3. Authentication Attempt – The module sends the request via httpx.AsyncClient, simulating a legitimate login attempt.
  4. Response Analysis – Code interprets HTTP status codes, JSON payloads, or redirect behaviors to determine if the email is registered.

All Login method modules set method = "login" and return a standardized dictionary containing exists, rateLimit, emailrecovery, and other metadata.

Core Orchestration in holehe/core.py

The central execution engine resides in holehe/core.py, which schedules each module's async function through launch_module(). This orchestrator manages the httpx.AsyncClient instance passed to every module, collects the standardized result dictionaries, and handles concurrent execution across multiple services.

Modules do not implement detection logic in the core file; instead, core.py acts as the dispatcher. Each service-specific module implements its own login routine while adhering to the output contract: returning a dictionary with keys including name, domain, method, exists, rateLimit, frequent_rate_limit, emailrecovery, phoneNumber, and others.

Implementation Examples

Snapchat Login Detection (holehe/modules/social_media/snapchat.py)

The Snapchat module demonstrates complex token extraction and JSON-based existence verification. Located at holehe/modules/social_media/snapchat.py, this implementation first harvests security tokens from the login page HTML before attempting authentication:

async def snapchat(email, client, out):
    name = "snapchat"
    domain = "snapchat.com"
    method = "login"
    frequent_rate_limit=False

    # 1. Fetch the login page to obtain X-SRF token & client-id

    req = await client.get("https://accounts.snapchat.com")
    xsrf = req.text.split('data-xsrf="')[1].split('"')[0]
    webClientId = req.text.split('ata-web-client-id="')[1].split('"')[0]

    # 2. Build the login request

    url = "https://accounts.snapchat.com/accounts/merlin/login"
    headers = {
        "Host": "accounts.snapchat.com",
        "User-Agent": random.choice(ua["browsers"]["firefox"]),
        "Accept": "*/*",
        "X-XSRF-TOKEN": xsrf,
        "Accept-Encoding": "gzip, late",
        "Content-Type": "application/json",
        "Connection": "close",
        "Cookie": f"xsrf_token={xsrf}; web_client_id={webClientId}"
    }
    data = '{"email":' + email + ',"app":"BITMOJI_APP"}'

    # 3. Send the request

    response = await client.post(url, data=data, headers=headers)

    # 4. Analyse the response

    try:
        if response.status_code != 204:
            data = response.json()
            out.append({
                "name": name, "domain": domain, "method": method,
                "frequent_rate_limit": frequent_rate_limit,
                "rateLimit": False,
                "exists": data["hasSnapchat"],
                "emailrecovery": None,
                "phoneNumber": None,
                "others": None})
            return None
        out.append({"name": name, "domain": domain, "method": method,
                    "frequent_rate_limit": frequent_rate_limit,
                    "rateLimit": False, "exists": False,
                    "emailrecovery": None, "phoneNumber": None, "others": None})
    except Exception:
        out.append({"name": name, "domain": domain, "method": method,
                    "frequent_rate_limit": frequent_rate_limit,
                    "rateLimit": True, "exists": False,
                    "emailrecovery": None, "phoneNumber": None,
                    "others": None})

This module specifically checks for HTTP status code 204 (indicating successful login, which implies the account exists) versus other status codes that return JSON containing the hasSnapchat boolean flag.

Evernote Login Detection (holehe/modules/productivity/evernote.py)

The Evernote module in holehe/modules/productivity/evernote.py illustrates a classic form-based login flow that examines JSON responses for account existence markers:

async def evernote(email, client, out):
    name = "evernote"
    domain = "evernote.com"
    method = "login"
    frequent_rate_limit=False

    headers = {"Referer": "https://www.evernote.com/Login.action"}
    # 1. Initial GET to obtain hidden form fields

    data = await client.get("https://www.evernote.com/Login.action", headers=headers)

    # 2. Build payload for the login POST

    data2 = {
        "username": email,
        "analyticsLoginOrigin": "login_action",
        "clipperFlow": "false",
        # other mandatory fields …

    }
    # 3. POST login request

    response = await client.post('https://www.evernote.com/Login.action',
                                 data=data2, headers=headers)

    # 4. Interpret response – Evernote returns JSON with "hasEvernote" flag

    result = response.json()
    out.append({
        "name": name, "domain": domain, "method": method,
        "frequent_rate_limit": frequent_rate_limit,
        "rateLimit": False,
        "exists": result.get("hasEvernote", False),
        "emailrecovery": None, "phoneNumber": None, "others": None})

Unlike Snapchat's token-heavy approach, Evernote relies on standard form POST data but similarly extracts the hasEvernote boolean from the JSON response to determine registration status.

Response Interpretation and Rate Limiting

Holehe's Login detection method interprets server responses through three primary indicators:

  • Success Indicators: HTTP 200/204 status codes or JSON boolean flags (hasSnapchat, hasEvernote, hasPatreon) set to true indicate the email is registered.
  • Failure Indicators: Error messages stating "invalid credentials", "password too short", or specific JSON error codes (such as code 2 for "User already exists" in some services) confirm non-existence.
  • Rate Limiting: HTTP 429 responses or connection failures trigger the rateLimit: True flag in the output dictionary, allowing the Holehe interface to display "[x]" for that service.

Additional implementations in holehe/modules/social_media/patreon.py and holehe/modules/shopping/amazon.py follow this same pattern, using direct POST requests to /login endpoints and parsing specific JSON error codes or existence flags to determine registration status.

Summary

  • The Holehe Login detection method simulates authentication attempts to verify email registration without requiring valid passwords.
  • Each module sets method = "login" and implements a standardized async function signature accepting email, client, and out parameters.
  • Detection relies on parsing HTTP status codes, JSON response flags, and error messages to set the exists boolean in the output dictionary.
  • Anti-CSRF tokens and session identifiers are extracted from preliminary GET requests to satisfy service-specific security requirements.
  • The core orchestrator in holehe/core.py handles concurrent execution while individual modules contain the service-specific login logic.
  • Rate limiting detection (HTTP 429) prevents false negatives and marks services as temporarily unavailable.

Frequently Asked Questions

How does Holehe distinguish between registered and unregistered emails?

Holehe analyzes the HTTP response status and payload returned by the login endpoint. Services typically return distinct JSON flags (like hasSnapchat, hasEvernote, or hasPatreon) or specific error codes indicating "user already exists" versus "invalid credentials" or "account not found". The Login detection method captures these nuances through service-specific parsing logic in each module.

Why does Holehe use a dummy password instead of trying to crack the actual password?

The Login detection method intentionally uses placeholder or minimal data (often just the email and a dummy password) because the goal is presence detection, not authentication. Most services reveal whether an email is registered during the initial validation phase before password verification occurs, allowing Holehe to determine account existence without attempting unauthorized access.

What happens when a service rate-limits the Login detection attempt?

When a module encounters HTTP 429 responses or connection timeouts, it catches the exception and appends a result dictionary with rateLimit: True to the output list. This signals to the Holehe interface that the service is temporarily blocking requests, displaying "[x]" rather than a true/false existence value, allowing users to retry later.

Can the Login detection method bypass two-factor authentication protections?

No. The Login detection method operates at the initial authentication stage, submitting only the email address (and occasionally dummy credentials) to the login endpoint. It detects whether the account exists based on the service's response to this initial submission, before any two-factor or multi-factor authentication challenges would occur.

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 →