False Positives and False Negatives in Holehe Account Detection: Common Causes and Fixes

False positives and false negatives in Holehe primarily stem from ambiguous third-party API responses, aggressive rate limiting, and outdated parsing logic within individual service modules.

Holehe is an open-source OSINT tool that determines whether an email address is registered on hundreds of online services by invoking public registration and recovery endpoints. Because the tool relies on interpreting JSON and HTML responses from external APIs—each implemented as an independent Python module—its accuracy depends heavily on how well these modules handle evolving error messages, CSRF protections, and network edge cases.

How Holehe Detects Account Existence

The detection pipeline follows a modular architecture centered in holehe/core.py. Understanding this flow is essential to diagnosing why errors occur.

First, the import_submodules function (lines 37‑47 in holehe/core.py) dynamically discovers and loads every module under holehe/modules/:


# From holehe/core.py - Module discovery

import_submodules(holehe.modules)

Next, launch_module (lines 66‑74 in holehe/core.py) executes each module asynchronously, passing the target email, an httpx.AsyncClient instance, and a shared result list. Inside individual modules—such as holehe/modules/social_media/facebook.py—the code examines status codes and response bodies. A typical detection pattern looks like this:


# Simplified logic from facebook.py (lines 53-62)

if check["status"] != "fail":
    if 'email' in check["errors"]:
        if check["errors"]["email"][0]["code"] == "email_is_taken":
            out.append({"exists": True, ...})

Each module returns a standardized dictionary containing keys like exists, rateLimit, and error. The central print_result function (lines 22‑49 in holehe/core.py) then displays “[+]” for positive matches, “[-]” for negatives, and “[!]” for errors.

Common Causes of False Positives

False positives occur when Holehe reports an account exists where none does, usually due to misinterpreted response signals.

Ambiguous "Email Already Taken" Messages

Some services return generic "email already used" messages for addresses that are deny-listed, previously released, or flagged by typo-squatting protections. When modules encounter these strings, they often set exists: True despite no active registration. For example, if a service blocks disposable domains with a "taken" response, the module at holehe/modules/social_media/facebook.py may incorrectly flag the email as registered.

Misinterpreted Password Recovery Responses

Modules utilizing password-recovery endpoints—such as adobe.py or mail_ru.py—may receive a "recovery email sent" status even for non-existent accounts. Services that do not explicitly disclose account existence often return identical success messages for both registered and unregistered emails. Holehe interprets this as confirmation, creating a false positive.

CSRF Token and Anti-Scraping Fallbacks

Many modules require valid CSRF tokens to submit registration checks. In facebook.py, token extraction occurs around line 27. If this extraction fails due to HTML changes or bot detection, the module may fall back to generic error handling. When fallback logic improperly interprets anti-scraping challenges (like Cloudflare interstitials) as "account exists" signals, it appends exists: True to the results.

Mishandled Rate Limit Flags

When requests are throttled, modules set rateLimit: True (visible in the exception handling blocks of facebook.py, lines 30‑36). Downstream analysis tools or automated scripts may mistakenly treat these flagged responses as positive matches rather than inconclusive results, generating false positives in aggregate reports.

Common Causes of False Negatives

False negatives occur when Holehe fails to detect an existing account, typically due to blocked requests or changed API structures.

Third-Party API Schema Changes

Services frequently alter their JSON response schemas. If a platform moves the "email_is_taken" indicator to a different field or renames error codes, hard-coded checks like those in facebook.py no longer match. The module defaults to exists: False, missing valid registrations.

Rate Limiting and Request Blocking

Persistent rate limiting prevents modules from reaching the registration endpoint entirely. When launch_module cannot complete the HTTP request, it often appends a result with exists: False or no result at all, effectively hiding existing accounts from the final report.

Missing or Stale CSRF Tokens

