Most people think of a Google account as a private thing, yet the platform quietly surfaces a surprising amount of information about public accounts to anyone who knows which endpoints to ask. GHunt, maintained by mxrch under the Malfrats banner, is the open source tool that turned this observation into a discipline. Its own README describes it as an offensive Google framework oriented toward open-source intelligence, and version 2 rebuilt it as a fully asynchronous Python 3.10+ codebase that also runs on 3.13. Instead of a pile of scripts, it is a structured framework with a login engine, a declarative API layer, and focused investigation modules.
What makes GHunt worth reading is not just what it finds but how it is put together. The codebase separates concerns the way a well-run product would: authentication lives in one helper, credential storage in one object, request construction in one base class, and each investigative capability in its own module. Every module can emit structured JSON alongside its rich terminal output, serving both humans and downstream tooling. Reading the source is a compact lesson in how to talk to large authenticated platforms programmatically without dragging a browser along.
This article is an educational tour of the GHunt source tree, aimed at engineers, researchers, and defenders who want to understand how such a framework is engineered. It is not a how-to for profiling people. The project’s own documentation asks that it be used only in personal, criminal-investigation, pentesting, or open-source-research contexts, and this article endorses exactly that framing. Respect the privacy of others, follow the laws of your jurisdiction, and treat everything below as a study of architecture, not an invitation to surveil anyone.
GHunt at a glance: a thin CLI over an auth engine, a declarative Google API layer, and six focused intel modules.
Reading the overview from left to right:
- The process starts at ghunt/ghunt.py, a version gate that refuses to run below Python 3.10, then shows the banner and hands control to the CLI.
- ghunt/cli.py defines the subcommands, including login, email, gaia, drive, geolocate, and spiderdal, and dispatches each into asyncio.
- The authentication spine lives in ghunt/helpers/auth.py, which mints and refreshes the master token, per-app tokens, cookies, and OSIDs.
- Everything the framework knows about its session is stored by ghunt/objects/base.py in a single GHuntCreds object persisted to disk.
- ghunt/objects/apis.py provides the GAPI base class and the EndpointConfig dataclass that describe how each request must be authenticated.
- Public Google API keys and their required origins are cataloged in ghunt/knowledge/keys.py.
- ghunt/apis/peoplepa.py wraps the People Pa service that answers both the email and gaia modules.
- The intel modules under ghunt/modules/ each own one investigation type and print or export their own results.
Why You Need This
The first reason is awareness. GHunt demonstrates, at the protocol level, exactly which pieces of information a Google account exposes publicly: whether the profile and cover photos are custom or default, when the profile was last edited, which services the account has activated, and how much activity shows up in public Maps contributions. For anyone managing their own digital footprint, seeing the code that queries these surfaces is more convincing than any privacy checklist. The tool documents the boundary between public and private on one of the world’s largest platforms.
The second reason is engineering. GHunt is one of the cleanest public examples of a Python client for an ecosystem that was never meant to have an official API for this purpose. It shows how to model heterogeneous endpoints with a single declarative dataclass, how to keep multiple token types alive at once, how to refresh credentials safely inside an asyncio event loop, and how to keep per-request cookies out of a shared HTTP client. Those patterns transfer directly to any large-platform integration you will ever build.
The third reason is defense. Blue teams and privacy-conscious users benefit from understanding the adversary’s tooling in depth. Knowing that custom profile photos are treated as high-value signals, that public calendar events can be enumerated, and that Maps reviews can be correlated into location estimates gives you a concrete list of settings to review. Frameworks like this exist whether you study them or not, and an informed defender is harder to profile.
How It Works
Inside GHunt: the auth engine, the GAPI request layer, and the six modules that share them.
Understanding the Architecture
A version gate and a thin CLI. Execution begins in ghunt.py, which checks that the interpreter is at least Python 3.10 and then prints the banner and version. Control passes to parse_and_run in cli.py, which builds an argparse parser with a rich help formatter, defines one subparser per capability, and uses a match statement to route each subcommand into its async main function. There is no hidden state; the CLI is a literal table of what the framework can do, which makes the project easy to navigate.
A login flow built around an Android master token. The auth helper speaks to Google the way an Android device does. It requests a master token from the android authentication service using the ac2dm service name, then derives per-app authorization tokens from that master token, passing each target package name with its signing-certificate fingerprint. Browser-side credentials are regenerated separately: cookies come from the accounts OAuth login followed by a merge session call, and OSID cookies are fetched through a dedicated set-OSID step executed concurrently. The interactive auth_dialog offers four ways to bootstrap a session: listening for the GHunt Companion browser extension to relay session data, pasting a base64 blob from it, or supplying an existing oauth2_4 or aas_et token.
One credentials object, one file. GHuntCreds in objects/base.py holds the cookies, the OSIDs, the Android master token, and the per-app authorization tokens in a single in-memory object. Saving serializes it to JSON, encodes it in base64, and writes it to creds.m inside the .malfrats/ghunt folder in the user’s home directory. The login module’s check_and_login routine loads that file, validates each component, regenerates what is stale, and saves again; the –clean flag simply deletes the file to start over. This one-file model keeps repeated runs stateful without any database.
A declarative request engine. Each Google service is wrapped in a small class that inherits from GAPI and declares its endpoints as EndpointConfig dataclasses. A config spells out the HTTP verb, the data type, which headers and cookies are needed, and crucially the authentication mode: SAPISIDHASH-signed cookies, cookies only, an OAuth token, or none. When a request fires, GAPI assembles the exact header set, adding an API key with matching Origin and Referer headers whenever the endpoint requires one, and attaching the ext metadata headers some Google endpoints expect. OAuth tokens are generated on demand and cached with an expiry timestamp guarded by an asyncio lock, so concurrent coroutines never race to refresh the same token. Underneath, the framework uses a subclassed httpx.AsyncClient whose merge-cookies override ensures the client never accumulates session state between requests.
A catalog of public keys. The knowledge/keys.py file ships seven API keys that Google’s own web properties embed in their pages, each paired with the origin it is normally used from, such as Photos, the APIs explorer, Calendar, YouTube, and Drive. GAPI consults this catalog whenever an endpoint requires a key, reproducing the exact origin headers that make those keys acceptable. It is pragmatic reverse-engineering bookkeeping, kept declarative rather than buried in call sites.
Six intel modules share one spine. The email and gaia modules both lean on the People Pa wrapper’s people lookup endpoint with maximum detail. They verify the PROFILE container is present, then surface custom profile and cover photos with their default status, the Gaia ID, the profile’s last update timestamp, user types with human-readable definitions, Chat and Google Plus extended data, and the list of activated Google services from in-app reachability. The drive module takes a file or folder ID and reports title, mime type, checksum, size, dates, link-sharing roles, the source application brand resolved via the client auth config service, image or video metadata, parent folders, child item counts, every user with a role on the file alongside email and Gaia ID, top comment authors, and any non-default capabilities. The geolocate module submits a Wi-Fi BSSID or a JSON body to the geolocation endpoint, then reverse-geocodes the result through Nominatim to print coordinates, an accuracy radius in meters, an estimated address, and a Maps link. The spiderdal module crawls the Digital Asset Links graph breadth-first from a website or an Android package with its SHA-256 fingerprint, capping concurrency with a semaphore at ten, and reports every reachable site and package, including which origin leaked each link, before a Play Store check labels each package public or private.
Maps signals and confidence math. A dedicated gmaps helper queries the Maps review statistics endpoint using protobuf-style templates stored in config, parsing the returned payload for the counts of reviews, ratings, and photos, and treating a redirect to the sorry page as a rate-limit signal. Configuration also defines a thirty-kilometer grouping radius and helpers translate numeric confidence values into human phrases. The statistics land in both the terminal report and the JSON export, framed as public contribution counts.
End to end. Follow one command through the framework: the CLI matches the email subcommand, the module loads or refreshes credentials through the auth helper, People Pa answers a single maximum-detail lookup, the gmaps helper adds contribution statistics, and the rich console prints the assembled profile, or GHuntEncoder writes it all to a JSON file. One file of credentials, one declarative API layer, one focused module per question. That symmetry is why the framework reads like a product rather than a script collection.
Advantages
- Fully asynchronous core. Every network operation runs on asyncio with httpx, so concurrent lookups, token refreshes, and the spiderdal crawl stay fast and responsive.
- Declarative endpoint configs. EndpointConfig captures verbs, headers, cookies, and authentication modes in one place, making new Google services cheap to wrap correctly.
- Resilient multi-token auth. Master token, per-app tokens, cookies, and OSIDs each have their own lifecycle, validation, and regeneration path, so a stale component does not sink the session.
- Strict module isolation. Each intel module owns its API wrapper, output format, and JSON export, keeping the codebase navigable and easy to extend.
- Dual output modes. Rich terminal panels for humans and GHuntEncoder-produced JSON files for tooling come from the same data, with no second code path.
- Session persistence without a database. One base64 creds file preserves the entire authenticated state across runs and is trivially reset with –clean.
Benefits
- Understand your own exposure. The email and gaia modules reveal precisely which account surfaces are public, from custom photos to activated services, so you can tighten what matters.
- Learn production-grade API client patterns. Token caching with locks, per-endpoint auth modes, and cookie-free clients are directly reusable lessons for any large-platform integration.
- Strengthen blue-team awareness. Knowing which signals investigators can correlate, from Maps statistics to Drive collaborators, turns abstract privacy advice into a concrete checklist.
- Study reverse engineering discipline. The keys catalog, origin headers, and Android-style token exchange are a masterclass in documented protocol work.
- Adapt the architecture to your own tools. The GAPI pattern is a template you can lift for any authenticated API that lacks an official SDK.
- Open source you can audit. The AGPL-3.0 license and a compact, well-factored codebase make every claim in this article verifiable in minutes.
Usage
Installation follows the project README and uses pipx so the CLI lands on your PATH:
pipx install ghunt
The first run bootstraps a session, typically with the GHunt Companion browser extension relaying session data:
ghunt login
Each module is then a single subcommand, and any module can append its findings to a JSON file:
ghunt email someone@example.com --json results.json
ghunt gaia 123456789012345678901
ghunt drive <file_id>
ghunt geolocate -b AA:BB:CC:DD:EE:FF
ghunt spiderdal -u example.com
ghunt spiderdal -p com.example.app -f <sha256_fingerprint>
The geolocate module accepts either a BSSID with -b or a JSON body with -f, and spiderdal accepts either a URL with -u or a package and fingerprint pair, with an optional –strict flag to skip www-prefixed variants.
Conclusion
GHunt earns its reputation twice over: as a practical OSINT framework for Google accounts and as a beautifully organized Python codebase. The version 2 rewrite shows what a mature async architecture looks like when applied to an unfriendly, undocumented API surface: a single credentials object, a declarative endpoint layer that handles seven different key-and-origin combinations without repetition, an auth engine that juggles four credential types, and modules that stay laser-focused on their own questions. Read it to understand your exposure, to borrow its engineering patterns, or to appreciate how much structure a small team can carry. Remember the project’s own words about responsible use, and keep your curiosity pointed at systems you are authorized to examine.
Links:
Enjoyed this post? Never miss out on future posts by following us