Rule Authoring
Picket’s compatibility rule format is Gitleaks TOML. Native rule-pack metadata extends this model, but strict compatibility mode must keep Gitleaks behavior stable.
Config Loading
Section titled “Config Loading”Compatibility commands load configuration in this order:
--configGITLEAKS_CONFIGGITLEAKS_CONFIG_TOML{target}/.gitleaks.toml- embedded Gitleaks compatibility rules
Native commands currently use the same rule model with Picket-native environment precedence. picket rules check uses native precedence by default and also accepts --profile picket explicitly. Gitleaks-compatible git, dir/file/directory, and stdin scans use this same native precedence only when --profile picket is supplied.
--configPICKET_CONFIGPICKET_CONFIG_TOMLGITLEAKS_CONFIGGITLEAKS_CONFIG_TOML{target}/.gitleaks.toml- embedded Picket default config, which extends the embedded Gitleaks compatibility rules and adds
picket-defaultcoverage
Strict compatibility commands ignore PICKET_CONFIG and PICKET_CONFIG_TOML. Native commands also understand optional Picket metadata fields on each rule.
File-backed config loads, including [extend] path, are capped at 10 MiB per file. Resolved configs are capped at 10,000 rules. Inline GITLEAKS_CONFIG_TOML and PICKET_CONFIG_TOML values are parsed from the environment value already supplied to the process.
In strict compatibility mode, [extend] path follows the pinned Gitleaks/Viper local-file behavior: absolute paths are accepted, and relative paths resolve from the process current working directory. Picket keeps that behavior for compatibility, with the byte cap, extend-depth cap, and cycle detection described above. Treat configs with local extend.path values as trusted scanner configuration rather than as scan-root-confined input.
The embedded native default combines gitleaks with the high-confidence picket-default pack. Current native defaults include Anthropic OAuth and Claude Code session credentials; legacy, project, project service-account, and organization-admin OpenAI API keys; OpenAI Codex OAuth credentials; Cast AI, Groq, and xAI keys; AWS key pairs; Azure Storage connection strings; credentialed database URLs; Google API keys and GCP service-account keys; Sourcegraph tokens; GitHub token families; Docker registry auth; private JWKs; Kubernetes Secrets; MCP server environment credentials; and npm tokens and basic credentials. Provider-specific fields receive offline structural validation where a deterministic validator exists.
The database URL rule requires a known database scheme, a username, and an embedded password; passwordless URLs are skipped. Native GitHub token rules replace inherited Gitleaks GitHub token rules so native scans emit Picket-owned IDs and metadata without duplicate findings. The native Sourcegraph rule replaces the inherited broad Sourcegraph rule so native scans do not report arbitrary 40-hex commit IDs as access tokens.
--rule-pack picket-strict adds broader medium-confidence rules for semicolon-delimited connection-string passwords, HTTP Basic authorization values, and Azure SAS signatures. --rule-pack picket-experimental adds low-confidence opaque bearer-token and session-cookie detectors under active tuning. Repeat --rule-pack to add both. These packs are opt-in and do not change the native default or strict Gitleaks compatibility behavior. Compatibility commands require --profile picket before accepting either pack.
Native .cs scans evaluate deterministic C# string-literal concatenations before matching, so literal-only string.Concat(...) calls and binary + literal chains can produce findings with csharp-string-concat decode provenance. Picket-native picket-* rule packs do not inherit Gitleaks compatibility global allowlists; broad compatibility stopwords must not suppress native hosted-scanner parity findings.
Target-local and environment configs replace the embedded native default. Use [extend] useDefault = true in a custom config to add local rules over the Gitleaks compatibility default. Explicit --rule-pack selections layer over the resolved native config.
Rule Shape
Section titled “Rule Shape”Supported rule fields:
id: stable rule identifier.description: human-readable finding description.regex: content pattern. Empty is valid only whenpathis present.path: path pattern.secretGroup: capture group containing the secret.0means automatic first non-empty capture behavior.entropy: minimum Shannon entropy.0disables entropy filtering.randomnessThreshold: minimum nativep(random)score from0.0through1.0.0disables score filtering. See Randomness Scoring.detector: stable built-in structured detector name. The regex and keywords remain the candidate prefilter; the detector parses the selected input and returns exact evidence spans.prefilter: optional native source predicate. A result oftrueskips the source for a top-level predicate or skips the owning rule for a rule predicate.filter: optional native finding predicate. A result oftruesuppresses the candidate.keywords: case-insensitive prefilter terms.tags: classification labels.skipReport: run supporting detection without reporting normal findings.severity: native report severity. Defaults tocritical.confidence: native report confidence. Defaults tohigh.rulePack: native rule-pack identifier such asgitleaks,picket-default, orpicket-strict.provider: owning provider or credential family.documentationUrl: rule documentation or remediation URL.validation: stable validation template identifiers supported by the rule. Identifiers name existing offline or live validators; they do not trigger network calls by themselves.revocation: stable revocation template identifiers supported by the rule. Identifiers name report/analyze templates; revocation is never automatic during scan.deprecated:truewhen the rule remains loadable but should not be used for new rule packs.examples: positive examples that must produce findings for this rule during rule QA.negativeExamples: negative examples that must not produce findings for this rule during rule QA.
Example:
[[rules]]id = "sample-token"description = "Sample token"regex = '''token-[0-9]+'''keywords = ["token"]tags = ["example"]severity = "high"confidence = "medium"rulePack = "picket-default"provider = "example"documentationUrl = "https://example.invalid/rules/sample-token"examples = ["token-12345"]negativeExamples = ["token-value"]Randomness thresholds are native-only. A positive threshold suppresses a finding when its score is lower than the configured value; strict compatibility scans ignore the field. Keep the default of zero until reviewed positive and negative examples establish a safe threshold for that specific rule.
Built-in structured detector identifiers are:
codex-credentialsdocker-registry-credentialsgcp-service-account-keyjwk-private-keykubernetes-secretmcp-server-credentialsnpm-credentialspassword-assignment
Structured detectors are native-only. JSON, YAML, and npmrc parse products are bounded and shared for one input so multiple rules do not repeatedly parse the same content. Unknown detector names fail config validation.
The password-assignment detector recognizes bounded password and passwd
assignments without restricting the value alphabet. The
picket-generated-password rule combines that explicit context with a reviewed
randomness threshold. This keeps generated values containing punctuation or
ordinary stopwords detectable without broadening the compatibility-derived
generic API-key rule.
Contextual Predicates
Section titled “Contextual Predicates”prefilter and filter are Picket-native controls. Strict Gitleaks-compatible
commands parse and preserve these fields but never validate or evaluate them.
Use picket rules check, picket rules test, or a native scan to validate
predicate syntax.
A top-level prefilter runs once for each source before rule regexes run. A
rule prefilter runs before its owning rule. A top-level filter applies to
every candidate finding, while a rule filter applies only to candidates from
that rule. Filters run after finding metadata and optional randomness scoring
are available and before required-rule correlation. When both global and rule
filters exist, either one can suppress the candidate.
The expression grammar is deliberately closed:
- boolean operators:
!,&&, and|| - grouping with parentheses
- equality operators:
==and!= - numeric operators:
<,<=,>, and>= - string operators:
contains,starts_with, andends_with - Scout-backed regex search with
matches; its right operand must be a string literal and is compiled once during rule validation - finite numeric, boolean, single-quoted string, and double-quoted string literals
! binds before comparisons, comparisons bind before &&, and && binds
before ||. Boolean evaluation short-circuits. String comparisons and string
operators are ordinal and case-sensitive. For string-list fields, contains
tests exact list membership.
Prefilters can read:
| Field | Type | Value |
|---|---|---|
source.path |
string | Logical source path stored in findings |
source.symlink |
string | Symbolic-link display path, or an empty string |
Filters can read those source fields plus:
| Field | Type |
|---|---|
finding.rule_id |
string |
finding.description |
string |
finding.match |
string |
finding.secret |
string |
finding.line |
string |
finding.start_line |
number |
finding.end_line |
number |
finding.start_column |
number |
finding.end_column |
number |
finding.entropy |
number |
finding.randomness_score |
number |
finding.decode_depth |
number |
finding.is_decoded |
boolean |
finding.tags |
string list |
finding.decode_path |
string list |
finding.severity |
string |
finding.confidence |
string |
finding.rule_pack |
string |
finding.provider |
string |
Example:
prefilter = 'source.path starts_with "vendor/"'
[[rules]]id = "sample-token"description = "Sample token"regex = '''token-[0-9]+'''keywords = ["token"]prefilter = 'source.path ends_with ".generated.cs"'filter = '''finding.provider == "example" &&finding.secret matches "^token-0+$"'''Predicate compilation rejects expressions that exceed any of these limits:
| Resource | Limit |
|---|---|
| Expression text | 4,096 UTF-8 bytes |
| Tokens | 256 |
| Parenthesis nesting | 16 |
| Compiled instructions | 512 |
| String literal | 1,024 UTF-8 bytes |
| Compiled regexes | 32 |
Evaluation uses a 64-value stack, accepts at most 65,536 characters from one
dynamic string, and examines at most 256 items from a string list. If source
or finding data exceeds an evaluation limit, the expression returns false.
This fail-open behavior prevents a resource-limit condition from hiding a
finding. Predicates have no field, operator, or function that can access the
filesystem, environment, network, reflection, or runtime code generation.
Predicate source participates in the compiled rule-set fingerprint. Predicate-bearing rule sets use path-sensitive native cache addressing so a result cannot be reused for another logical source path.
Supported validation template identifiers are:
offline:anthropic-oauth-tokenoffline:aws-access-key-idoffline:aws-access-key-pairoffline:azure-storage-connection-stringoffline:buildkite-tokenoffline:cast-ai-api-keyoffline:claude-code-session-urloffline:codex-access-tokenoffline:codex-refresh-tokenoffline:database-connection-urloffline:docker-hub-access-tokenoffline:docker-registry-authoffline:gcp-api-keyoffline:gcp-service-account-key-jsonoffline:github-app-tokenoffline:github-classic-tokenoffline:github-fine-grained-patoffline:groq-api-keyoffline:jwk-private-keyoffline:jwtoffline:jwt-base64offline:kubernetes-secretoffline:langsmith-api-keyoffline:mcp-server-credentialoffline:npm-auth-tokenoffline:npm-basic-authoffline:nvidia-api-keyoffline:openai-admin-api-keyoffline:openai-legacy-api-keyoffline:openai-project-api-keyoffline:openai-service-account-api-keyoffline:openrouter-api-keyoffline:private-key-envelopeoffline:replicate-api-tokenoffline:sourcegraph-access-tokenoffline:tailscale-api-keyoffline:vercel-tokenoffline:xai-api-keylive:github-rest-user-v1
Supported revocation template identifiers are:
revocation:aws-iam-access-keyrevocation:azure-storage-account-keyrevocation:gcp-api-keyrevocation:gcp-service-account-keyrevocation:github-credentials-api
picket rules check rejects a template identifier when the current verifier or analyzer cannot honor it for that rule ID.
Cast AI API keys are organization-scoped and inherit their creator’s permissions. If a key is exposed, delete it in the Cast AI console, create a replacement, and update each dependent workload. Prefer a dedicated service account with only the permissions required by that workload.
Allowlists
Section titled “Allowlists”Global allowlists use [[allowlists]] or the deprecated [allowlist] form. Rule allowlists use [[rules.allowlists]] or the deprecated [rules.allowlist] form.
Supported allowlist fields:
descriptioncondition:or,and,||, or&&commitspathsregexTarget:secret,match, orlineregexesstopwordstargetRulesfor global allowlists only
Deprecated singular allowlist tables cannot be mixed with plural allowlist tables in the same scope.
The native default profile uses exact contextual allowlists for public Supabase and Stripe publishable keys, Cargo checksums and revisions, and complete Kubernetes external-secret template references. Cargo suppression requires both the expected file path and checksum or revision syntax. It does not ignore Cargo files as a class. Supabase secret keys and concrete Kubernetes Secret values remain reportable.
Required Rules
Section titled “Required Rules”Required rules let a primary finding require nearby supporting findings.
[[rules]]id = "primary"description = "Primary"regex = '''secret-[0-9]+'''
[[rules.required]]id = "supporting"withinLines = 3withinColumns = 80Picket resolves required evidence after the original input and all enabled decoding passes have been scanned. A primary finding can therefore be satisfied by supporting evidence discovered through base64, hex, percent, Unicode, or other recursive decoding. Line and column proximity always use positions remapped to the original source. Supporting rules with skipReport = true participate in the composite match without producing their own top-level findings.
Every required rule ID must exist, and a rule must not require itself.
Validation
Section titled “Validation”picket rules check validates:
- TOML shape for the supported Gitleaks schema.
- duplicate rule IDs.
- missing regex/path combinations.
- invalid regexes and secret capture groups.
- empty keywords, tags, allowlist entries, and required-rule IDs.
- required-rule references.
- required positive and negative examples for Picket-native rules.
- keyword prefilters for Picket-native content rules.
- known built-in detector names and detector-compatible native rules.
- native predicate syntax, field availability, operand types, regexes, and resource limits.
- obvious Picket-native regex performance hazards such as unbounded
.*or.+spans outside character classes. - positive and negative examples without printing example contents in diagnostics.
- validation and revocation template identifiers supported by the current verifier/analyzer.
picket rules test <rule-id> <input> scans sample text with one selected rule using Picket-native config precedence by default. It accepts --source for target-local .gitleaks.toml discovery, --path for path-only rules and report location metadata, --max-decode-depth, --max-target-megabytes, --ignore-gitleaks-allow, --redact[=n], and the native report formats json, jsonl, csv, junit, html, gitlab, sarif, and toon. Use -- before <input> when the sample starts with -. The default output is Picket JSON with schema, rule metadata, stable fingerprints, hashes, decode provenance, and offline validation state. Use --print-config to emit the resolved selected rule config.
Scout Regex
Section titled “Scout Regex”Picket compiles rule and allowlist patterns to Scout ByteRegex. Unsupported patterns fail at config load with the rule ID and pattern context. Structured detector rules still use ByteRegex and keywords as their candidate prefilter; only the selected native rule then runs its bounded structured detector. Picket must not silently fall back to a different regex engine in Native AOT builds.