{"id":51909735,"url":"https://github.com/26zl/leak-sweep","last_synced_at":"2026-07-27T03:30:41.445Z","repository":{"id":372055086,"uuid":"1289574913","full_name":"26zl/leak-sweep","owner":"26zl","description":"Scan your GitHub repos for leaked personal information (secrets, PII, national IDs) so you don't get doxxed.","archived":false,"fork":false,"pushed_at":"2026-07-18T16:48:53.000Z","size":111,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-18T17:18:51.855Z","etag":null,"topics":["doxxing","github","gitleaks","pii","presidio","privacy","python","secrets-detection","security"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/26zl.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-07-04T23:45:25.000Z","updated_at":"2026-07-18T16:48:56.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/26zl/leak-sweep","commit_stats":null,"previous_names":["26zl/leak-sweep"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/26zl/leak-sweep","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/26zl%2Fleak-sweep","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/26zl%2Fleak-sweep/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/26zl%2Fleak-sweep/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/26zl%2Fleak-sweep/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/26zl","download_url":"https://codeload.github.com/26zl/leak-sweep/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/26zl%2Fleak-sweep/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35935763,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-07-27T02:00:06.776Z","response_time":101,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["doxxing","github","gitleaks","pii","presidio","privacy","python","secrets-detection","security"],"created_at":"2026-07-27T03:30:38.900Z","updated_at":"2026-07-27T03:30:41.428Z","avatar_url":"https://github.com/26zl.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# leak-sweep\n\n**Scan all your GitHub repos for leaked personal information — so you don't get\ndoxxed by your own git history.** The main Python scanner drives\n[gitleaks](https://github.com/gitleaks/gitleaks),\n[Presidio](https://github.com/data-privacy-stack/presidio) and\n[python-stdnum](https://github.com/arthurdejong/python-stdnum) (LGPL) over every\nrepo you can reach with `gh`, and tells you exactly where your private data shows up.\n\nIt looks for:\n\n- **Secrets** (API keys, tokens, passwords) across the *entire git history* — gitleaks\n- **Your own identifiers** (name, email, phone, address — from `personal.txt`) across the whole history\n- **National ID numbers** for the selected regions (checksum-validated via python-stdnum), in history and files\n- **General PII** in current files (names, locations, emails, phones, cards, IBAN, public IPs) — Presidio\n- **Commit identities** (author/committer) and **file paths** matching your identifiers\n- **Beyond your own repos** (with `--deep`): repos you collaborate on, your public profile, gists, forks of your repos, EXIF/GPS in committed images, and a GitHub-wide search for your identifiers in *other people's* repos\n\nNothing leaves your machine except requests and clones sent to GitHub. The\noptional `--search` check submits each watchlist term to GitHub's Search API.\nSensitive values (cards, national IDs, secrets and GPS coordinates) are\n**masked in the report by default**.\n\n## Why\n\nPublic repos leak more than code: a real email in an old commit, a phone number\nin a test fixture, an API key in history, a config file you forgot to `.gitignore`.\nThis finds those before someone else does.\n\n## Setup\n\n### macOS\n\n```sh\nbrew install python gh gitleaks  # then `gh auth login` if you aren't logged in\n./setup.sh                   # creates .venv, installs deps + the spaCy model, seeds personal.txt\n```\n\n### Linux\n\nInstall Python 3.9–3.14, Git and GitHub CLI with your distribution's package\nmanager, install Gitleaks from its official release, then run:\n\n```sh\n./setup.sh\ngh auth login\n```\n\n### Windows (PowerShell)\n\n```powershell\nwinget install --id Python.Python.3.13 -e\nwinget install --id Git.Git -e\nwinget install --id GitHub.cli -e\nwinget install --id Gitleaks.Gitleaks -e\n```\n\nOpen a new PowerShell window after the installs so `PATH` is refreshed, then:\n\n```powershell\n.\\setup.ps1\ngh auth login\n.\\.venv\\Scripts\\python.exe .\\sweep.py --selftest\n```\n\n\u003cdetails\u003e\u003csummary\u003eManual setup (if you'd rather not run the script)\u003c/summary\u003e\n\n```sh\npython3 -m venv .venv\n.venv/bin/pip install --require-hashes -r requirements.lock\ncp personal.example.txt personal.txt   # then fill in your own identifiers\nchmod 600 personal.txt\n```\n\u003c/details\u003e\n\nEdit `personal.txt` with the identifiers you care about (emails, phone numbers\nin a few formats, addresses, old usernames). It is **gitignored** and the tool\nrefuses to run if it ever becomes git-tracked. Its terms stay local unless you\nexplicitly enable `--search` or `--deep`.\n\n\u003e Runs natively on Python 3.9–3.14 on macOS, Linux and Windows. `setup.ps1`\n\u003e creates the Windows virtual environment and restricts `personal.txt` to the\n\u003e current Windows account.\n\nWhen run from this checkout, private data stays under the checkout. An installed\n`leak-sweep` command uses the private `~/.leak-sweep` directory.\n\n## Usage\n\n```sh\n.venv/bin/python sweep.py                  # all your repos (forks skipped)\n.venv/bin/python sweep.py --repo NAME      # a single repo (repeatable)\n.venv/bin/python sweep.py --owner ORG      # a user/org you have access to\n.venv/bin/python sweep.py --include-forks  # include forks\n.venv/bin/python sweep.py --no-presidio    # skip the NER pass (faster)\n.venv/bin/python sweep.py --id-regions SE,DK   # national-ID regions (default: auto)\n.venv/bin/python sweep.py --id-regions all      # every supported country (noisier)\n.venv/bin/python sweep.py --id-regions none     # disable national-ID detection\n.venv/bin/python sweep.py --region GB      # phone-number region for parsing (default: NO)\n.venv/bin/python sweep.py --raw            # write full unmasked values to the report\n.venv/bin/python sweep.py --fail-on public # exit 1 on public findings (default: never; for cron/CI)\n.venv/bin/python sweep.py --clean          # delete the work/ clones\n.venv/bin/python sweep.py --version        # print version\n.venv/bin/python sweep.py --selftest       # run the built-in checks\n```\n\nIn Windows PowerShell, use `.\\.venv\\Scripts\\python.exe .\\sweep.py` in place\nof `.venv/bin/python sweep.py`.\n\n### Beyond your own repos\n\nBy default the tool scans repos you **own**. These flags widen the net to the\nrest of your GitHub doxxing surface:\n\n```sh\n.venv/bin/python sweep.py --collaborator   # also repos you collaborate on (not just own)\n.venv/bin/python sweep.py --profile        # what your public profile exposes (name/location/bio/email)\n.venv/bin/python sweep.py --gists          # your gists (public + secret)\n.venv/bin/python sweep.py --forks          # forks of your public repos (leaks live on there)\n.venv/bin/python sweep.py --exif           # GPS/author metadata in committed images/PDFs (needs exiftool)\n.venv/bin/python sweep.py --search         # GitHub-wide search (code/commits/issues) in OTHERS' repos\n.venv/bin/python sweep.py --wiki           # your repos' wikis (separate .wiki.git repos)\n.venv/bin/python sweep.py --releases       # release names + notes\n.venv/bin/python sweep.py --actions        # recent Actions run logs (watchlist terms; slow)\n.venv/bin/python sweep.py --deep           # all of the above at once\n```\n\n`--search` is **best-effort** and sends every term in `personal.txt` to GitHub's\nSearch API. GitHub only indexes default branches of non-archived public repos,\nso it can miss things — it complements, not replaces, the clone scan of your\nown repos.\n\nThe report lands in `reports/report-\u003ctimestamp\u003e.md` (plus a `.json`).\n`reports/`, `work/` (the clones) and `personal.txt` are gitignored — no findings\nor private data are ever committed, and source-checkout runs skip that\ncheckout's origin. These paths use owner-only POSIX permissions on macOS/Linux\nand a current-user-only ACL on Windows. **The report still contains your\nwatchlist identifiers in cleartext — keep it private.**\n\n### Exit codes (for cron/CI)\n\nBy default the tool exits `0` after a complete report-only scan. For automation,\npass `--fail-on public` (or `any`): `1` = matching findings, `2` = an incomplete\nscan, and `130` = interrupted (a partial report is still written).\n\nWeekly sweep via cron (adjust the path to wherever you cloned it):\n\n```\n0 9 * * 1 cd /path/to/leak-sweep \u0026\u0026 .venv/bin/python sweep.py --fail-on public\n```\n\n## Check your git setup\n\n`gitcheck.py` performs a read-only check of your local Git / GitHub setup across\n**git, the gh CLI and GitHub Desktop**:\n\n```sh\npython3 gitcheck.py\n# or, after installing the wheel: leak-sweep-gitcheck\n```\n\nIt checks commit identity and GitHub noreply use, auth and credential helpers,\ncommit signing, default branch and pull/push policy, pruning and line-ending\nbehavior, risky `safe.directory`/file-protocol settings, hooks, and\nWindows-specific long-path/NTFS protection. Inside a repo it also checks local\nconfig parsing, branch/worktree state, object-database connectivity, origin and\nfetch refspec, remote protocol/reachability, upstream/ahead/behind status, and\ncommit emails already present in history. It exits non-zero if a check fails;\nwarnings identify recommended or privacy-sensitive improvements.\n\n## Development checks\n\n```sh\n.venv/bin/pip install --require-hashes -r requirements-dev.lock\n.venv/bin/python -m py_compile sweep.py gitcheck.py leak_sweep_reporting.py national_id.py\n.venv/bin/python sweep.py --selftest\n.venv/bin/python -m unittest discover -s tests -v\n.venv/bin/ruff check .\n.venv/bin/pyright --pythonpath .venv/bin/python\n.venv/bin/pip-audit --require-hashes -r requirements.lock\n.venv/bin/pip-licenses\n.venv/bin/python -m build --no-isolation\nbash -n setup.sh\n```\n\n`pyproject.toml` is the dependency source of truth. Regenerate the checked-in\nhash-locked files with [uv](https://docs.astral.sh/uv/) after changing it:\n\n```sh\nuv pip compile pyproject.toml --python-version 3.9 --universal --generate-hashes -o requirements.lock\nuv pip compile pyproject.toml --extra dev --python-version 3.9 --universal --generate-hashes -o requirements-dev.lock\n```\n\n## Releases\n\nUpdate `sweep.__version__`, merge a green CI run, then create and push a matching\nsigned or annotated `vX.Y.Z` tag. The release workflow verifies the tag/version\npair, rebuilds and tests the wheel, generates release notes from Git history,\nand publishes it to GitHub Releases. It does not publish to PyPI.\n\n## Known limitations\n\n- Phone numbers without `+`/separators in code files are not reported (too much\n  noise from dates) — put your number in `personal.txt` and it's caught everywhere\n- NER runs on at most 400 prose files per repo; files \u003e 512 KB are skipped (counted in the report)\n- Binary files (PDFs, images) aren't scanned — but their paths are checked against your watchlist\n- Presidio uses the English model (`en_core_web_sm`); Norwegian names are caught\n  most reliably via `personal.txt`. For better NER, install `en_core_web_lg` into\n  the venv and swap the model name in `sweep.py`.\n- National-ID detection is checksum-based (python-stdnum); some countries' IDs\n  have weak validation, so verify before acting.\n\n## License\n\nMIT — see [LICENSE](LICENSE). Use at your own risk, and only scan repos you own\nor are authorised to access.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F26zl%2Fleak-sweep","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F26zl%2Fleak-sweep","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F26zl%2Fleak-sweep/lists"}