If a module fails to fetch required tokens (e.g., due to cookie expiration or anti-bot measures), the subsequent POST request is rejected by the service. The module records exists: False because it never receives the "email taken" confirmation, even when the account is actually registered.

HTML-Only Response Indicators

Some services embed "email already used" notifications in HTML banners rather than JSON responses. Modules configured to parse only JSON—common in older implementations—miss these indicators entirely, returning false negatives for valid accounts.

Mitigation Strategies and Best Practices

While inherent limitations exist due to reliance on external services, you can minimize errors using built-in CLI flags and maintenance routines.

Filter for Confirmed Results Only

Use the --only-used flag to display only services where exists is explicitly True, removing ambiguous rate-limit entries from your view:

holehe user@example.com --only-used

Disable Recovery Endpoint Checks

To avoid false positives from password-recovery modules, use the --no-password-recovery flag (or equivalent implementation in your version):

holehe user@example.com --no-password-recovery

Export for Manual Verification

Export results to CSV for manual analysis of discrepancies, particularly useful when investigating patterns of false positives:

holehe user@example.com --csv output.csv

Keep Modules Updated

The check_update function in holehe/core.py (lines 65‑87) ensures you have the latest module definitions. Regular updates minimize false negatives caused by outdated parsing logic:


# Update holehe to latest modules

pip install --upgrade holehe

Programmatic Error Handling

When using Holehe as a library, inspect the rateLimit and error fields before interpreting exists:

from holehe.core import maincore
import trio
import sys

sys.argv = ["holehe", "user@example.com"]
results = trio.run(maincore)

# Filter out rate-limited services before analysis

confirmed = [r for r in results if not r.get("rateLimit") and not r.get("error")]

Summary

  • False positives typically arise from ambiguous "email taken" messages, misinterpreted password-recovery responses, and mishandled CSRF or rate-limit errors in modules like facebook.py.
  • False negatives usually result from API schema changes, aggressive rate limiting, missing CSRF tokens, or HTML parsing limitations within individual service modules.
  • Mitigation relies on using CLI flags such as --only-used and --no-password-recovery, regularly updating the tool via check_update, and programmatically filtering results for rateLimit or error statuses.
  • The reliability of detection is ultimately tied to the accuracy of response parsing in files under holehe/modules/, making consistent updates essential as third-party services evolve.

Frequently Asked Questions

Why does Holehe report an account exists when the email is not registered?

This false positive usually occurs when a service returns generic "email already taken" messages for reasons other than active registration—such as deny-listed domains or typo-squatting protection. Modules like facebook.py interpret these signals as confirmation of existence. Additionally, password-recovery endpoints in modules such as adobe.py may return "email sent" statuses for non-existent accounts, which Holehe can misinterpret as proof of registration.

How can I reduce false negatives when scanning for accounts?

To minimize false negatives, ensure you are running the latest version of Holehe so that module parsing logic matches current API schemas. Use the check_update function in holehe/core.py to verify module freshness. Additionally, avoid aggressive scanning that triggers rate limits, as throttled modules default to exists: False. Running scans with realistic User-Agent strings from holehe/localuseragent.py can also help bypass basic anti-scraping measures that block requests.

What causes Holehe to miss existing accounts on specific platforms?

False negatives often stem from two technical issues: outdated JSON schema checks and missing CSRF tokens. When services move error codes like "email_is_taken" to new response fields, hard-coded checks in modules fail to match. Similarly, if CSRF token extraction fails (as seen in the fallback logic of facebook.py), the registration check request is rejected before the service can confirm the email exists, resulting in a reported negative.

Should I trust rate-limited results in Holehe output?

No, rate-limited results should be treated as inconclusive. When a module encounters throttling or network errors, it sets rateLimit: True (see the exception handling in facebook.py, lines 30‑36). These entries should not be interpreted as confirmations of account existence or absence. Use the --only-used flag to exclude these ambiguous results from your final analysis, or implement custom filtering that checks the rateLimit key before processing results.

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 →