detect

package
v0.8.0 Latest Latest
Warning

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

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

Documentation

Overview

Package detect finds credentials in arbitrary byte content and knows, per provider, how to verify and revoke them.

The scan is built for throughput: every provider does a handful of SIMD-accelerated substring searches for its fixed token prefixes followed by an exact shape check and, where the format allows it, an offline checksum. A well-formed string with a wrong checksum is not a token; that single check removes the false positives a regex scanner has to live with.

The shared vocabulary lives here: Kind, Token, Verification and the Provider interface. The providers themselves are sub-packages, assembled into a Registry by package providers.

Index

Constants

View Source
const UserAgent = "patty"

UserAgent identifies patty to the provider APIs.

Variables

This section is empty.

Functions

func All added in v0.5.0

func All(b []byte, ok func(byte) bool) bool

All reports whether every byte of b satisfies ok. The empty slice does.

func AlnumAt added in v0.5.0

func AlnumAt(content []byte, i int) bool

AlnumAt reports whether content has an alphanumeric byte at i; false past the end. Used to reject candidates that continue into a longer word.

func Base64URLAt added in v0.8.0

func Base64URLAt(content []byte, i int) bool

Base64URLAt reports whether content has a URL-safe base64 byte at i; false past the end. Used to reject candidates that continue into a longer key.

func Do added in v0.5.0

func Do(client *http.Client, req *http.Request) (*http.Response, error)

Do sends the request with patty's User-Agent set.

func Fingerprint

func Fingerprint(value string) string

Fingerprint returns the fingerprint of a raw token value.

func HintMatches added in v0.8.0

func HintMatches(hint, value string) bool

HintMatches reports whether a partially redacted credential, the head and tail of the value around an ellipsis as providers list their keys (`sk-ant-api03-R2D…igAA`, `sk-abc...def`), fits the full value. A hint without an ellipsis or without a tail never matches: the head alone is usually just the prefix every key shares.

func IsAlnum added in v0.5.0

func IsAlnum(c byte) bool

IsAlnum reports whether c is an ASCII letter or digit.

func IsBase64URL added in v0.8.0

func IsBase64URL(c byte) bool

IsBase64URL reports whether c is in the URL-safe base64 alphabet, which most API keys are made of.

func IsDigit added in v0.5.0

func IsDigit(c byte) bool

IsDigit reports whether c is an ASCII digit.

func IsHex added in v0.5.0

func IsHex(c byte) bool

IsHex reports whether c is a lower- or upper-case hexadecimal digit.

func ReadBody added in v0.5.0

func ReadBody(r io.Reader, limit int64) []byte

ReadBody reads at most limit bytes of a response body.

func Redact

func Redact(value string) string

Redact hides the middle of a credential, keeping enough of both ends to recognise it (`ghp_AbCd…WxYz`). A URL keeps its path up to the last segment, which is the secret part of a webhook (`https://…/T…/B…/Ab…Yz`).

func Span added in v0.5.0

func Span(content []byte, start, limit int, ok func(byte) bool) int

Span returns the length of the run of bytes starting at content[start] that satisfy ok, at most limit bytes.

func WordBefore added in v0.8.0

func WordBefore(content []byte, i int) bool

WordBefore reports whether the byte before position i continues a word into the candidate: a letter, digit or underscore. False at the start.

Types

type Configurable added in v0.8.0

type Configurable interface {
	Configure(env func(string) string)
}

Configurable is a Provider that takes operator configuration from the environment: a privileged credential of the operator's own, such as an organization's admin key, that lets the provider revoke credentials its API would otherwise only accept as callers. Configure runs once, before the provider joins a Registry, so Kinds may depend on what is configured.

type Correlator added in v0.7.0

type Correlator interface {
	// Observe returns the identifiers under which content names credentials
	// of this provider (the recipients an encrypted file lists), or nil when
	// the object is of no interest. It runs on every scanned object and has
	// to be cheap; it must not keep a reference to content.
	Observe(content []byte) []string
	// Identifiers returns what the credential is known as in such content:
	// the public key of an identity. The scan matches them against what
	// Observe reported.
	Identifiers(tok Token) []string
}

