# How Holehe's Password Recovery Detection Differs from Registration Checks

> Discover how Holehe's password recovery detection differs from registration checks. Learn about its method attribute for targeted endpoint probing.

- Repository: [Palenath/holehe](https://github.com/megadose/holehe)
- Tags: deep-dive
- Published: 2026-08-25

---

**Holehe distinguishes between password recovery detection and registration checks by using a `method` attribute in each module that specifies whether to probe a service's "forgot password" endpoint or its account creation validation flow.**

Holehe is an open-source OSINT tool that identifies where an email address is registered across online services. According to the megadose/holehe source code, the tool employs two distinct strategies—password recovery detection and registration checks—each encoded in a module's **`method`** attribute to determine account existence without attempting actual authentication.

## Two Core Detection Strategies

### Password Recovery Detection

Modules using the `"password recovery"` method mimic the "forgot password" flow of a target service. They submit the email address to the service's password-reset endpoint and parse the response for indicators such as masked email addresses, secondary emails, phone numbers, or success flags. Because the service only returns recovery information for registered accounts, this method reveals existence without risking account creation or triggering rate limits associated with registration attempts.

Examples of this approach appear in [`holehe/modules/software/adobe.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/software/adobe.py) and [`holehe/modules/social_media/odnoklassniki.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/social_media/odnoklassniki.py), where the modules extract masked contact details from recovery responses to confirm account ownership.

### Registration and Login Checks

Alternatively, modules with `method` set to `"register"` (or occasionally `"login"`) emulate the sign-up process. These modules submit the target email—often accompanied by dummy credentials—to the service's registration endpoint and analyze validation errors. If the response contains strings like "email already taken" or "email is registered," the module confirms the address is associated with an existing account.

This approach is implemented in [`holehe/modules/social_media/facebook.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/social_media/facebook.py) and most other social media modules where password recovery endpoints return ambiguous responses.

## Architectural Implementation in holehe/core.py

The orchestration logic resides in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py), which handles module discovery and execution strategy filtering.

### Module Discovery and Loading

The `import_submodules` function (lines 37-48) walks the `holehe.modules` package to dynamically load every `.py` file. Subsequently, `get_functions` extracts the callable coroutine from each submodule along with its `method` metadata string.

### Strategy Filtering via CLI

When users invoke the `-NP` or `--no-password-recovery` flag, the filtering logic in `get_functions` (lines 55-62) excludes modules where `method == "password recovery"`, except for specific whitelisted cases. This allows investigators to avoid password-recovery flows that might send unsolicited reset emails to the target.

### Async Execution Context

The `launch_module` function invokes each coroutine with the target `email`, a shared `httpx.AsyncClient`, and an `out` list. Each module appends a result dictionary containing standardized fields including `exists`, `rateLimit`, `emailrecovery`, and `method`, ensuring consistent output regardless of the internal detection strategy employed.

## Code Implementation Examples

### Password Recovery Detection in Adobe

In [`holehe/modules/software/adobe.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/software/adobe.py), the module implements the password recovery strategy by querying Adobe's authentication challenges endpoint:

```python

# https://github.com/megadose/holehe/blob/master/holehe/modules/software/adobe.py#L5-L15

async def adobe(email, client, out):
    name = "adobe"
    domain = "adobe.com"
    method = "password recovery"
    # First request obtains an authentication state token

    r = await client.post(
        "https://auth.services.adobe.com/signin/v1/authenticationstate",
        json={"username": email, "accountType": "individual"},
    )
    # Second request queries the password‑recovery endpoint

    response = await client.get(
        "https://auth.services.adobe.com/signin/v2/challenges",
        params={"purpose": "passwordRecovery"},
    )
    # If a secondary email is returned, the account exists

    out.append({
        "name": name, "domain": domain, "method": method,
        "exists": True, "emailrecovery": response['secondaryEmail'],
    })

```

### Registration Check in Facebook

Conversely, [`holehe/modules/social_media/facebook.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/social_media/facebook.py) uses the registration approach by attempting a fake account creation:

```python

# https://github.com/megadose/holehe/blob/master/holehe/modules/social_media/facebook.py#L6-L12

async def facebook(email, client, out):
    name = "Facebook"
    domain = "facebook.com"
    method = "register"
    # Submit a fake registration payload

    check = await client.post(
        "https://www.facebook.com/api/v1/web/accounts/web_create_ajax/attempt/",
        data={
            "email": email,
            "username": "...random...",
            "first_name": "",
            "opt_into_one_tap": "false",
        },
        headers={"x-csrftoken": token},
    )
    # Facebook returns an error object; if it contains "email_is_taken"

    # we know the address is already registered.

    if check["status"] != "fail" and "email_is_taken" in str(check["errors"]):
        out.append({
            "name": name, "domain": domain, "method": method,
            "exists": True, "emailrecovery": None,
        })

```

## Summary

- **Password recovery detection** probes "forgot password" endpoints and parses recovery responses for masked data or success indicators, using `method = "password recovery"`.
- **Registration checks** simulate account creation to trigger "email already taken" errors, using `method = "register"` or `"login"`.
- The [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) file orchestrates strategy selection through `import_submodules` and `get_functions`, with CLI flags to filter recovery-based modules.
- Each strategy carries different trade-offs in stealth, rate limiting, and the potential to send unsolicited emails to targets.

## Frequently Asked Questions

### What is the main advantage of password recovery detection over registration checks?

Password recovery detection typically avoids triggering account creation rate limits and validation flows. By querying existing account recovery mechanisms, the method reduces the risk of alerting security systems that monitor for automated registration attempts, though it may generate password reset emails visible to the target.

### How does Holehe exclude password recovery methods from a scan?

The tool filters modules based on the `method` attribute when users specify the `-NP` or `--no-password-recovery` command-line flag. In [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py), the `get_functions` logic skips modules where `method == "password recovery"` unless explicitly whitelisted, ensuring investigators can avoid sending unsolicited reset notifications.

### Can a single Holehe module implement both detection strategies?

While the architecture supports distinct `method` values per module, individual modules typically specialize in one approach based on the target service's API constraints. Services like Odnoklassniki and Adobe exclusively use password recovery detection, while Facebook and Instagram rely on registration validation, as defined in their respective `method` attributes.

### Why would a module use registration checks instead of password recovery?

Some services obfuscate their password recovery responses or require additional authentication steps that prevent reliable enumeration. In these cases, probing the registration endpoint for "email already taken" errors provides a more reliable signal of account existence, implemented in modules like [`facebook.py`](https://github.com/megadose/holehe/blob/main/facebook.py) where the registration flow exposes clearer validation messages.