Documentation
¶
Overview ¶
This file implements the contextual detectors: credentials that are identified by WHERE they appear (an HTTP Authorization header, a Cookie/Set-Cookie header, the userinfo component of a URL, a CLI password/token flag) rather than by a provider-specific token shape (validators.go et al.) or a bare key=value assignment (generic.go); assignments are deliberately not duplicated here.
All four validators redact ONLY the credential value: header names, URL scheme/host/path structure, cookie names, and flag names are always preserved byte for byte.
Escaped/embedded header lines ¶
Log pipelines frequently embed raw header lines inside JSON strings (`{"line":"\"authorization: bearer abc...\""}`). The case-folded triggers still hit inside such strings, so every value alphabet here deliberately excludes '"' and '\\': a value terminated by an escaped closing quote (`...abc\"`) simply ends at the backslash instead of swallowing the JSON framing.
Cookie multi-pair design tension ¶
A ValidateFunc returns exactly one span, but one Cookie header can carry several credential-bearing pairs. Returning one wide span from the first to the last qualifying value would over-redact the benign pairs between them, and the `cookie:` trigger fires only once per header no matter how many pairs follow. The resolution used by cookie-session-token: the header trigger (`cookie:` / `set-cookie:`) confirms the FIRST qualifying pair's value, and the rule additionally registers the qualifying pair names themselves (`session=`, `sid=`, `token=`, `jwt=`, `auth=`) as triggers, so each qualifying pair produces its own trigger occurrence and therefore its own span. The Aho-Corasick matcher reports every occurrence of every literal, so a header with three token-bearing pairs gets three pair-trigger hits even though `cookie:` hits once. To keep those weak pair literals from firing on arbitrary key=value text (which the generic assignment rules already cover), the pair-trigger path demands cookie context: the literal "ookie" (Cookie:/Set-Cookie:, however cased) somewhere in the lookbehind, or an immediately preceding `;`-separated pair boundary. When that context is absent the pair path reports no match.
This file implements CI/devops provider credential validators: CircleCI personal/project API tokens, Buildkite API access tokens, Datadog API and Application keys, Grafana service-account and cloud-access-policy tokens, Doppler tokens, and Vercel access tokens. Each function follows the same contract as the seed validators in validators.go: pure, panic-free functions of window that report a window-relative half-open span to redact.
Several of these providers (Buildkite, Datadog, and legacy Vercel tokens) issue bare fixed-length alphanumeric/hex values with no in-token prefix at all — the same shape as a git commit SHA or an MD5 hash. Per docs/RULE_AUTHORING.md, a generic value shape like that needs additional context to be a safe deterministic rule, so these are implemented as contextual assignments keyed on the provider's own documented environment-variable name (the same design AWSSecretAccessKey, cloud.go, already uses for AWS's equally prefix-less secret access key).
CircleCI and Vercel each still have an older, bare, prefix-less token format in circulation (a 40-character hex string for CircleCI, a 24-character alphanumeric string for legacy Vercel). CircleCI's legacy format has no distinguishing context at all — the exact same shape as a git SHA-1 and, separately, a Buildkite token — so it is deliberately not matched here rather than risk a high false-positive rule; Vercel's legacy format is covered by VercelLegacyToken below since it does have a well-documented env var to key off.
This file implements the generic contextual credential rules: heuristic ValidateFuncs that fire on assignment-style context around keyword triggers like "api_key", "password", or "token" (as opposed to the deterministic provider-specific validators in validators.go, which confirm exact known token shapes). Header/URL/cookie contexts are intentionally out of scope here and handled by contextual validators.
Parsing model ¶
All three validators share one parse: after the trigger, skip optional horizontal whitespace, skip one optional quote character (the trigger's own closing quote, for JSON-style quoted keys like "api_key": ...), skip optional whitespace again, require an assignment separator ("=", ":", or "=>"), skip optional whitespace again, then capture a value:
- If the next byte is a quote character (double quote, single quote, or backtick) — optionally itself escaped with a leading backslash (the case where an already-quoted string is embedded in a further layer of escaping, e.g. JSON embedded in a log line) — the value runs until the matching quote (or matching escaped-quote sequence, if the opening quote was itself escaped) and is captured without the quotes.
- Otherwise the value is the maximal run of printable, non-space bytes, stopping at whitespace or one of the printable separators comma, semicolon, closing brace, or a stray quote character.
This is deliberately not a full unescaping parser: a value containing an actual backslash-escaped instance of its own delimiting quote (e.g. a JSON string value that itself contains \") will be truncated at that inner escape rather than continuing past it. That is an accepted simplification — the truncated prefix is still fed through entropy.Secretlike and, being shorter, is if anything less likely to pass, which is the conservative failure direction for a redaction tool.
The trigger's preceding byte is also checked (isTriggerBoundaryOK): triggers are rejected when immediately preceded by an alphanumeric byte, so "x_api_key=" still fires (preceded by '_', non-alnum) but "capi_key=" does not (preceded by 'c', alnum) — the trigger must not be a suffix of a longer identifier.
False-positive budget ¶
FalsePositiveBudgetPerTenMiB documents the accuracy target these balanced-profile rules are tuned against. It is enforced empirically by the accuracy corpus harness, not by any check in this package; the constant exists so that harness (and this file's authors) have one canonical number to reference and keep in sync.
This file implements generic-secret-assignment, the one deep-profile- only heuristic rule this codebase ships as of this writing. It exists to give the deep profile a real meaning distinct from balanced (see docs/PROFILES.md): balanced's three generic contextual rules in generic.go are deliberately tuned to a tight keyword list (api_key, secret_key, password, token, ...) to keep their false-positive rate low enough for a default profile. This rule widens that keyword surface to bare, generic words — "key", "secret", "auth", "access", "credential", "creds" — the same broader anchor set gitleaks' and betterleaks' own "generic-api-key" rule uses (confirmed directly against both projects' source: neither is actually keyword-free, despite sometimes being described that way — both require one of that same broad keyword set followed eventually by an assignment operator).
That broader surface catches real assignments balanced's specific keywords structurally cannot, e.g. "AWS Secret Key = ..." or "Client Auth Token: ..." contain no literal "secret_key" or "auth_token" substring. It also fires on far more ordinary, non-secret text (English prose containing "key"/"auth"/"access", source identifiers like "keyboard_layout" or "author"), so it is deliberately confined to the deep profile and paired with a stricter entropy bar (entropy.PresetDeepGenericValue) than any balanced-profile generic rule uses.
This file implements two JWT-based detectors sharing one parser: the standalone JWT detector (a bare JWS compact serialization, header.payload.signature, anywhere in the input with no surrounding context required) and the Supabase service-role key detector (the same shape, additionally requiring a `"role":"service_role"` claim in the decoded payload — the claim Supabase bakes into its highest-privilege API key, the one Postgres treats as bypassing row-level security). Contextual occurrences (Authorization headers, cookies) are also caught by the contextual rules; these rules exist for the bare tokens those rules cannot see — JWTs pasted into agent transcripts, log lines, and tool output.
The shape enforced here follows the betterleaks standalone-JWT rule (both the header and the payload segment must begin with "ey" — the base64 encoding of "{" — which is what keeps the false-positive rate low on eyJ-heavy auth-debugging transcripts), tightened to the base64url alphabet RFC 7515 actually specifies for the two JSON segments.
Validators for payments, messaging, and project-management provider credentials: Stripe, Slack (user/app tokens — bot tokens are the pre-existing SlackBotToken in validators.go), SendGrid, Twilio, Linear, and Notion.
All functions here follow the same contract as validators.go: pure, window-relative, byte-only, never panic regardless of how the window is truncated relative to the trigger or the rule's configured lookaround.
Source-control and package-registry credential validators: GitHub (OAuth, App, refresh, and fine-grained PAT), GitLab (PAT, runner, and deploy tokens), npm, PyPI, and Docker Hub. The classic GitHub PAT validator (GitHubPAT, trigger "ghp_") already lives in validators.go and is not duplicated here.
These share two shapes:
- prefix + a fixed-length run of ASCII alphanumeric characters (GitHub OAuth/App/refresh tokens, npm access tokens): see fixedAlnumToken.
- prefix + a variable-length run of a wider token alphabet ([A-Za-z0-9_-]) bounded by a min/max length (GitLab PAT/runner/ deploy tokens, PyPI API tokens, Docker Hub PATs): see runToken.
GitHubFineGrainedPAT is the one irregular shape (two fixed-length alnum runs separated by a literal underscore) and is implemented directly.
Package validators holds the ValidateFunc implementations referenced by the generated built-in rule tables (internal/rules/zz_generated_rules.go).
Every function here has the signature
func(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
as required by rules.ValidateFunc: window is the bounded slice of bytes around a trigger occurrence (trigger occupies window[trigStart:trigEnd]), and the function reports the half-open span within window to redact. Implementations here are pure functions of window: no I/O, no logging, and no retention of window past the call. They must never panic or index out of range, regardless of how short window is relative to the trigger or the rule's configured lookahead — callers may hand them a window truncated at a chunk or input boundary.
This package currently holds two seed validators (GitHubPAT, SlackBotToken) that prove the spec-to-generated-code pipeline end to end. Additional files in this package provide the full validator catalog.
Index ¶
- Constants
- func AWSAccessKeyID(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func AWSBedrockLongLivedAPIKey(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func AWSBedrockShortLivedAPIKey(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func AWSSecretAccessKey(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func AnthropicAPIKey(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func AuthorizationHeader(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func AzureAppConfigurationSecret(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func AzureServiceBusSASKey(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func AzureStorageAccountKey(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func BuildkiteAPIToken(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func CerebrasAPIKey(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func CircleCIToken(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func CohereAPIKey(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func CommandLinePasswordFlag(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func CookieSessionToken(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func CursorAPIKey(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func DatadogAPIKey(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func DatadogApplicationKey(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func DeepSeekAPIKey(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func DeepgramAPIKey(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func DockerHubOAT(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func DockerHubPAT(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func DopplerToken(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func GCPAPIKey(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func GenericAPIKeyAssignment(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func GenericBearerLikeTokenAssignment(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func GenericPasswordAssignment(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func GenericSecretAssignment(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func GitHubAppToken(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func GitHubFineGrainedPAT(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func GitHubOAuthToken(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func GitHubPAT(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func GitHubRefreshToken(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func GitLabDeployToken(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func GitLabFeedToken(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func GitLabFeedTokenV2(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func GitLabPAT(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func GitLabPipelineTriggerToken(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func GitLabRunnerToken(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func GrafanaCloudAccessPolicyToken(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func GrafanaServiceAccountToken(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func GroqAPIKey(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func HuggingFaceToken(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func JWT(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func LinearAPIKey(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func NotionInternalToken(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func NpmAccessToken(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func OpenAILegacyKey(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func OpenAIProjectKey(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func PEMPrivateKey(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func PEMPrivateKeyBegin(window []byte, trigStart, trigEnd int, final bool) (start, end int, state uint64, open, ok bool)
- func PEMPrivateKeyExtend(window []byte, state uint64, final bool) (end int, next uint64, open bool)
- func PuTTYPrivateKey(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func PuTTYPrivateKeyBegin(window []byte, trigStart, trigEnd int, final bool) (start, end int, state uint64, open, ok bool)
- func PuTTYPrivateKeyExtend(window []byte, state uint64, final bool) (end int, next uint64, open bool)
- func PyPIAPIToken(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func SendGridAPIKey(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func SlackAppToken(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func SlackBotToken(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func SlackUserToken(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func StripeEphemeralKey(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func StripeSecretKey(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func StripeWebhookSecret(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func SupabaseServiceRoleKey(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func TerraformCloudAPIToken(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func TwilioAPIKeySID(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func URLCredentials(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func VaultBatchToken(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func VaultServiceToken(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func VercelLegacyToken(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
- func VercelToken(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
Constants ¶
const FalsePositiveBudgetPerTenMiB = 1
FalsePositiveBudgetPerTenMiB is the accuracy target for the balanced- profile generic contextual rules in this file: fewer than this many false-positive redactions per 10 MiB of ordinary keyword-dense log and config data (the kind of text where "password", "token", "api_key" etc. appear constantly without carrying an actual secret value). The accuracy corpus harness measures against this number; it is not self-enforcing at build or test time.
Variables ¶
This section is empty.
Functions ¶
func AWSAccessKeyID ¶
AWSAccessKeyID confirms the AWS access key ID shape: one of the AKIA/ASIA/ABIA/ACCA triggers followed by exactly 16 RFC-4648 upper-base32 characters, bounded on both sides by a byte that is not an uppercase letter or digit (or the edge of window). It rejects AWS's own documentation placeholder ("AKIAIOSFODNN7EXAMPLE") and, more generally, any key whose 16-character body ends with "EXAMPLE", which real access key IDs never do.
func AWSBedrockLongLivedAPIKey ¶
AWSBedrockLongLivedAPIKey confirms the Amazon Bedrock long-lived API key shape: the fixed trigger "ABSKQmVkcm9ja0FQSUtleS", followed by 91-251 further characters of standard base64 and up to two '=' padding characters — the base64 encoding of a structured "BedrockAPIKey-<id>-at-<account-id>:<secret>" payload that AWS accepts in place of SigV4 credentials for calling Bedrock's model-invocation APIs.
https://docs.aws.amazon.com/bedrock/latest/userguide/api-keys.html https://github.com/awslabs/git-secrets (canonical AWS-maintained detection pattern)
func AWSBedrockShortLivedAPIKey ¶
AWSBedrockShortLivedAPIKey confirms the Amazon Bedrock short-lived API key shape: the fixed trigger "bedrock-api-key-YmVkcm9jay5hbWF6b25hd3MuY29t", followed by 20-4096 further characters of standard base64 and up to two '=' padding characters.
https://docs.aws.amazon.com/bedrock/latest/userguide/api-keys.html https://github.com/aws/aws-bedrock-token-generator-js (canonical AWS-maintained token construction) https://github.com/awslabs/git-secrets (canonical AWS-maintained detection pattern)
func AWSSecretAccessKey ¶
AWSSecretAccessKey confirms the shape of a value assigned to an aws_secret_access_key key (the trigger is matched case-insensitively, so this also fires on AWS_SECRET_ACCESS_KEY): optional spaces/tabs, a '=' or ':' separator (optionally preceded by a JSON-style closing quote), optional spaces/tabs, an optional opening quote, exactly 40 characters of [A-Za-z0-9/+=], a matching closing quote if one was opened, and a boundary. Only the 40-character value is reported as the redaction span — the key name itself is never touched. It rejects an all-identical value and the well-known AWS documentation placeholder secret.
func AnthropicAPIKey ¶
AnthropicAPIKey confirms the Anthropic API key shape: trigger "sk-ant-" followed by 80-130 bytes of [A-Za-z0-9_-] (this covers both the common "api03-"/"admin01-"-style sub-segment plus the ~80-120 character body, since that sub-segment's own alphabet is a subset of the body's, and the literal "sk-ant-" prefix's total post-prefix length is what's actually bounded). Real Anthropic keys are never shorter than ~100 characters after the prefix; the 80 floor rejects the short fabricated "sk-ant-api03-<32-40 chars>" keys that dominate documentation and test fixtures. It also rejects placeholder bodies (all one character, or any long repeated run) and requires a non-alphanumeric byte (or end of window) on both sides.
func AuthorizationHeader ¶
AuthorizationHeader confirms a credential in an Authorization: or Proxy-Authorization: header (the triggers include the colon and are case-folded). Per-scheme behavior, kept deliberately small:
- Bearer / Token (case-insensitive): the value is the following run of token68 bytes (see isAuthTokenChar). It must be at least authBearerMinLen bytes and not an isPlaceholder value; pure template refs ("${...}") and angle-bracket placeholders ("<token>") never even parse, since '$', '{', '<' are outside the value alphabet, leaving an empty (rejected) value.
- Basic: the value is the following run of base64 bytes, at least authBasicMinLen long. No placeholder/entropy check: a well-formed base64 credential pair in this position is always sensitive.
- Any other scheme (Digest, AWS4-HMAC-SHA256, ...): conservative. If the rest of the line contains a case-sensitive "Signature=" (AWS SigV4), only that parameter's value token is redacted. Otherwise, if the rest of the line mentions "password" (case-insensitive), the whole parameter blob up to end of line is redacted (over-redaction of an explicitly password-bearing header is the safe direction). Otherwise there is no match — a plain Digest challenge/response never fires.
Only the credential value (or parameter blob) is redacted, never the header name or scheme word.
func AzureAppConfigurationSecret ¶
AzureAppConfigurationSecret confirms the shape of the value following a "Secret=" trigger (matched case-insensitively) in an App Configuration connection string ("Endpoint=...;Id=...;Secret=..."). This is the classic 32-byte base64 key shape; a longer, unpadded variant has been observed for some App Configuration secrets but is not yet documented by Microsoft, so it is deliberately not matched here rather than guessed at.
func AzureServiceBusSASKey ¶
AzureServiceBusSASKey confirms the shape of the value following a "SharedAccessKey=" trigger (matched case-insensitively). Service Bus, Event Hubs, and Relay namespaces all share this one SAS mechanism under an identical "sb://...servicebus.windows.net" connection-string grammar — the connection string alone cannot distinguish which of the three issued a given key, so this rule covers all of them.
https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-sas https://learn.microsoft.com/en-us/azure/event-hubs/event-hubs-get-connection-string
func AzureStorageAccountKey ¶
AzureStorageAccountKey confirms the shape of the value following an "AccountKey=" trigger (matched case-insensitively): 86-88 characters of A-Za-z0-9/+ followed by the literal "==" padding of a standard 64-byte base64-encoded blob, bounded by a byte that cannot extend the base64 run or its padding (a ';' commonly follows in an Azure connection string, which already satisfies this boundary). If the base64 run reaches the end of window before the "==" padding can be confirmed, the match is rejected outright rather than guessing at what a truncated window might have contained. It rejects a placeholder body, mirroring azureShortBase64Secret below.
func BuildkiteAPIToken ¶
BuildkiteAPIToken confirms the shape of a value assigned to BUILDKITE_API_TOKEN or BUILDKITE_AGENT_TOKEN (matched case-insensitively, the officially documented environment variable names for Buildkite's REST API token and agent registration token respectively): 40 characters of lowercase hex. Buildkite tokens have no fixed prefix of their own — identical in shape to a git SHA-1 hash — so this rule exists specifically for the documented variable-name context, per the file-level note above.
https://buildkite.com/docs/apis/managing-api-tokens https://buildkite.com/docs/agent/v3/tokens
func CerebrasAPIKey ¶
CerebrasAPIKey confirms the Cerebras API key shape: trigger "csk-" followed by 32-64 alphanumeric characters.
Cerebras does not publish a format spec on any source reachable during development: no gitleaks or TruffleHog detector exists for it, and inference-docs.cerebras.ai itself was unreachable. The "csk-" prefix and a 32-character example body come from several independent third-party integration guides that converge on the same placeholder shape ("csk-1234567890abcdef1234567890abcdef"), not from Cerebras's own docs, which show only a generic "your-api-key-here" placeholder. This should be re-verified against inference-docs.cerebras.ai/api-reference/authentication when reachable.
func CircleCIToken ¶
CircleCIToken confirms the current CircleCI personal/project API token shape: trigger "CCIPAT_" (personal) or "CCIPRJ_" (project), followed by a 20-24 character base58 UUID segment, a literal '_', and a fixed 40-character lowercase hex segment. CircleCI's older bare 40-character hex tokens (personal and project tokens were the same shape) are not matched by any rule here: that shape has no distinguishing context at all, identical to a git SHA-1 hash or a Buildkite token, so a deterministic rule for it would carry an unacceptable false-positive rate.
https://circleci.com/changelog/new-format-for-api-access-tokens https://circleci.com/docs/managing-api-tokens/
func CohereAPIKey ¶
CohereAPIKey confirms the shape of a value assigned to CO_API_KEY or COHERE_API_KEY (matched case-insensitively; CO_API_KEY is the keyword gitleaks' own "cohere-api-token" rule keys on): 40 characters of mixed-case alphanumeric. Cohere's key has no prefix of its own — a bare 40-character token, the same shape as many unrelated opaque or hex identifiers — so this rule is keyed on the documented variable name instead, the same design AWSSecretAccessKey (cloud.go) already uses for AWS's equally prefix-less secret access key.
func CommandLinePasswordFlag ¶
CommandLinePasswordFlag confirms a secret passed to a CLI flag (--password, --passwd, --token, --api-key, --secret; case-folded). The short "-p " form is deliberately not a trigger — it is hopelessly false-positive-prone (-p is "port" as often as "password").
The byte immediately after the trigger must be '=' or horizontal whitespace: anything else means the flag name continues ("--password-file", "--token-url") and there is no match. The byte before the trigger must not be '-' or alphanumeric ("---password", "x--token" are not flags), except for a '-' that opens the line: that is the removal marker of a unified diff line ("-" + "--password=..."). A bare (unquoted) value must not start with '-': that is the next flag, not a value ("--password --prompt").
The value is either quoted (single/double/backtick, tolerating a backslash-escaped opening quote for JSON-embedded command lines, via the shared detectQuote/findQuotedEnd helpers) or a bare argument run. Placeholder and template-ref values are rejected via isPlaceholder. Password flags require only length >= cliPasswordMinLen; token/key/secret flags require length >= cliTokenMinLen AND entropy.PresetLooseToken, since their values are machine-generated and should look random. Only the value is redacted.
func CookieSessionToken ¶
CookieSessionToken confirms a credential-bearing cookie pair. The rule registers two kinds of triggers and this validator dispatches on which one fired (by inspecting window[trigStart:trigEnd]):
- Header triggers ("cookie:", "set-cookie:", trailing ':'): the pairs after the colon are scanned in order and the FIRST pair whose name qualifies (cookieNameQualifies) and whose value qualifies (cookieValueQualifies) has its value confirmed. Later qualifying pairs in the same header are caught by the pair triggers below — see the file comment for why one validator call cannot return them all. Note the pair triggers fire only when a keyword directly abuts the '=' ("...token=", "...sid=", "sessionid="), so a non-first pair whose name buries its keyword elsewhere ("session_2=") is a known miss; the trigger list carries the common real-world names rather than every conceivable shape.
- Pair triggers ("session=", "sessionid=", "sid=", "token=", "jwt=", "auth=", trailing '='): the full cookie name is extended backwards over name bytes (so "auth_token=" and "connect.sid=" are judged by their whole name, and "csrftoken=" is vetoed by its "csrf" prefix), cookie context is required (see cookiePairContextOK), and the following value must qualify. Without cookie context the pair path never matches: bare key=value assignments belong to the generic rules, not this one.
Only the cookie VALUE is redacted, never the name or header structure.
func CursorAPIKey ¶
CursorAPIKey confirms the Cursor API key shape: trigger "crsr_" followed by 20 or more characters of [A-Za-z0-9_-]. Cursor's own sensitive-prompt-guard hook script (github.com/cursor/cookbook) uses the regex crsr_[A-Za-z0-9_-]{20,} — an open floor with no upper bound at all, unlike every other rule in this file — so this validator imposes no separate maximum of its own: it consumes the maximal [A-Za-z0-9_-] run and only requires the 20-byte floor, relying on the rule's own maxLookahead (deliberately generous, in ai.json) as the practical ceiling rather than an arbitrary internal cap that a longer real key could silently fall outside of.
func DatadogAPIKey ¶
DatadogAPIKey confirms the shape of a value assigned to DD_API_KEY (matched case-insensitively, Datadog's own documented Agent configuration variable): 32 characters of lowercase hex. Like Buildkite's token, a Datadog API key has no prefix of its own, so this rule is keyed on the documented variable name.
https://docs.datadoghq.com/agent/guide/environment-variables/
func DatadogApplicationKey ¶
DatadogApplicationKey confirms the shape of a value assigned to DD_APP_KEY (matched case-insensitively, the variable name Datadog's own Terraform provider and CLI tooling document): 40 characters of lowercase hex.
https://registry.terraform.io/providers/DataDog/datadog/latest/docs
func DeepSeekAPIKey ¶
DeepSeekAPIKey confirms the DeepSeek API key shape: trigger "sk-" followed by exactly 32 lowercase alphanumeric characters (35 bytes total including the prefix). This shares its trigger literal with openai-legacy-key but the two never both confirm the same occurrence: OpenAI's legacy key is 51 bytes total with a mixed-case body containing the mandatory uppercase "T3BlbkFJ" infix, which a lowercase-only, exactly-32-byte DeepSeek body can never satisfy, and vice versa.
func DeepgramAPIKey ¶
DeepgramAPIKey confirms the shape of a value assigned to DEEPGRAM_API_KEY (matched case-insensitively): 40 characters of lowercase alphanumeric. Like Cohere's, Deepgram's key has no prefix of its own — TruffleHog's own detector keys on the literal word "deepgram" appearing nearby rather than on any byte prefix — so this rule is keyed on the documented environment-variable name instead.
func DockerHubOAT ¶
DockerHubOAT confirms the Docker Hub organization access token shape: trigger "dckr_oat_" followed by 32-100 characters from [A-Za-z0-9_-]. Docker's own docs describe organization access tokens (OATs) as a distinct token type from personal access tokens (not tied to an individual user, managed by organization owners) but don't publish a byte-level format; the "dckr_oat_" prefix and 32-character floor come from two independently-maintained scanners (TruffleHog and the betterleaks gitleaks fork) that converge on the same shape. 100 is the same generous practical ceiling DockerHubPAT uses, not a documented maximum.
https://docs.docker.com/security/access-tokens/ (token type); prefix/length: github.com/trufflesecurity/trufflehog pkg/detectors/dockerhub/v2/dockerhub.go
func DockerHubPAT ¶
DockerHubPAT confirms the Docker Hub personal access token shape: trigger "dckr_pat_" followed by 27-100 characters from [A-Za-z0-9_-]. 100 is a generous practical ceiling chosen for this validator, not a documented maximum.
https://docs.docker.com/security/for-developers/access-tokens/
func DopplerToken ¶
DopplerToken confirms the Doppler token shape: one of seven scoped triggers ("dp.st.", "dp.pt.", "dp.ct.", "dp.sa.", "dp.said.", "dp.scim.", "dp.audit.") followed by a 40-44 character alphanumeric body. Only a service token (dp.st.) may additionally carry a single config label between the prefix and the body (e.g. "dp.st.dev.<body>"), per Doppler's own documented format regex; the other six prefixes' regexes have no label segment, so this is tried only when the matched trigger is "dp.st.", falling back to a bodyless-label match if the label candidate doesn't resolve to a valid body.
func GCPAPIKey ¶
GCPAPIKey confirms the GCP API key shape: trigger "AIza" followed by exactly 35 characters of [0-9A-Za-z_-], bounded on both sides by a byte outside that alphabet (or the edge of window). It rejects an all-identical body.
func GenericAPIKeyAssignment ¶
GenericAPIKeyAssignment confirms an api-key/access-token-shaped assignment: one of this rule's triggers (api_key, apikey, api-key, access_token, auth_token, client_secret, secret_key, secret_key_base, session_secret, private_token — see internal/rules/specs/generic-credentials.json), not itself a suffix of a longer identifier, followed by an assignment separator and a value that entropy.Secretlike confirms as plausibly random under entropy.PresetAssignmentValue. Only the value is reported for redaction.
func GenericBearerLikeTokenAssignment ¶
func GenericBearerLikeTokenAssignment(window []byte, trigStart, trigEnd int) (start, end int, ok bool)
GenericBearerLikeTokenAssignment confirms a bearer-token-shaped assignment behind the weak, single "token" trigger. Because "token" alone is much weaker evidence of a secret position than api_key or password (it also matches ordinary code like "token = csv.next()" or a documentation placeholder like "token: <YOUR_TOKEN>"), this validator demands more of the value than the other two: it must be at least bearerLikeTokenMinLen (20) bytes long, and must pass entropy.Secretlike under entropy.PresetLooseToken with that same stricter MinLen. Only the value is reported for redaction.
func GenericPasswordAssignment ¶
GenericPasswordAssignment confirms a password-shaped assignment: one of this rule's triggers (password, passwd, pwd), not itself a suffix of a longer identifier, followed by an assignment separator and a value. It uses entropy.PresetAssignmentValue with MinLen lowered to 8 (password values run shorter than typical API keys) and additionally rejects any value entropy.Classify buckets as ClassWordlike — a plain dictionary word is never an acceptable password value, and this is checked explicitly here (on top of entropy.Secretlike's own unconditional word-like rejection) because password fields are exactly the position where a bare dictionary word is most likely to show up in real fixtures and logs. This validator's separator requirement also guards against the `pwd`/`passwd` shell commands and utilities: bare "pwd" or "passwd: files systemd" (an /etc/nsswitch.conf-style line) never parse past the separator/value step and so never match. Only the value is reported for redaction.
func GenericSecretAssignment ¶
GenericSecretAssignment confirms an assignment behind one of this rule's broad, generic triggers (key, secret, auth, access, credential, creds — see internal/rules/specs/generic-deep.json), not itself a suffix of a longer identifier. Like the balanced generic rules, it first rejects an empty inline assignment (isEmptyInlineAssignment) — documentation fragments such as `key=` — since without that guard the closing quote is mistaken for an opening value quote and unrelated following text is captured as the "secret". It then tries the same tight, zero-gap parse the balanced generic rules use (parseAssignmentValue, which already understands the "key": ... JSON-quoted-key shape); if that fails to find an immediate separator, it falls back to a gap-tolerant parse (skipWeakGap) that allows a short intervening phrase or hyphenated/underscored identifier before the separator. The captured value must pass the same shape checks the balanced rules use (isIndirectAssignmentValue, isMachineTokenValue, isAlphaSpaceOnly) plus entropy.Secretlike under the stricter entropy.PresetDeepGenericValue. Only the value is reported for redaction.
func GitHubAppToken ¶
GitHubAppToken confirms the GitHub App installation/user-to-server token shape: trigger "ghu_" or "ghs_" followed by exactly 36 ASCII alphanumeric characters.
func GitHubFineGrainedPAT ¶
GitHubFineGrainedPAT confirms the GitHub fine-grained personal access token shape: trigger "github_pat_" followed by 22 ASCII alphanumeric characters, a literal underscore, and 59 more ASCII alphanumeric characters.
func GitHubOAuthToken ¶
GitHubOAuthToken confirms the GitHub OAuth access token shape: trigger "gho_" followed by exactly 36 ASCII alphanumeric characters.
func GitHubPAT ¶
GitHubPAT confirms the classic GitHub personal access token shape: trigger "ghp_" followed by exactly 36 ASCII alphanumeric characters and a non-alphanumeric byte (or end of window). It rejects placeholder bodies (isPlaceholder): repeated characters ("XXXX...X"), ascending alphabet runs ("ABCDEFGH..."), and keyword stand-ins, which real tokens never are but test fixtures and documentation examples routinely use.
func GitHubRefreshToken ¶
GitHubRefreshToken confirms the GitHub OAuth refresh token shape: trigger "ghr_" followed by exactly 36 ASCII alphanumeric characters.
func GitLabDeployToken ¶
GitLabDeployToken confirms the GitLab deploy token shape: trigger "gldt-" followed by 20-50 characters from [A-Za-z0-9_-].
func GitLabFeedToken ¶
GitLabFeedToken confirms the classic (v1) GitLab feed token shape: trigger "glft-" followed by exactly 20 characters from [A-Za-z0-9_-]. This is GitLab's own default Devise.friendly_token length for the user model's FEED_TOKEN_PREFIX field, corroborated by gitleaks' "gitlab-feed-token" rule and by GitLab's own client-side secret detection pattern.
GitLab also issues a newer, structurally different "v2" feed token (see GitLabFeedTokenV2) under the same "glft-" prefix; the two validators safely coexist on the shared trigger because a v2 token's body is always far longer than 20 bytes of [A-Za-z0-9_-] (it embeds a 64-hex-character HMAC plus a dash-separated numeric ID), so this validator's exact-20 length check never confirms one.
func GitLabFeedTokenV2 ¶
GitLabFeedTokenV2 confirms the newer, path-dependent GitLab feed token shape: trigger "glft-" followed by exactly 64 hex characters, a literal '-', and one or more ASCII digits (the numeric user ID this token is scoped to). Unlike v1, this body is an HMAC-SHA256 digest of the specific feed path keyed by the user's real feed token, not a standalone random secret — but it's still sensitive: GitLab's own backend accepts it as a bearer credential for that user's feed.
func GitLabPAT ¶
GitLabPAT confirms the GitLab personal access token shape: trigger "glpat-" followed by 20-50 characters from [A-Za-z0-9_-].
https://docs.gitlab.com/user/profile/personal_access_tokens/#create-a-personal-access-token
func GitLabPipelineTriggerToken ¶
GitLabPipelineTriggerToken confirms the GitLab pipeline trigger token shape: trigger "glptt-" followed by exactly 40 characters from [A-Za-z0-9_-]. GitLab's own client-side secret detection pattern uses this full alphabet at this length; gitleaks independently corroborates the 40-character length with a narrower hex-only alphabet, so the broader alphabet here is a safe superset chosen to avoid false negatives on a real token gitleaks' stricter pattern would miss.
func GitLabRunnerToken ¶
GitLabRunnerToken confirms the GitLab runner authentication token shape: trigger "glrt-" followed by 20-50 characters from [A-Za-z0-9_-].
https://docs.gitlab.com/ci/runners/new_creation_workflow/#glrt-authentication-tokens
func GrafanaCloudAccessPolicyToken ¶
GrafanaCloudAccessPolicyToken confirms the Grafana Cloud access policy token shape: trigger "glc_" followed by 32-400 characters of standard base64 and up to two '=' padding characters.
func GrafanaServiceAccountToken ¶
GrafanaServiceAccountToken confirms the Grafana service-account token shape: trigger "glsa_" followed by a fixed 32-character alphanumeric body, a literal '_', and a fixed 8-character hex checksum.
https://grafana.com/docs/grafana/latest/administration/service-accounts/
func GroqAPIKey ¶
GroqAPIKey confirms the Groq API key shape: trigger "gsk_" followed by exactly 52 [A-Za-z0-9] and a non-alphanumeric byte (or end of window).
func HuggingFaceToken ¶
HuggingFaceToken confirms the Hugging Face token shape: trigger "hf_" followed by exactly 34 [A-Za-z0-9] and a non-alphanumeric byte (or end of window). Identifiers like "hf_hub_download" are naturally excluded: the underscore after "hub" ends the alphanumeric run well short of 34.
func JWT ¶
JWT confirms a standalone JWS compact serialization. See parseJWT for the exact shape enforced.
func LinearAPIKey ¶
LinearAPIKey confirms a Linear personal API key: trigger "lin_api_" followed by 40-60 ASCII alphanumeric characters and a non-alphanumeric byte (or end of window).
func NotionInternalToken ¶
NotionInternalToken confirms a Notion internal integration token, in either of its two documented forms:
- trigger "secret_" preceded by a non-identifier byte (or start of window) — this trigger is a substring of the common identifier "client_secret_" (an OAuth client secret field name, not a Notion token), so a preceding letter/digit/underscore means this occurrence isn't a standalone token — followed by exactly 43 ASCII alphanumeric characters.
- trigger "ntn_" followed by 46-60 ASCII alphanumeric characters.
Both forms require a non-identifier byte (or start of window) before the trigger, per the fixed-literal-prefix convention in docs/RULE_AUTHORING.md, and a non-alphanumeric byte (or end of window) after the body. Which shape is being validated is determined by trigEnd-trigStart (7 for "secret_", 4 for "ntn_"), since that's all that distinguishes the two triggers from inside a validator that only sees window-relative offsets.
func NpmAccessToken ¶
NpmAccessToken confirms the npm access token shape: trigger "npm_" followed by exactly 36 ASCII alphanumeric characters.
The fixed length plus trailing-boundary check are what let this trigger safely coexist with npm's own identifier prefixes, e.g. "npm_config_registry" or "npm_config_yes": their bodies are not 36 bytes of pure alphanumerics (an underscore breaks the run well short of 36), so fixedAlnumToken rejects them.
func OpenAILegacyKey ¶
OpenAILegacyKey confirms the classic OpenAI secret key shape: trigger "sk-" followed by exactly 20 [A-Za-z0-9], the literal infix "T3BlbkFJ", then exactly 20 more [A-Za-z0-9] (48 bytes total), with a non-alphanumeric byte (or end of window) on the right and a byte that is not [A-Za-z0-9_-] (or start of window) on the left.
Because "sk-" is a substring of "sk-ant-", "sk-proj-", "sk-svcacct-", and "sk-admin-", this validator explicitly refuses to confirm when the bytes immediately after the trigger begin with any of those other rules' distinguishing suffixes — those occurrences belong to anthropic-api-key or openai-project-key instead.
func OpenAIProjectKey ¶
OpenAIProjectKey confirms the OpenAI project-scoped key shapes: trigger "sk-proj-", "sk-svcacct-", or "sk-admin-" followed by [A-Za-z0-9_-]. The body must be at least 40 bytes and at most 200. If it contains the "T3BlbkFJ" infix anywhere, it is confirmed regardless of length beyond that floor/ceiling; without the infix, it must additionally be at least 48 bytes and not look like a placeholder (all one character, or a long repeated run).
func PEMPrivateKey ¶
PEMPrivateKey confirms a PEM-encapsulated private-key block within window, treating the end of window as the end of input. It is PEMPrivateKeyBegin with final set; see that function and the file comment for the grammar and span semantics.
func PEMPrivateKeyBegin ¶ added in v0.3.0
func PEMPrivateKeyBegin(window []byte, trigStart, trigEnd int, final bool) (start, end int, state uint64, open, ok bool)
PEMPrivateKeyBegin confirms a PEM private-key block (rules.BlockBeginFunc). The trigger is "-----BEGIN " (trailing space included). The header label must contain "PRIVATE KEY" (so CERTIFICATE and PUBLIC KEY blocks are rejected), then the body is scanned until the matching "-----END ...PRIVATE KEY...-----" marker. When final is false and the body runs on past the window after a plausible run, the block is open and continues with PEMPrivateKeyExtend. A trigger opening a unified diff line (the rule's two-byte lookbehind shows the marker) makes the block a diff block, closed by the END lines of its own file versions.
func PEMPrivateKeyExtend ¶ added in v0.3.0
PEMPrivateKeyExtend continues an open PEM block (rules.BlockExtendFunc) from the previous window's resume point, to the END marker, to the fail-safe end, or — when the body runs past this window too — to the next resume point.
func PuTTYPrivateKey ¶
PuTTYPrivateKey confirms the private section of a PuTTY PPK file within window, treating the end of window as the end of input. It is PuTTYPrivateKeyBegin with final set.
func PuTTYPrivateKeyBegin ¶ added in v0.3.0
func PuTTYPrivateKeyBegin(window []byte, trigStart, trigEnd int, final bool) (start, end int, state uint64, open, ok bool)
PuTTYPrivateKeyBegin confirms the private section of a PuTTY PPK file (rules.BlockBeginFunc). The trigger is "PuTTY-User-Key-File-"; the version digit must be 2 or 3 (followed by ':'). The validator then locates the "Private-Lines: N" header at a line start and consumes N base64 body lines. Span: first byte of "Private-Lines:" through the last base64 byte of the last body line (the public portion stays). If "Private-Lines:" never appears in the window the validator reports no match; once it has appeared, the fail-safe confirms a partial body with at least one plausible (>= 16-byte base64) line.
In a unified diff patch every line opens with '+', '-' or ' ': a header behind one such marker selects diff mode, in which every body line must open with a marker too and each file version is counted separately (see ppkScanner). The rule's two-byte lookbehind shows the trigger line's own marker, which selects the versions the key follows. A header indented by one space reads as a context line, whose body lines then need the same one-byte indent.
func PuTTYPrivateKeyExtend ¶ added in v0.3.0
func PuTTYPrivateKeyExtend(window []byte, state uint64, final bool) (end int, next uint64, open bool)
PuTTYPrivateKeyExtend continues an open PPK section (rules.BlockExtendFunc) from the previous window's resume point: a line start, the end of a counted line's base64, or inside a counted or stepped-over line.
func PyPIAPIToken ¶
PyPIAPIToken confirms the PyPI API token shape: trigger "pypi-" followed by 85-300 characters from [A-Za-z0-9_-] (a base64url-encoded macaroon). 300 is a generous practical ceiling chosen for this validator, not a documented maximum — PyPI does not publish an upper bound on token length.
func SendGridAPIKey ¶
SendGridAPIKey confirms a SendGrid API key: trigger "SG." preceded by a non-identifier byte (or start of window) — this trigger is a substring of ordinary words like "MSG." (a message-related identifier), so a preceding letter/digit/underscore means this "SG." occurrence is part of a longer identifier, not a key — followed by exactly 22 [A-Za-z0-9_-] characters, a literal '.', exactly 43 more [A-Za-z0-9_-] characters, and a byte outside that alphabet (or end of window).
func SlackAppToken ¶
SlackAppToken confirms a Slack app-level token: trigger "xapp-" followed by a run of 40-100 bytes drawn from [A-Za-z0-9-] containing at least 3 hyphens, and a non-alphanumeric byte (or end of window). Slack's documented shape is <digit>-<10-12 char alnum segment>-<10-13 digits>-<64 hex chars>, but this validator deliberately accepts the looser digit/dash/token-char envelope rather than pinning every segment length, so it isn't invalidated by minor token-format revisions.
func SlackBotToken ¶
SlackBotToken confirms the Slack bot token shape: trigger "xoxb-" preceded by a non-identifier byte (or start of window), followed by <10-13 digits>-<10-13 digits>-<24-34 alphanumeric characters> and a non-alphanumeric byte (or end of window). Every segment is checked against isPlaceholder, so fixture shapes like "xoxb-1234567890-..." are rejected along with all-identical segments.
func SlackUserToken ¶
SlackUserToken confirms a Slack user-scoped token: one of the triggers "xoxp-", "xoxa-", "xoxr-", "xoxs-" followed by <10-13 digits>-<10-13 digits>-<24-34 alphanumeric characters>. xoxp tokens historically carry an extra digit group before that final segment (<digits>-<digits>-<digits>-<alnum>); both the two-group and three-group shapes are accepted for all four prefixes, since the distinguishing factor is workspace/token vintage, not which of these four prefixes was used. The three-group shape is tried first (it is the more specific match); when it doesn't validate, the parser falls back to treating the segment right after the second dash as the final alphanumeric run directly.
func StripeEphemeralKey ¶
StripeEphemeralKey confirms a Stripe ephemeral key: trigger "ek_live_" or "ek_test_" followed by 60-150 characters from the URL-safe-base64 alphabet ([A-Za-z0-9_-]) and a boundary. Unlike sk_/rk_ secret keys, an ephemeral key's body is not a flat random token: it's a base64url encoding of the account ID it's scoped to plus a random component, so it legitimately contains '-' and '_' and its length scales with the account ID rather than being fixed. Neither gitleaks nor TruffleHog has a rule for this key type; the shape here comes from real (but synthetic-safe, since only the encoding structure was inspected, never a real key's decoded contents) fixtures in Stripe's own stripe-ios and stripe-android SDK repositories.
func StripeSecretKey ¶
StripeSecretKey confirms a Stripe secret/restricted API key: one of the triggers "sk_live_", "sk_test_", "rk_live_", "rk_test_" followed by 24-99 ASCII alphanumeric characters and a non-alphanumeric byte (or end of window). Test-mode keys (sk_test_/rk_test_) are still credentials — they authenticate against Stripe's test-mode API — so they are redacted identically to live-mode keys.
func StripeWebhookSecret ¶
StripeWebhookSecret confirms a Stripe webhook signing secret: trigger "whsec_" followed by 32-64 ASCII alphanumeric characters and a non-alphanumeric byte (or end of window).
func SupabaseServiceRoleKey ¶
SupabaseServiceRoleKey confirms the same JWS compact-serialization shape as JWT (see parseJWT), additionally base64url-decoding the payload segment and requiring a `"role":"service_role"` claim within it. A payload that fails to decode as base64url — truncated by the window, or simply not base64 — is rejected rather than guessed at.
func TerraformCloudAPIToken ¶
TerraformCloudAPIToken confirms the HCP Terraform/Terraform Enterprise API token shape: a 14-character alphanumeric prefix, the literal trigger ".atlasv1.", and a 60-70 character secret from [A-Za-z0-9_=-], bounded on the left by a byte that cannot extend the prefix backward (or the edge of window). A token with this shape grants read/modify access to Terraform Cloud-managed infrastructure state, which routinely contains further embedded secrets (provider credentials, database passwords) in its resource attributes and outputs.
https://developer.hashicorp.com/terraform/cloud-docs/api-docs/user-tokens https://developer.hashicorp.com/terraform/cloud-docs/api-docs/team-tokens https://developer.hashicorp.com/terraform/cloud-docs/api-docs/organization-tokens
func TwilioAPIKeySID ¶
TwilioAPIKeySID confirms a Twilio API key SID: trigger "SK" (matched case-sensitively — see the rule spec) preceded by a non-identifier byte (or start of window) — "SK" is a substring of ordinary words like "TASK" and "DESK", so a preceding letter/digit/underscore means this isn't a standalone SID — followed by exactly 32 ASCII lowercase hex characters and a non-alphanumeric byte (or end of window).
func URLCredentials ¶
URLCredentials confirms a password inside a URL's userinfo component ("scheme://user:password@host/..."). The trigger is the literal "://".
The scheme before "://" must look like a scheme: a run of scheme bytes at least 2 long whose first byte is a letter — this rejects prose like `the "://" separator`. After "://", the userinfo is scanned for '@'; if a terminator byte appears first there is no userinfo and no match.
Only the PASSWORD is redacted: the bytes after the first ':' of the userinfo up to (excluding) the '@'. A username-only URL ("https://user@host") is deliberately not a match: a bare username is an identifier, not a secret, and redacting it would destroy far more benign URLs than it would protect (gitleaks flags whole user:pass URLs; this rule intentionally preserves everything but the password so the URL stays byte-for-byte usable around the marker). An empty password ("redis://:@host") is likewise no match. Percent-encoded bytes pass through unexamined — they are just bytes to this scan.
Placeholders and plain word-like values are rejected via entropy helpers plus the tiny urlPasswordPlaceholders whole-value list, so documentation and development-default shapes like "user:pass", "user:content", and "foo:xxx" never fire. Random-looking passwords remain detectable.
func VaultBatchToken ¶
VaultBatchToken confirms the HashiCorp Vault batch token shape: trigger "hvb." followed by 100-300 characters from [A-Za-z0-9_-]. Batch tokens are the same blast-radius class as service tokens (whatever their policies allow) but encode more state directly into the token, which is why their body runs longer.
https://github.com/hashicorp/vault/blob/main/vault/token_store.go (TokenPrefixLength, TokenLength) https://github.com/gitleaks/gitleaks/blob/master/config/gitleaks.toml (production length range)
func VaultServiceToken ¶
VaultServiceToken confirms the HashiCorp Vault service token shape: trigger "hvs." followed by 20-150 characters from [A-Za-z0-9_-]. A Vault service token grants whatever access its policies allow, up to full administrative control of everything Vault manages.
https://github.com/hashicorp/vault/blob/main/vault/token_store.go (TokenPrefixLength, TokenLength) https://github.com/gitleaks/gitleaks/blob/master/config/gitleaks.toml (production length range)
func VercelLegacyToken ¶
VercelLegacyToken confirms the shape of a value assigned to VERCEL_TOKEN, VERCEL_API_TOKEN, or VERCEL_ACCESS_TOKEN (matched case-insensitively — VERCEL_TOKEN is Vercel's own documented CLI/REST API auth variable, the other two are common conventions seen alongside it): 24 alphanumeric characters. Tokens minted before Vercel introduced its current prefixed format remain valid and have no distinguishing shape of their own, so this rule is keyed on the documented variable names rather than the token body alone.
https://vercel.com/docs/cli https://vercel.com/docs/rest-api
func VercelToken ¶
VercelToken confirms the current (2026+) Vercel access token shape: one of five scoped triggers ("vcp_" personal, "vci_" integration, "vca_" app access, "vcr_" app refresh, "vck_" API key) followed by 40-80 alphanumeric characters.
https://vercel.com/changelog/new-token-formats-and-secret-scanning
Types ¶
This section is empty.