patty

command module
v0.13.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 13, 2026 License: MIT Imports: 3 Imported by: 0

README

patty

patty

Finds leaked GitHub, Slack, AWS, Anthropic, OpenAI, container registry and Kubernetes credentials, SSH, TLS and cosign private keys, and the keys that decrypt sops secrets, in every corner of a repository's history.
Marge's sister. Works at the DMV. Checks everyone's credentials.


A token that was committed once is in the repository forever -- even after the file was deleted, the commit amended, the branch force-pushed or the pull request closed. A normal clone does not show most of that history, and a scanner that walks git log --all never sees it. patty does: it mirrors the whole object database, pulls in what GitHub still holds but no ref points at anymore, and scans every object once.

It is fast enough to point at an entire organization. 210,000 objects and 6.7 GiB of content of prometheus/prometheus scan in about two seconds; the wall clock is the clone.

Install

Download a binary from the releases page (Linux, macOS, Windows; amd64 and arm64), or build from source:

go install github.com/teemow/patty@latest

patty drives git on the command line, so git 2.30 or newer has to be on the PATH.

Setup

For GitHub targets patty uses a token from GITHUB_TOKEN, GH_TOKEN, or the gh CLI (gh auth token), in that order. Without one it works anonymously: public repositories only, 60 API requests per hour.

Classic token: repo scope for private repositories, nothing for public ones.

Fine-grained token: select the repositories to scan, then grant:

Permission Access Why
Metadata Read List repositories, read sizes and the activity feed
Contents Read Clone private repositories

Anthropic and OpenAI keys: their APIs cannot revoke a key by itself. To let --revoke deactivate a leaked Anthropic API key or delete a leaked OpenAI key, set ANTHROPIC_ADMIN_KEY to an Admin API key of the organization the leaked key belongs to, or OPENAI_ADMIN_KEY to an admin key of that organization. With one configured, --verify also names each key the way the Console does (name, workspace or project, creator), and --revoke deactivates only keys the organization's own key list confirms as its own; a key from another organization is reported as such. Without one, the report says where to revoke by hand. Detection and --verify need no admin key.

Google Cloud: the file GOOGLE_APPLICATION_CREDENTIALS names, CLOUDSDK_AUTH_ACCESS_TOKEN, and the credential files gcloud writes under ~/.config/gcloud are read locally, so the report can say that a leaked service account key or refresh token is still configured on this machine; only fingerprints are compared, and gcloud's credentials.db is not opened. Revoking a Google OAuth token with --revoke signs out every tool that shares its grant, gcloud included.

The tokens patty finds never leave your machine unless you pass --verify or --revoke; see what leaves your machine.

Usage

patty .                          # the repository you are in, reflog and stashes included
patty acme/api acme/web          # two GitHub repositories
patty acme --verify              # everything acme owns; say which tokens are still live
patty acme --revoke              # ...and ask their providers to revoke the live ones, after confirmation
patty acme --json > leaks.json   # machine-readable report

A target is a local path, owner/repo, a github.com URL, or a bare owner (user or organization) to scan every repository of, private ones included when the token can see them. Exit code 0 means nothing was found, 1 that tokens were found, 2 that a target failed or was skipped and nothing was found.

patty --help lists every flag. The ones you will reach for:

  • --verify -- ask GitHub, Slack, AWS, Google Cloud, Azure, Anthropic, OpenAI, the registries and the API servers named in kubeconfigs which credentials are still active; --revoke then revokes those, after asking (--yes skips the question). API servers on private networks are only contacted with --verify-private-servers
  • --ignore fp,fp -- leave tokens you have already dealt with out of the report, by fingerprint or by kind (--ignore kubernetes-secret-manifest)
  • --keep -- keep mirrors in the cache so a re-run only fetches what changed; --max-disk and --min-free cap what the cache may use
  • --include-forks -- include forks when expanding an owner

Other commands: patty revoke for tokens you already have in hand, patty cache and patty cache clean for kept mirrors, patty self-update.

The report

2 credentials found (1 active) in 108 repositories, 82473 objects, 1.5 GiB

