Skip to main content

Open-source · Local-first · Command-line

Audit your own post history the way an AI would.

Modern language models can read a few hundred of your ordinary public posts and infer where you live, where you work, your routine — and link a pseudonymous account back to your real name. Not from one careless post, but from the mosaic of many. ExposureCheck runs that same adversarial reading on your own export, on your own terms, and shows you what to generalise or edit.
$ exposurecheck audit --twitter ./twitter_export \
    --backend local --expensive-model llama3.1 --i-own-this-data

ExposureCheck v0.1  ·  local backend  ·  nothing left this machine
Parsed 3,214 posts · 19 months · prefilter kept 2,901 (weak signals retained)

RISK CONTRIBUTION        posts   what drives it
───────────────────────────────────────────────────────────────
● LOCATION       High      28    local events, commute clues, "my gym"
● EMPLOYER       High      11    project code-names, office banter
● SCHEDULE       Medium    63    posting-time concentration → UTC-8
○ FAMILY         Low        4    a relative's first name, a school

Top card · LOCATION (High)
  [LOCAL EVENT] near [NEIGHBORHOOD]  — 6 posts
  [COMMUTE] on [TRANSIT LINE]        — mentioned 9 times
  → generalise: drop venue names; delay event posts by a week
  12 posts to review · re-run with -i to open YOUR own originals

No dossier written. No profile saved. "High" is not "you are doxxed" —
it means a model could narrow this down. Fix, then re-scan.

A real run on a local model — masked categories, no resolved values, no profile saved.

What it does, in one minute
#

ExposureCheck reads the data you export from a platform — never a live account, never anyone else’s — and asks the question an adversary would ask: given all of this together, what can be inferred about the person behind it?

  • It parses your Reddit GDPR export and your X / Twitter archive (a folder or a .zip).
  • It runs a recall-preserving cascade: a cheap pass ranks every post, an expensive pass reads the high-priority ones, and weak signals are kept — the mosaic is built from weak signals, so discarding them would be false comfort.
  • It extracts the metadata layer deterministically — the self-set location field, outbound links, image EXIF/GPS, device model, and the posting-time concentration that betrays your timezone. On X this leaks more than the text does.
  • It reports category risk cards — Location, Employer, Family, Schedule, Finances, Account-linkage — ranked by risk contribution, each with masked examples and concrete, generalise-first fixes.

It is local-first, writes no dossier, and never saves a profile of you to disk.

New to “mosaic re-identification”? Start with the threat, not the tool: read the companion explainer, Audit your own post history the way an AI would, then come back.

What it deliberately does not do
#

  • No dossier. It never prints “you live in X, work at Y, your name is Z.” Cards show masked snippets; the resolved value appears only when you click through to your own original post, in-session, never saved.
  • No export of findings. No scraping (export input only). No posting or deleting on your behalf. No analysing anyone else’s history.
  • It does not make you anonymous. It reduces risk. “Low” is not “safe”, and metadata, timing, and writing-style are only partly in scope.

What leaves your machine — and what doesn’t
#

This is the first thing a privacy tool should tell you, so here it is up front. The inference runs on a backend you choose, and that choice — not the tool — decides what travels:

BackendWhat it isDoes your data leave your machine?
locala local Ollama / llama.cpp / LM Studio modelNo — stays on your computer
heuristicoffline regex stub, near-zero recallNo — but dev/CI only, not a real audit
cloudany OpenAI-compatible endpoint, your key⚠️ Yes — your posts go to that provider

The tool itself has no server, no telemetry, no account. The author holds none of your data and no keys. When you pick cloud, your export goes to the API provider you chose — and that provider’s logging, retention, training policy, and the IP/billing tied to your key all apply. ExposureCheck does not add a hop; it also cannot remove the one you opted into.

The one cloud caveat that actually matters
#

If the account you are auditing is a pseudonymous one you keep apart from your real identity, and your AI/cloud account is registered or paid under your real name, then sending that history to the cloud lets the provider link real identity ↔ anonymous account on their side (subpoena, breach, insider). That is the exact deanonymization this tool exists to prevent.

So: auditing a strictly-anonymous account → use --backend local (or a cloud account opened and paid for anonymously). Auditing your real-name / public account → cloud is fine. The CLI states this and asks you to acknowledge it when it applies. We never force local — that would shrink the audience to nobody — we make the trade-off explicit.

How it works
#

export ─▶ parse ─▶ prefilter (drop only TRUE-empty) ─┬─▶ deterministic: profile + EXIF + timing ─┐
                                                     └─▶ cascade: cheap route ─▶ expensive read ─┤
                                         risk-contribution scoring ─▶ category cards ─▶ no-dossier report