Correlator is a Provider whose credentials unlock content that may sit in the scanned repositories themselves: an age identity decrypts every sops file encrypted to its recipient. The scan shows it every object and asks afterwards what each credential opens, so the report can say how much a leak is worth.

type DryRunRevoker added in v0.5.0

type DryRunRevoker interface {
	DryRunRevoke(ctx context.Context, tok Token) error
}

DryRunRevoker is a Provider whose revocation endpoint can rehearse a revocation: it answers as it would for the real request without revoking anything. patty uses it to preview a revocation before asking for confirmation.

type Kind

type Kind string

Kind names one credential family of one provider, such as a classic GitHub personal access token or a Slack bot token.

type KindInfo added in v0.5.0

type KindInfo struct {
	Kind Kind
	// Description is the human name: "personal access token (classic)".
	Description string
	// Revocable reports whether the provider's revocation endpoint accepts this kind.
	Revocable bool
	// RevokePage is where the owner revokes a credential of this kind by hand.
	RevokePage string
	// RevokeNote is added to the manual revocation advice when the API cannot
	// revoke the kind: what to check instead, or why it does not matter.
	RevokeNote string
	// RevokeEffect names a side effect of revoking through the API that is
	// easy to miss. The placeholder {app} stands for the issuing application.
	RevokeEffect string
	// AuditNote says how to find out whether a leaked credential of this kind
	// was used while it was exposed, and what the provider does on its own
	// when it spots the leak. Shown for every finding, revoked or not.
	AuditNote string
	// UnlocksLabel labels the advice line that lists what a credential of
	// this kind opens in the scanned repositories ("decrypts"). Set only for
	// the kinds of a Correlator.
	UnlocksLabel string
	// UnlocksNone is that line when nothing scanned names the credential.
	UnlocksNone string
}

KindInfo describes one credential family.

type LocalSources added in v0.5.0

type LocalSources struct {
	// Env lists environment variables tools read the credential from.
	Env []string
	// EnvFiles lists environment variables whose value is the path of a
	// file holding the credential.
	EnvFiles []string
	// ConfigFiles are relative to the XDG config directory (~/.config).
	ConfigFiles []string
	// HomeFiles are relative to the home directory.
	HomeFiles []string
	// Commands print a credential to stdout, such as `gh auth token`.
	Commands [][]string
}

LocalSources names where a provider's credentials are configured on the machine running patty. Paths may contain globs.

type Provider added in v0.5.0

type Provider interface {
	// Name is how the provider is called in reports: "GitHub", "Slack".
	Name() string
	// Kinds describes every credential family the provider detects.
	Kinds() []KindInfo
	// Find returns every credential of this provider in content. Offsets
	// are set; line numbers are filled in by the Registry.
	Find(content []byte) []Token
	// Verify asks the provider whether the credential is still accepted.
	// Only the provider's explicit invalid-credentials answer is reported as
	// revoked; anything else that is not a clean acceptance is unknown.
	Verify(ctx context.Context, tok Token) Verification
	// Revoke asks the provider to revoke the given credentials. A nil error
	// means every request was accepted; the caller confirms the outcome with
	// Verify.
	Revoke(ctx context.Context, tokens []Token) error
	// LocalSources lists where tools keep this provider's credentials on a
	// developer machine.
	LocalSources() LocalSources
}

Provider is one credential issuer: it knows the token formats it hands out, how to ask whether one is still live, and how to revoke it.

A provider never stores or logs a token value, and never contacts its API from Find.

func Configure added in v0.8.0

func Configure(env func(string) string, providers ...Provider) []Provider

Configure hands every provider that takes operator configuration the environment to read it from, and returns the providers for NewRegistry.

type Registry added in v0.5.0

type Registry struct {
	// contains filtered or unexported fields
}

Registry is the set of providers a scan looks for. It dispatches by Kind and merges the providers' findings into one offset-ordered list.

func NewRegistry added in v0.5.0

func NewRegistry(providers ...Provider) *Registry

NewRegistry builds a registry from providers, in report order.

func (*Registry) Correlators added in v0.7.0

func (r *Registry) Correlators() []Correlator

Correlators returns the registered providers that relate their credentials to the content they unlock, in order.

func (*Registry) Find added in v0.5.0

func (r *Registry) Find(content []byte) []Token

Find returns every credential of every provider in content, sorted by offset, with line numbers filled in.

func (*Registry) Info added in v0.5.0

func (r *Registry) Info(kind Kind) KindInfo

Info describes the kind; the zero KindInfo for an unknown one.

func (*Registry) Provider added in v0.5.0

func (r *Registry) Provider(kind Kind) Provider

Provider returns the provider that issues credentials of this kind, or nil.

func (*Registry) ProviderName added in v0.5.0

func (r *Registry) ProviderName(kind Kind) string

ProviderName returns the name of the provider of this kind, or "".

func (*Registry) Providers added in v0.5.0

func (r *Registry) Providers() []Provider

Providers returns the registered providers in order.

func (*Registry) Revocable added in v0.5.0

func (r *Registry) Revocable(kind Kind) bool

Revocable reports whether the kind's provider revokes it through its API.

func (*Registry) RevokePage added in v0.5.0

func (r *Registry) RevokePage(kind Kind) string

RevokePage is where the owner revokes a credential of this kind by hand.

func (*Registry) Verify added in v0.5.0

func (r *Registry) Verify(ctx context.Context, tok Token) Verification

Verify dispatches to the token's provider.

type Token

type Token struct {
	Kind  Kind
	Value string
	// Offset is the byte offset of the token in the scanned content.
	Offset int
	// Line is the 1-based line the token starts on.
	Line int
	// ChecksumVerified reports whether the token carries a checksum that
	// was verified offline. Classic GitHub tokens do; every other format is
	// matched on shape alone.
	ChecksumVerified bool
	// Attribution is what the token's own shape says about its owner, without
	// contacting the provider: a team id in a Slack token, for example. Empty
	// when the format carries nothing of the sort.
	Attribution string
	// Secret is the material a credential needs besides Value when it is made
	// of several strings: the secret access key found next to an AWS key id,
	// and the session token of a temporary one. Its layout is the provider's
	// business. Value alone identifies the credential; Secret is never
	// printed, logged or fingerprinted.
	Secret string
}

Token is one credential found in scanned content.

func ScanPrefix added in v0.5.0

func ScanPrefix(found []Token, content []byte, prefix string, at func(start int) (Token, bool)) []Token

ScanPrefix finds every occurrence of prefix in content and calls at with its offset; at returns the token when the bytes there have the exact shape. Matches are appended to found.

func (Token) Fingerprint

func (t Token) Fingerprint() string

Fingerprint returns a short, stable, non-reversible identifier for the token value: the first 16 hex characters of its SHA-256. It is safe to put in logs and allow-lists.

type Verification

type Verification struct {
	Status VerifyStatus `json:"status"`
	// Detail describes what the credential gives access to: user and scopes,
	// the workspace of a Slack token, the number of repositories an
	// installation token reaches.
	Detail string `json:"detail,omitempty"`
	// ClientID is the id of the application the credential was issued to,
	// when the provider reports one.
	ClientID string `json:"client_id,omitempty"`
	// App is the name of that application when patty knows the client id.
	App string `json:"app,omitempty"`
	// Expires is when the credential stops working, for credentials that expire.
	Expires string `json:"expires,omitempty"`
}

Verification is the result of Provider.Verify.

func (Verification) Issuer added in v0.2.0

func (v Verification) Issuer() string

Issuer names the application a credential was issued to: the known app name, else the raw client id, else "".

type VerifyStatus

type VerifyStatus string

VerifyStatus is the outcome of checking a credential against its provider.

const (
	// StatusActive means the provider accepted the credential: it is live and must be revoked.
	StatusActive VerifyStatus = "active"
	// StatusRevoked means the provider explicitly rejected the credential as invalid.
	StatusRevoked VerifyStatus = "revoked"
	// StatusUnverifiable means the credential family cannot be checked without side effects.
	StatusUnverifiable VerifyStatus = "unverifiable"
	// StatusUnknown means the check could not be completed (network, rate
	// limit, an unexpected answer). It is never treated as proof of anything.
	StatusUnknown VerifyStatus = "unknown"
)

Directories

Path Synopsis
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.
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.
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.
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.
Package providers assembles the credential providers patty ships with.
Package providers assembles the credential providers patty ships with.
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.
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.

Jump to

Keyboard shortcuts

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