● ACTIVE     github-pat               ghp_2O6PWxYz…k3Lq  fp b492588d8d3ffbbb  user acme-bot, scopes: repo, workflow
    acme/dotfiles  .config/hub:4  2c10f8f4 2025-04-15 Jane Doe · initial commit
                   not on any branch or tag, only reachable through pull request refs: PR #1, PR #10, +11 more
    acme/lab       trials/run-7/messages.json:107  4048b6e8 2026-05-29 Jane Doe · record trial output
                   on main, +405 more
    ↳ revoke   at https://github.com/settings/tokens; or run again with --revoke
    ↳ local    still configured in ~/.config/hub; replace it there after revoking
    ↳ history  acme/dotfiles: only in pull request refs (GitHub Support has to purge those) · acme/lab: in branch history (rewrite with git filter-repo, then force-push)

● revoked    github-pat               ghp_jtP7Ab12…9zXy  fp 58b0d6ffe3821055
    acme/infra     cluster/apps/secret.sops.yaml:8  96a9ac2e 2026-01-05 Jane Doe · add training app
                   orphaned: no branch, tag or PR reaches this commit · force-pushed away from main on 2026-01-06 by jane

Each token is listed once with every place it was found, the oldest commit that introduced it, and how reachable that commit still is: on a branch, only through pull request refs, or orphaned by a force push. Active tokens come first, each with what to do about it: where to revoke it, whether it is still configured on this machine, and what its history needs. Reading the report explains every line, revoking and its side effects included.