The cascade exists so a 1–3k-post history stays affordable: the cheap pass decides what deserves the expensive read instead of sending everything. Risk-contribution scoring then ranks categories by how much they actually narrow you down — not by raw model confidence, which is not calibrated.

Install
#

The core — parsing, EXIF, the cascade, and the cloud/local HTTP backends — is Python standard library only. No third-party package touches your export, which keeps the code you have to trust small.

# from source (a PyPI release ships with the first public version):
git clone https://github.com/coraaegis/exposurecheck && cd exposurecheck
pip install -e .

# or run without installing:
python -m exposurecheck --help
# Local model — nothing leaves your machine (recommended for anonymous accounts)
exposurecheck audit \
  --reddit ./reddit_export.zip \
  --twitter ./twitter_export \
  --backend local --expensive-model llama3.1 \
  --i-own-this-data

# Cloud — bring your own key; set it in the ENV, never on the command line
export OPENAI_API_KEY=sk-...
exposurecheck audit --twitter ./twitter_export --backend cloud --i-own-this-data

The API key is read from an environment variable on purpose: command-line arguments leak into shell history and process listings.

ExposureCheck is a command-line tool today, aimed at people comfortable in a terminal — which is also where its first reviewers live. A one-click app for non-technical users (a packaged build with a local, in-browser UI and no Python to install) is the next milestone; the CLI stays for power users.

Trust it the way you’d trust any privacy tool — by checking, not by faith
#

The author is pseudonymous, so don’t take a name on faith. Take things you can verify instead:

  • Read the code. It is open-source (MIT) and stdlib-only, so the dependency tree you have to audit is essentially the standard library.
  • Verify the release. Each release is PGP-signed by Cora Aegis. Fetch the key over WKD and check the signature:
    gpg --locate-keys cora@cypherpunkguide.com
    gpg --verify exposurecheck-0.1.0.tar.gz.asc
    SHA-256 checksums ship with every release, and builds are reproducible — rebuild from the tagged source and confirm the artifact matches.
  • No identity code-signing certificate, by design — such a certificate would tie the project to a legal identity, the opposite of the point. An unsigned Windows binary may show a SmartScreen “unknown publisher” prompt; that is expected. Prefer a package manager (pip / Scoop / Homebrew) or run from source, and verify the PGP signature.
  • The output design is the safeguard. The no-dossier rule is enforced in code: masked labels are machine-generated, so even the model’s own text cannot surface a resolved value into the report. The dual-use guardrails — ownership-gated input, category-only output, masking, and a pre-release abuse evaluation — are documented in ABUSE-EVAL.md.

A transparent data-flow table and a published threat model show what the tool intends. The source, the signature, and the reproducible build are how you confirm it does that — and nothing else.

Limits you should hold in mind
#

  • “Low” is not “safe.” The tool reduces risk; it does not certify anonymity.
  • Recall is not perfect. A miss (“nothing flagged”) is not proof you are un-identifiable — especially on the heuristic backend, which exists for testing, not auditing.
  • Out of scope: writing-style fingerprinting, cross-platform correlation beyond what’s in your exports, network-level metadata, and the visual content of images (v1 reads EXIF/metadata only — see the roadmap).
  • The tool itself reads your most sensitive data. That is exactly why it is local-first, stdlib-only, open-source, and signed: so the thing you run to check your exposure is itself the smallest, most auditable surface it can be.

FAQ
#

Does ExposureCheck upload my posts anywhere?
#

Only if you choose the cloud backend, and then only to the API provider whose key you supplied. With local or heuristic, nothing leaves your machine. The tool has no server or telemetry of its own.

Will it tell me my own address or real name?
#

No. That is the deliberate “no-dossier” design. It shows masked categories and points you at your own original posts so you can decide what to change. It never assembles or stores a profile of you.

I’m auditing an anonymous account. Is the cloud backend safe?
#

Use --backend local for a strictly-anonymous account, unless your cloud account is itself anonymous. Sending an anonymous account’s history to a real-name AI account links the two on the provider’s side — the exact risk this tool helps you find.

Is it really safe to run on my full history?
#

The code is open-source and stdlib-only so you can read what it does, the release is PGP-signed and reproducible so you can confirm what you installed, and it writes no profile to disk. Verify those, don’t take them on trust — that’s the whole posture.

Why a command line and not an app?
#

The first audience is technical, and a CLI is the most auditable form. A packaged one-click app with a local in-browser UI is the next milestone for non-technical users.


Built by Cora Aegis. Found a privacy or safety flaw? Responsible disclosure is welcome — cora@cypherpunkguide.com (PGP via WKD). The canonical source and the name ExposureCheck live at github.com/coraaegis/exposurecheck.