Holehe & The Secret Email — Dating a ProtonMail Account via Its PGP Key
ProtonMail never publishes account creation dates. It publishes a PGP key for every address, and that key carries a timestamp — one HKP query away.
Platform: OSINT Industries CTF (ctf.osint.industries)
Category: OSINT
Flag format: OSINT{DD-MM-YYYY}
The Challenge
You are investigating the origins of a popular OSINT tool used to pivot from email addresses to online accounts: Holehe.
Behind every tool, there is a creator — and behind that creator, there is an email address. Your mission is to trace back the very first appearance of the creator’s email address online and determine the exact date it was created.
Constraints were explicit: legal, open-source information only. No contacting the developer, no intrusion. Everything solvable through code repositories, public profiles and archives.
Two things need to be found: the creator’s public email address, and the creation date of that address. The second half is where the challenge actually lives, because ProtonMail does not publish account creation dates anywhere in its UI.
Result up front: the address is megadose@protonmail.com, its PGP key was generated 14 January 2021 at 09:41:06 UTC, and the flag is OSINT{14-01-2021}. One HKP keyserver query gets you there. The rest of this is why that query is load-bearing and where it can quietly hand you the wrong day.
Step 1 — The repo owner is megadose, not a fork
Holehe is a well-known tool, so this part is mechanical. A search leads straight to the canonical repository:
https://github.com/megadose/holehe
The repository owner is the GitHub user megadose. Commit history confirms authorship rather than a fork or a mirror — worth checking, since several clones of Holehe exist under other accounts and one of them would send you looking at the wrong person entirely.
Step 2 — The email sits in setup.py, and again in a second repo
The email is present in the Holehe repository itself, in setup.py:
setup(
name='holehe',
version="1.61",
author="megadose",
author_email="megadose@protonmail.com",
...
)
Packaging metadata is a reliable place to look for maintainer contact details across the Python ecosystem — the same value is mirrored on PyPI, so it survives even if the repository changes.
For independent confirmation I pivoted to another repository under the same account, toutatis, and checked its CODE_OF_CONDUCT.md:
https://github.com/megadose/toutatis/blob/master/CODE_OF_CONDUCT.md
The Contributor Covenant boilerplate requires an enforcement contact, and this one is filled in with the same address. Two independent repositories, two independent contexts, same email:
megadose@protonmail.com
Cross-verification across repositories is not busywork. A single occurrence in a single file could be stale, copied from a template, or belong to a different maintainer. Two makes it an attributed identity.
Step 3 — ProtonMail publishes no registration date anywhere
ProtonMail is a privacy-focused provider. It does not expose account registration dates through its web interface, through any public profile, or through any documented API endpoint intended for that purpose.
The way through is indirect: every ProtonMail address gets an OpenPGP key pair generated at registration time, and that public key is published on Proton’s own keyserver so other people can send encrypted mail. OpenPGP keys carry a creation timestamp inside the key material as a matter of protocol. Query the keyserver, read the timestamp.
Step 4 — Every ProtonMail address ships a dated PGP key
Proton exposes a standard HKP (HTTP Keyserver Protocol) interface. The op=index operator returns machine-readable metadata rather than the key itself:
https://api.protonmail.ch/pks/lookup?op=index&search=megadose%40protonmail.com
Response:
info:1:1
pub:b2e401ef07705693a0ccd8d1b0e29d2cac738595:22::1610617266::
uid:megadose@protonmail.com <megadose@protonmail.com>:1610617266::
No tooling required — this runs in a browser address bar.

Re-run 2026-08-06 — the response is byte-identical to the one above, so the key has not been rotated in the years since.
Parsing the response
The HKP draft specification defines the machine-readable index format. Each line matters here.
info:1:1 — format version 1, followed by the count of keys returned. The count is 1. This is more useful than it looks: it means there is exactly one key on file for this address, so there is no ambiguity about which timestamp represents the origin. Had this returned a higher number, the correct approach would be to take the oldest pub: entry, since later ones would represent key rotations rather than account creation.
pub: line — colon-delimited, fields in order:
| Field | Value | Meaning |
|---|---|---|
| 1 | pub | record type |
| 2 | b2e401ef07705693a0ccd8d1b0e29d2cac738595 | key fingerprint |
| 3 | 22 | algorithm ID |
| 4 | (empty) | key length |
| 5 | 1610617266 | creation date, Unix epoch |
| 6 | (empty) | expiration date |
| 7 | (empty) | flags (revoked/disabled/expired) |
Field 5 is the answer. Field 6 being empty means the key carries no expiration. Field 7 being empty means the key is neither revoked nor disabled — the address is live.
Algorithm ID 22 is EdDSA (Curve25519), per the IANA OpenPGP registry. This is a consistency check rather than a requirement: Proton switched its default from RSA-2048 to Curve25519 for newly created accounts in 2019, so an EdDSA key is exactly what a 2021-era account should have. An RSA key here would have been a reason to look harder at whether the key predated or postdated the address.
uid: line — carries the same timestamp, 1610617266. This is the self-signature creation date of the User ID packet: the moment the key was bound to that email address. Key creation and UID binding at the identical second is the strongest available evidence that both happened in a single automated operation — which is precisely what ProtonMail’s registration flow does. This is what upgrades “key creation date” from a proxy into a well-supported claim about account creation.
Converting the timestamp
1610617266 → Thu, 14 Jan 2021 09:41:06 UTC
The timestamp is UTC. Most online converters helpfully render epoch values in the browser’s local timezone, and if you are not paying attention you will submit whatever your machine decided. At 09:41 UTC this is harmless. Had the key been generated near midnight UTC, a local offset would have shifted the date by a full day and produced a wrong flag that looks entirely correct. Convert explicitly:
date -u -d @1610617266
Flag
OSINT{14-01-2021}
Notes
The claim being made. The evidence establishes that the OpenPGP key for megadose@protonmail.com was created on 14 January 2021, and that the address was bound to it in the same operation. That the account was registered on that date is an inference from how ProtonMail’s signup works — strong here given the single-key result and the matching UID timestamp, but it is an inference and a writeup should say so.
Wrong flag, right answer. I burned a submission on this one. My first attempt was rejected despite containing the correct date, because I had assembled the flag from text that had passed through an editor with typographic substitution enabled. The separators were en dashes (–, U+2013), not hyphens (-, U+002D). Visually near-identical in a proportional font, completely different bytes.
Worth building the reflex, because it costs points on challenges you have already solved:
print([hex(ord(c)) for c in flag])
Type flags by hand, or launder them through a plaintext field first. Markdown editors, note-taking apps, word processors and most CMS platforms will silently rewrite hyphens, quotes and ellipses.
Generalising the technique. The HKP query works against any keyserver, not just Proton’s — keys.openpgp.org/pks/lookup?op=index&search= follows the same syntax. The difference is coverage: Proton generates a key for every address automatically, so a lookup is effectively an existence check plus a registration timestamp for the entire protonmail.com, protonmail.ch, pm.me and proton.me namespace. On general-purpose keyservers, only people who deliberately uploaded a key are present, and the creation date reflects when they made that key rather than when they made the account.
Fetching the full key instead of the index uses the same endpoint with a different operator:
curl -s "https://api.protonmail.ch/pks/lookup?op=get&search=megadose@protonmail.com" > key.asc
gpg --show-keys --with-colons key.asc
For this challenge it adds nothing the index did not already provide, but it is the route to take when you need subkey structure or signature details.