How it works

  1. Mirror, not clone. git clone --mirror brings every ref GitHub advertises, including refs/pull/* and so the history of every pull request.
  2. Fetch what was rewritten. The repository activity feed names the commits that were force-pushed away or deleted; GitHub still serves them by SHA, so patty fetches them too.
  3. Scan objects, not diffs. Every blob, commit and tag in the object database is read exactly once, reachable or not, and checked for GitHub tokens, Slack tokens and webhooks, AWS access keys, Anthropic and OpenAI API keys, the registry logins in Docker configs and pull secrets (base64 layers included) and Docker Hub and Quay tokens, the client certificates, tokens and logins of kubeconfigs and Kubernetes service account tokens, SSH, TLS and cosign private keys, and the age identities and PGP keys that decrypt sops secrets. The values of every Kubernetes Secret manifest are decoded and searched for all of them, and a Secret committed in the clear is reported on its own. Classic GitHub tokens and age identities are confirmed against their built-in checksum, so a lookalike in a test fixture is not reported; an AWS key id names the account it belongs to without asking AWS, a sops identity comes with the list of encrypted files in the scanned repositories it opens, and a private key with the certificate, authorized_keys, image policy or GitHub account that trusts its public half.
  4. Attribute afterwards. Only for objects that contain a token does patty look up the path, the introducing commit, and the refs that still contain it.

Mirrors live in a size-capped cache and are removed after the scan unless --keep is set, so pointing patty at an organization never fills a drive. How patty works has the details, the token families it detects, and a comparison with gitleaks.

Development

make build          # Build the binary
make test           # Run tests (needs git on the PATH)
make lint           # Run golangci-lint
make help           # Show all available targets

Test tokens are constructed at runtime -- classic GitHub tokens from a random part plus a computed checksum, Slack tokens from their id groups and secret, AWS key ids from a prefix and a base32 body, Anthropic and OpenAI keys from a random body plus their fixed prefix, suffix or marker, Docker configs and pull secrets encoded on the fly, age identities and PGP keys freshly generated -- so no token-shaped string is committed to this repository.

License

MIT -- see LICENSE for details.

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis
Package cmd wires the patty command line.
Package cmd wires the patty command line.
internal
detect
Package detect finds credentials in arbitrary byte content and knows, per provider, how to verify and revoke them.
Package detect finds credentials in arbitrary byte content and knows, per provider, how to verify and revoke them.
detect/anthropic
Package anthropic is the Anthropic credential provider: API keys, Admin API keys, and the OAuth access and refresh tokens Claude Code signs in with.
Package anthropic is the Anthropic credential provider: API keys, Admin API keys, and the OAuth access and refresh tokens Claude Code signs in with.
detect/aws
Package aws is the AWS credential provider: the access keys of IAM users and the temporary access keys STS hands out.
Package aws is the AWS credential provider: the access keys of IAM users and the temporary access keys STS hands out.
detect/azure
Package azure is the Microsoft Azure credential provider: the client secrets of Entra ID applications (service principals), storage account keys, and shared access signatures.
Package azure is the Microsoft Azure credential provider: the client secrets of Entra ID applications (service principals), storage account keys, and shared access signatures.
detect/gcp
Package gcp is the Google Cloud credential provider: service account keys, the application default credentials of a signed-in user, the OAuth access and refresh tokens they produce, and API keys.
Package gcp is the Google Cloud credential provider: service account keys, the application default credentials of a signed-in user, the OAuth access and refresh tokens they produce, and API keys.
detect/github
Package github is the GitHub credential provider: classic and fine-grained personal access tokens, OAuth and GitHub App tokens.
Package github is the GitHub credential provider: classic and fine-grained personal access tokens, OAuth and GitHub App tokens.
detect/jwt
Package jwt reads JSON Web Tokens without verifying them.
Package jwt reads JSON Web Tokens without verifying them.
detect/kubernetes
Package kubernetes is the provider for the credentials that reach a Kubernetes API server: the client certificates, bearer tokens and basic auth logins a kubeconfig carries, service account tokens wherever they turn up, and Secret manifests committed with their values in the clear.
Package kubernetes is the provider for the credentials that reach a Kubernetes API server: the client certificates, bearer tokens and basic auth logins a kubeconfig carries, service account tokens wherever they turn up, and Secret manifests committed with their values in the clear.
detect/openai
Package openai is the OpenAI credential provider: project, service account, admin and legacy user API keys.
Package openai is the OpenAI credential provider: project, service account, admin and legacy user API keys.
detect/privatekey
Package privatekey is the provider for private keys committed as PEM blocks: SSH keys, the keys behind TLS certificates and other PKCS#8 or legacy PEM material, and the encrypted signing keys cosign writes.
Package privatekey is the provider for private keys committed as PEM blocks: SSH keys, the keys behind TLS certificates and other PKCS#8 or legacy PEM material, and the encrypted signing keys cosign writes.
detect/providers
Package providers assembles the credential providers patty ships with.
Package providers assembles the credential providers patty ships with.
detect/registry
Package registry is the provider for OCI and Docker registry credentials: the logins a Docker config keeps per registry, wherever that config is embedded (a config.json, a Kubernetes pull secret, Helm values, a Basic Authorization header aimed at a registry), and the native tokens of Docker Hub and Quay.
Package registry is the provider for OCI and Docker registry credentials: the logins a Docker config keeps per registry, wherever that config is embedded (a config.json, a Kubernetes pull secret, Helm values, a Basic Authorization header aimed at a registry), and the native tokens of Docker Hub and Quay.
detect/slack
Package slack is the Slack credential provider: bot, user, app-level, refresh and configuration tokens, and incoming webhook URLs.
Package slack is the Slack credential provider: bot, user, app-level, refresh and configuration tokens, and incoming webhook URLs.
detect/sops
Package sops is the provider for the identities that decrypt sops-managed secrets: age identities and PGP private keys.
Package sops is the provider for the identities that decrypt sops-managed secrets: age identities and PGP private keys.
disk
Package disk keeps patty's clone cache within a byte budget and off the last free gigabytes of the drive.
Package disk keeps patty's clone cache within a byte budget and off the last free gigabytes of the drive.
github
Package github talks to the GitHub API: repository discovery, size estimates for the disk budget and the activity feed that names commits a clone can no longer see.
Package github talks to the GitHub API: repository discovery, size estimates for the disk budget and the activity feed that names commits a clone can no longer see.
gitrepo
Package gitrepo drives git plumbing for a repository patty scans.
Package gitrepo drives git plumbing for a repository patty scans.
localcreds
Package localcreds finds the credentials configured on this machine, so a report can say that a leaked token is not just out there but still in use right here.
Package localcreds finds the credentials configured on this machine, so a report can say that a leaked token is not just out there but still in use right here.
report
Package report renders scan results for terminals and machines.
Package report renders scan results for terminals and machines.
scan
Package scan runs the detector over every object of a repository and attributes what it finds to commits, paths and refs.
Package scan runs the detector over every object of a repository and attributes what it finds to commits, paths and refs.
source
Package source turns command line arguments into scan targets: local repositories, single GitHub repositories, or every repository of a user or organization.
Package source turns command line arguments into scan targets: local repositories, single GitHub repositories, or every repository of a user or organization.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL