diff --git a/CHANGELOG.md b/CHANGELOG.md
index 24e27b2..b5f84c6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,7 +5,9 @@ All notable changes to this project will be documented in this file.
## [v1.96.0]
- Added live HTTP validation for 18 rules across 15 providers: Val Town, Polar, hCaptcha, Thunderstore, Elastic Cloud (2 rules), LlamaCloud, Gemfury (2 rules), Vonage, ThingsBoard, Zapier, Facebook Access Token, GitLab Session Cookie, PostHog Feature Flags, Unkey API Key, and Hop.io (2 rules).
- Added revocation support for 7 rules across 6 providers: Discord webhooks (single-step DELETE), DigitalOcean PATs (self-revoke via OAuth), and multi-step HttpMultiStep revocation for LaunchDarkly, Resend, Linode, and Netlify (2 rules). Built-in revocation coverage is now 34 provider families with 53 revocation-enabled rules.
+- Expanded Alibaba Cloud coverage with STS temporary credential detection for STS access key IDs, STS security tokens, and STS access key secrets. Built-in rule coverage is now 921 rules total.
- Added 61 new detection rules across 46 providers: Axiom (API token + PAT), Trigger.dev (secret key + PAT), Dub.co, Svix webhook signing secret, Liveblocks, Inngest (signing key + event key), Seam, Courier, Cal.com, Arcjet, WarpStream, Mem0, Mintlify, Pirsch, Tinybird, Tolgee (project key + PAT), Ory (API key + session + OAuth2 tokens), Xendit, Xata, Crossmint (server + client keys), DeepL (Free + Pro), Flagsmith, E2B, Infisical, WooCommerce (consumer key + secret), Nightfall AI, Ramp (client ID + secret), Hex.pm (personal + workspace tokens), Convex deploy key, MiniMax, Mappedin (key + secret), Pollinations (secret + publishable), Fal.ai, Aikido, Hack Club, GuardSquare, Browser Use, Composio, Gamma, Hex.tech, Mastra, redirect.pizza, Upstash, and WorkOS. Also added new prefixed-token rules for Netlify (`nfp_`), Cloudflare (`cfut_`), and Supabase (`sb_publishable_`). Added live HTTP validation for 30 of these rules.
+- Added 32 new detection rules across 25 providers: Ghost CMS (admin + content keys), UpCloud (`ucat_`), Voiceflow (`VF.DM.`/`VF.WS.`), Robinhood Crypto (`rh-api-`), ClickUp (`pk_`), Unleash (client/admin + personal tokens), ConfigCat (standard + extended SDK keys), SaladCloud (`salad_cloud_`), Tigris (`tid_`/`tsec_`), Portainer (`ptr_`), Permit.io (`permit_key_`), Builder.io (`bpk-`), LiveKit (API key + secret), Close CRM (`api_`), Hetzner Cloud, Censys (API ID + secret), Wistia, PandaDoc, Pinata (key + secret), ZeroTier, Detectify, ChartMogul, Moralis, ButterCMS, and Loops. Includes HTTP validation for 19 of these rules.
- Removed 17 direct dependencies from the root crate by dropping unused deps (`p256`, `ed25519-dalek`, `jsonwebtoken`, `gitlab`, `lazy_static`, `base32`, `pem`, `byteorder`, `reqwest-middleware`, `sha1`, `time`, `ring`, `num_cpus`, `strum_macros`), replacing `once_cell` with `std::sync::{LazyLock, OnceLock}`, and using `std::thread::available_parallelism()` in place of `num_cpus`. Salt generation now uses `rand` instead of `ring`, and all `strum_macros::Display` imports are consolidated under `strum::Display`.
## [v1.95.0]
diff --git a/README.md b/README.md
index 9de1ebf..2a27a56 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
-
+
@@ -17,7 +17,7 @@
Kingfisher is an open source secret scanner and **live secret validation** tool built in Rust.
-It combines Intel's SIMD-accelerated regex engine (Hyperscan) with language-aware parsing to achieve high accuracy at massive scale, and **ships with 800+ built-in rules** to detect, **validate**, and triage leaked API keys, tokens, and credentials before they ever reach production.
+It combines Intel's SIMD-accelerated regex engine (Hyperscan) with language-aware parsing to achieve high accuracy at massive scale, and **ships with 921 built-in rules** to detect, **validate**, and triage leaked API keys, tokens, and credentials before they ever reach production.
Designed for offensive security engineers and blue-team defenders alike, Kingfisher helps you scan repositories, cloud storage, chat, docs, and CI pipelines to find and verify exposed secrets quickly.
@@ -49,9 +49,9 @@ Kingfisher is a high-performance, open source secret detection tool for source c
-### Performance, Accuracy, and 800+ Rules
+### Performance, Accuracy, and 921 Rules
- **Performance**: multithreaded, Hyperscan‑powered scanning built for huge codebases
-- **Extensible rules**: 800+ built-in rules plus YAML-defined custom rules ([docs/RULES.md](/docs/RULES.md))
+- **Extensible rules**: 921 built-in rules plus YAML-defined custom rules ([docs/RULES.md](/docs/RULES.md))
- **Validate & Revoke**: live validation of discovered secrets, plus direct revocation for supported platforms (GitHub, GitLab, Slack, AWS, GCP, and more) ([docs/USAGE.md](/docs/USAGE.md))
- **Revocation support matrix**: current built-in revocation coverage across providers and rule IDs ([docs/REVOCATION_PROVIDERS.md](/docs/REVOCATION_PROVIDERS.md))
- **Blast Radius Mapping**: instantly map leaked keys to their effective cloud identities and exposed resources with `--access-map`. Supports 39 providers (see table below).
@@ -345,7 +345,7 @@ gh attestation verify kingfisher-linux-x64.tgz --repo mongodb/kingfisher
# Detection Rules
-Kingfisher ships with [800+ built-in rules](crates/kingfisher-rules/data/rules/) covering cloud keys, AI tokens, CI/CD secrets, database credentials, and SaaS API keys. Below is an overview — see the full list in [crates/kingfisher-rules/data/rules/](crates/kingfisher-rules/data/rules/):
+Kingfisher ships with [921 built-in rules](crates/kingfisher-rules/data/rules/) covering cloud keys, AI tokens, CI/CD secrets, database credentials, and SaaS API keys. Below is an overview — see the full list in [crates/kingfisher-rules/data/rules/](crates/kingfisher-rules/data/rules/):
| Category | What we catch |
|----------|---------------|
@@ -362,7 +362,7 @@ Kingfisher ships with [800+ built-in rules](crates/kingfisher-rules/data/rules/)
## Write Custom Rules
-Kingfisher ships with 800+ rules with HTTP and service‑specific validation checks (AWS, Azure, GCP, etc.) to confirm if a detected string is a live credential.
+Kingfisher ships with 921 rules with HTTP and service‑specific validation checks (AWS, Azure, GCP, etc.) to confirm if a detected string is a live credential.
However, you may want to add your own custom rules, or modify a detection to better suit your needs / environment.
diff --git a/crates/kingfisher-rules/data/rules/alibaba.yml b/crates/kingfisher-rules/data/rules/alibaba.yml
index 70e1658..3265dd7 100644
--- a/crates/kingfisher-rules/data/rules/alibaba.yml
+++ b/crates/kingfisher-rules/data/rules/alibaba.yml
@@ -3,8 +3,9 @@ rules:
id: kingfisher.alibabacloud.1
pattern: |
(?x)
+ \b
(
- LTAI([a-zA-Z0-9]{12,20})
+ LTAI[A-Za-z0-9]{17,21}
)
\b
pattern_requirements:
@@ -25,8 +26,12 @@ rules:
pattern: |
(?x)
\b
- (?i:alibaba|alibaba[\s_-]*cloud|aliyun)
- (?:.|[\n\r]){0,40}?
+ (?:
+ (?i:alibaba|alibaba[\s_-]*cloud|aliyun)
+ |
+ LTAI[A-Za-z0-9]{17,21}
+ )
+ (?:.|[\n\r]){0,80}?
(?i:access[\s_-]*key[\s_-]*secret|access[\s_-]*secret|secret|token|key)
(?:.|[\n\r]){0,16}?
(?:
@@ -46,6 +51,7 @@ rules:
examples:
- alibaba_secret = 7jkWdTjKLnSlGddwPR5gBn65PHcZG6
- alibaba-token = aJHKLnSlGddwPR5g7jkWdTBn65PHc5
+ - AccessKeyId=LTAI8x2NiGqfyJGx7eLDhp12 AccessKeySecret=7jkWdTjKLnSlGddwPR5gBn65PHcZG6
validation:
type: Http
content:
@@ -81,4 +87,119 @@ rules:
- https://www.alibabacloud.com/help/en/ram/latest/create-an-accesskey-pair
depends_on_rule:
- rule_id: kingfisher.alibabacloud.1
- variable: AKID
\ No newline at end of file
+ variable: AKID
+ - name: Alibaba STS Access Key ID
+ id: kingfisher.alibabacloud.3
+ pattern: |
+ (?x)
+ \b
+ (
+ STS\.[A-Za-z0-9]{16,64}
+ )
+ \b
+ min_entropy: 3.0
+ confidence: medium
+ visible: false
+ examples:
+ - STS.NTKaenSkmLhG4HpM576UV
+ - STS.FJ6EMcS1JLZgAcBJSTDG1Z4CE
+ references:
+ - https://www.alibabacloud.com/help/en/openapi/credentials
+ - https://www.alibabacloud.com/help/en/ram/developer-reference/api-sts-2015-04-01-assumerole
+ - name: Alibaba STS Security Token
+ id: kingfisher.alibabacloud.4
+ pattern: |
+ (?xi)
+ \b
+ (?:security[\s_-]*token|sts[\s_-]*token|x[\s_-]*oss[\s_-]*security[\s_-]*token|alibaba[\s_-]*cloud[\s_-]*security[\s_-]*token|aliyun[\s_-]*security[\s_-]*token)
+ (?:.|[\n\r]){0,16}?
+ (?:
+ [=:]
+ |
+ ["']\s*:\s*["']
+ )
+ \s*
+ ["']?
+ (
+ CAIS[A-Za-z0-9+/_=-]{20,1024}
+ )
+ (?:["'\s,;}&\]]|$)
+ min_entropy: 4.0
+ confidence: medium
+ visible: false
+ examples:
+ - securityToken = "CAISuwJ1q6Ft5B2yu9Kiaa5E0VnVJ8q2o3P4r5S6t7U8v9W0xYz"
+ - ALIBABA_CLOUD_SECURITY_TOKEN=CAIS/gF1q6Ft5B2yfSjIr5eDA9xjJCcl57eKC7A3ThnJA
+ references:
+ - https://www.alibabacloud.com/help/en/openapi/credentials
+ - https://www.alibabacloud.com/help/en/ram/developer-reference/api-sts-2015-04-01-assumerole
+ - name: Alibaba STS Access Key Secret
+ id: kingfisher.alibabacloud.5
+ pattern: |
+ (?x)
+ \b
+ (?:
+ (?i:alibaba|alibaba[\s_-]*cloud|aliyun|sts)
+ |
+ STS\.[A-Za-z0-9]{16,64}
+ )
+ (?:.|[\n\r]){0,120}?
+ (?i:access[\s_-]*key[\s_-]*secret|access[\s_-]*secret)
+ (?:.|[\n\r]){0,16}?
+ (?:
+ [=:]
+ |
+ ["']\s*:\s*["']
+ )
+ \s*
+ ["']?
+ (
+ [A-Za-z0-9]{30,64}
+ )
+ \b
+ ["']?
+ min_entropy: 4.2
+ confidence: medium
+ examples:
+ - STS.NTKaenSkmLhG4HpM576UV AccessKeySecret=wyLTSmsyPGP1ohvvw8xYgB29dlGI8KMiH2pK
+ - "aliyun sts access_key_secret: 6itECZnhbG2RU6ktTSBSd6JxeLHKPWyBtSS62"
+ validation:
+ type: Http
+ content:
+ request:
+ method: GET
+ url: >
+ {%- assign nonce = "" | uuid | upcase -%}
+ {%- assign raw_timestamp = "" | iso_timestamp_no_frac -%}
+ {%- assign timestamp = raw_timestamp | replace: ":", "%3A" -%}
+
+ {%- capture params -%}
+ AccessKeyId={{ STS_AKID | url_encode }}&Action=GetCallerIdentity&Format=JSON&SecurityToken={{ SECURITY_TOKEN | url_encode }}&SignatureMethod=HMAC-SHA1&SignatureNonce={{ nonce }}&SignatureVersion=1.0&Timestamp={{ timestamp }}&Version=2015-04-01
+ {%- endcapture -%}
+ {%- assign encoded_params = params | replace: "+", "%20" | replace: "*", "%2A" | replace: "%7E", "~" -%}
+ {%- assign query_string = encoded_params | url_encode | replace: "%2D", "-" | replace: "%2E", "." -%}
+
+ {%- assign signature_base_string = "GET&%2F&" | append: query_string -%}
+ {%- assign token_amp = TOKEN | append: "&" -%}
+
+ {%- assign hmacsignature = signature_base_string | hmac_sha1: token_amp | url_encode -%}
+
+ https://sts.aliyuncs.com/?{{ params }}&Signature={{ hmacsignature }}
+ headers:
+ Accept: application/json
+ response_matcher:
+ - report_response: true
+ - type: StatusMatch
+ status: [200]
+ - type: WordMatch
+ words: ['"Arn"']
+ references:
+ - https://www.alibabacloud.com/help/en/openapi/credentials
+ - https://www.alibabacloud.com/help/en/nas/request-signatures
+ - https://www.alibabacloud.com/help/en/ram/developer-reference/api-sts-2015-04-01-getcalleridentity
+ - https://www.alibabacloud.com/help/en/ram/developer-reference/api-sts-2015-04-01-assumerole
+ depends_on_rule:
+ - rule_id: kingfisher.alibabacloud.3
+ variable: STS_AKID
+ - rule_id: kingfisher.alibabacloud.4
+ variable: SECURITY_TOKEN
diff --git a/crates/kingfisher-rules/data/rules/builderio.yml b/crates/kingfisher-rules/data/rules/builderio.yml
new file mode 100644
index 0000000..ea5389b
--- /dev/null
+++ b/crates/kingfisher-rules/data/rules/builderio.yml
@@ -0,0 +1,23 @@
+rules:
+ - name: Builder.io Private API Key
+ id: kingfisher.builderio.1
+ pattern: |
+ (?x)
+ \b
+ (
+ bpk-[a-f0-9]{32}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 2
+ min_lowercase: 2
+ min_entropy: 3.5
+ confidence: medium
+ examples:
+ - 'BUILDER_PRIVATE_KEY=bpk-326204939cb941afb1431bf19bdc007d'
+ - 'builder_key: "bpk-7e3094a4265949f69b98a02b80e82cb8"'
+ - 'bpk-3d990a73da74423ca9ac00b9a2cf0f08'
+ references:
+ - https://www.builder.io/c/docs/using-your-api-key
+ - https://www.builder.io/c/docs/write-api
+ # No validation: documented Private API Key endpoints are mutating Write API calls.
diff --git a/crates/kingfisher-rules/data/rules/buttercms.yml b/crates/kingfisher-rules/data/rules/buttercms.yml
new file mode 100644
index 0000000..9f7c38b
--- /dev/null
+++ b/crates/kingfisher-rules/data/rules/buttercms.yml
@@ -0,0 +1,35 @@
+rules:
+ - name: ButterCMS API Key
+ id: kingfisher.buttercms.1
+ pattern: |
+ (?xi)
+ \b(?:butter(?:cms|_cms))
+ (?:.|[\n\r]){0,32}?
+ (?:API[_-]?(?:KEY|TOKEN)|SECRET|TOKEN|KEY)
+ (?:.|[\n\r]){0,16}?
+ \b
+ (
+ [a-z0-9]{40}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 3
+ min_entropy: 3.5
+ confidence: medium
+ examples:
+ - 'BUTTERCMS_API_TOKEN=a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0'
+ references:
+ - https://buttercms.com/docs/api/
+ validation:
+ type: Http
+ content:
+ request:
+ method: GET
+ url: "https://api.buttercms.com/v2/posts/?auth_token={{ TOKEN }}&page_size=1"
+ headers:
+ Accept: application/json
+ response_matcher:
+ - report_response: true
+ - type: StatusMatch
+ status: [200]
+ - type: JsonValid
diff --git a/crates/kingfisher-rules/data/rules/censys.yml b/crates/kingfisher-rules/data/rules/censys.yml
new file mode 100644
index 0000000..58fa708
--- /dev/null
+++ b/crates/kingfisher-rules/data/rules/censys.yml
@@ -0,0 +1,62 @@
+rules:
+ - name: Censys API ID
+ id: kingfisher.censys.1
+ visible: false
+ pattern: |
+ (?xi)
+ \b
+ censys
+ (?:.|[\n\r]){0,32}?
+ (?:API[_-]?ID|APP[_-]?ID|ID)
+ (?:.|[\n\r]){0,16}?
+ \b
+ (
+ [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}
+ )
+ \b
+ min_entropy: 3.0
+ confidence: medium
+ examples:
+ - 'CENSYS_API_ID=a1b2c3d4-e5f6-7890-abcd-ef1234567890'
+
+ - name: Censys API Secret
+ id: kingfisher.censys.2
+ pattern: |
+ (?xi)
+ \b
+ censys
+ (?:.|[\n\r]){0,32}?
+ (?:SECRET|API[_-]?SECRET|KEY|TOKEN)
+ (?:.|[\n\r]){0,16}?
+ \b
+ (
+ [A-Za-z0-9]{32}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 3
+ min_uppercase: 3
+ min_lowercase: 3
+ min_entropy: 3.5
+ confidence: medium
+ examples:
+ - 'CENSYS_API_SECRET=aBcDeFgHiJkLmNoPqRsTuVwXyZ012345'
+ references:
+ - https://search.censys.io/api
+ depends_on_rule:
+ - rule_id: kingfisher.censys.1
+ variable: CENSYS_API_ID
+ validation:
+ type: Http
+ content:
+ request:
+ method: GET
+ url: https://search.censys.io/api/v1/account
+ headers:
+ Accept: application/json
+ Authorization: "Basic {{ CENSYS_API_ID | append: ':' | append: TOKEN | b64enc }}"
+ response_matcher:
+ - report_response: true
+ - type: StatusMatch
+ status: [200]
+ - type: JsonValid
diff --git a/crates/kingfisher-rules/data/rules/chartmogul.yml b/crates/kingfisher-rules/data/rules/chartmogul.yml
new file mode 100644
index 0000000..42cdb52
--- /dev/null
+++ b/crates/kingfisher-rules/data/rules/chartmogul.yml
@@ -0,0 +1,40 @@
+rules:
+ - name: ChartMogul API Key
+ id: kingfisher.chartmogul.1
+ pattern: |
+ (?xi)
+ \b
+ chartmogul
+ (?:.|[\n\r]){0,32}?
+ (?:API[_-]?KEY|SECRET|TOKEN|KEY)
+ (?:.|[\n\r]){0,16}?
+ \b
+ (
+ [a-z0-9]{32}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 3
+ min_entropy: 3.5
+ confidence: medium
+ examples:
+ - 'CHARTMOGUL_API_KEY=a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6'
+ references:
+ - https://dev.chartmogul.com/reference/authentication
+ validation:
+ type: Http
+ content:
+ request:
+ method: GET
+ url: https://api.chartmogul.com/v1/ping
+ headers:
+ Accept: application/json
+ Authorization: "Basic {{ TOKEN | append: ':' | b64enc }}"
+ response_matcher:
+ - report_response: true
+ - type: StatusMatch
+ status: [200]
+ - type: JsonValid
+ - type: WordMatch
+ words:
+ - '"pong"'
diff --git a/crates/kingfisher-rules/data/rules/clickup.yml b/crates/kingfisher-rules/data/rules/clickup.yml
new file mode 100644
index 0000000..6082d59
--- /dev/null
+++ b/crates/kingfisher-rules/data/rules/clickup.yml
@@ -0,0 +1,39 @@
+rules:
+ - name: ClickUp Personal API Token
+ id: kingfisher.clickup.1
+ pattern: |
+ (?xi)
+ \b
+ clickup
+ (?:.|[\n\r]){0,32}?
+ (?:API[_-]?KEY|SECRET|TOKEN|KEY)
+ (?:.|[\n\r]){0,16}?
+ \b
+ (
+ pk_[0-9]{7,9}_[0-9A-Z]{32}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 8
+ min_uppercase: 4
+ min_entropy: 3.5
+ confidence: medium
+ examples:
+ - 'CLICKUP_API_TOKEN=pk_4753994_EXP7MPOJ7XQM5UJDV2M45MPF0YHH5YHO'
+ - 'clickup_token: "pk_12345678_A1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6"'
+ references:
+ - https://clickup.com/api/
+ validation:
+ type: Http
+ content:
+ request:
+ method: GET
+ url: https://api.clickup.com/api/v2/user
+ headers:
+ Accept: application/json
+ Authorization: "{{ TOKEN }}"
+ response_matcher:
+ - report_response: true
+ - type: StatusMatch
+ status: [200]
+ - type: JsonValid
diff --git a/crates/kingfisher-rules/data/rules/closecrm.yml b/crates/kingfisher-rules/data/rules/closecrm.yml
new file mode 100644
index 0000000..a654887
--- /dev/null
+++ b/crates/kingfisher-rules/data/rules/closecrm.yml
@@ -0,0 +1,35 @@
+rules:
+ - name: Close CRM API Key
+ id: kingfisher.closecrm.1
+ pattern: |
+ (?xi)
+ \b
+ (
+ api_[A-Za-z0-9]{18,26}\.[A-Za-z0-9]{18,26}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 2
+ min_uppercase: 2
+ min_lowercase: 2
+ min_entropy: 3.5
+ confidence: medium
+ examples:
+ - 'CLOSE_API_KEY=api_7b8KOSMa0OevK9qJvT6F9s.2H3Bt8ktGaQ9kVK45P7j7p'
+ - 'close_key: "api_aBcDeFgHiJkLmNoPqRsT.uVwXyZ0123456789abcD"'
+ references:
+ - https://developer.close.com/
+ validation:
+ type: Http
+ content:
+ request:
+ method: GET
+ url: https://api.close.com/api/v1/me/
+ headers:
+ Accept: application/json
+ Authorization: "Basic {{ TOKEN | append: ':' | b64enc }}"
+ response_matcher:
+ - report_response: true
+ - type: StatusMatch
+ status: [200]
+ - type: JsonValid
diff --git a/crates/kingfisher-rules/data/rules/configcat.yml b/crates/kingfisher-rules/data/rules/configcat.yml
new file mode 100644
index 0000000..7feeac6
--- /dev/null
+++ b/crates/kingfisher-rules/data/rules/configcat.yml
@@ -0,0 +1,69 @@
+rules:
+ - name: ConfigCat SDK Key
+ id: kingfisher.configcat.1
+ pattern: |
+ (?xi)
+ \b
+ configcat
+ (?:.|[\n\r]){0,32}?
+ (?:API[_-]?KEY|SECRET|TOKEN|KEY)
+ [\s:=}"']{1,16}
+ (
+ [A-Za-z0-9_-]{22}/[A-Za-z0-9_-]{22}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 2
+ min_uppercase: 2
+ min_lowercase: 2
+ min_entropy: 3.5
+ confidence: medium
+ examples:
+ - 'CONFIGCAT_SDK_KEY=PKDVCLf-Hq-h-kCzMp-L7Q/psuH7BGHoUmdONrzzUOY7A'
+ - 'configcat_key: "PKDVCLf-Hq-h-kCzMp-L7Q/psuH7BGHoUmdONrzzUOY7A"'
+ references:
+ - https://configcat.com/docs/sdk-reference/overview/
+ validation:
+ type: Http
+ content:
+ request:
+ method: GET
+ url: "https://cdn-global.configcat.com/configuration-files/{{ TOKEN }}/config_v6.json"
+ headers:
+ Accept: application/json
+ response_matcher:
+ - report_response: true
+ - type: StatusMatch
+ status: [200]
+ - type: JsonValid
+
+ - name: ConfigCat SDK Key (Extended)
+ id: kingfisher.configcat.2
+ pattern: |
+ (?xi)
+ \b
+ (
+ configcat-sdk-1/[A-Za-z0-9_-]{22}/[A-Za-z0-9_-]{22}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 2
+ min_entropy: 3.5
+ confidence: medium
+ examples:
+ - 'CONFIGCAT_SDK_KEY=configcat-sdk-1/PKDVCLf-Hq-h-kCzMp-L7Q/psuH7BGHoUmdONrzzUOY7A'
+ references:
+ - https://configcat.com/docs/sdk-reference/overview/
+ validation:
+ type: Http
+ content:
+ request:
+ method: GET
+ url: "https://cdn-global.configcat.com/configuration-files/{{ TOKEN }}/config_v6.json"
+ headers:
+ Accept: application/json
+ response_matcher:
+ - report_response: true
+ - type: StatusMatch
+ status: [200]
+ - type: JsonValid
diff --git a/crates/kingfisher-rules/data/rules/detectify.yml b/crates/kingfisher-rules/data/rules/detectify.yml
new file mode 100644
index 0000000..b13ed24
--- /dev/null
+++ b/crates/kingfisher-rules/data/rules/detectify.yml
@@ -0,0 +1,37 @@
+rules:
+ - name: Detectify API Key
+ id: kingfisher.detectify.1
+ pattern: |
+ (?xi)
+ \b
+ detectify
+ (?:.|[\n\r]){0,32}?
+ (?:API[_-]?KEY|SECRET|TOKEN|KEY)
+ (?:.|[\n\r]){0,16}?
+ \b
+ (
+ [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 4
+ min_entropy: 3.5
+ confidence: medium
+ examples:
+ - 'DETECTIFY_API_KEY=2230dbea-051a-47f1-bc1d-c1b73b609420'
+ references:
+ - https://developer.detectify.com/
+ validation:
+ type: Http
+ content:
+ request:
+ method: GET
+ url: https://api.detectify.com/rest/v3/ips?limit=1
+ headers:
+ Accept: application/json
+ Authorization: "{{ TOKEN }}"
+ response_matcher:
+ - report_response: true
+ - type: StatusMatch
+ status: [200]
+ - type: JsonValid
diff --git a/crates/kingfisher-rules/data/rules/ghost.yml b/crates/kingfisher-rules/data/rules/ghost.yml
new file mode 100644
index 0000000..52d823c
--- /dev/null
+++ b/crates/kingfisher-rules/data/rules/ghost.yml
@@ -0,0 +1,50 @@
+rules:
+ - name: Ghost CMS Admin API Key
+ id: kingfisher.ghost.1
+ pattern: |
+ (?xi)
+ \b
+ ghost
+ (?:.|[\n\r]){0,32}?
+ (?:ADMIN|SECRET|TOKEN|KEY)
+ (?:.|[\n\r]){0,16}?
+ \b
+ (
+ [0-9a-f]{24}:[0-9a-f]{64}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 4
+ min_lowercase: 4
+ min_entropy: 3.5
+ confidence: medium
+ examples:
+ - 'GHOST_ADMIN_API_KEY=1efedd9db174adee2d23d982:4b74dca0219bad629852191af326a45037346c2231240e0f7aec1f9371cc14e8'
+ - 'ghost_key = "6101c750c9d0ab0e34567890:abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"'
+ references:
+ - https://ghost.org/docs/admin-api/
+ - https://ghost.org/docs/admin-api/#token-authentication
+
+ - name: Ghost CMS Content API Key
+ id: kingfisher.ghost.2
+ pattern: |
+ (?xi)
+ \b(?:ghost|content[_-]?api)
+ (?:.|[\n\r]){0,48}?
+ (?:KEY|TOKEN|SECRET|API)
+ (?:.|[\n\r]){0,24}?
+ \b
+ (
+ [0-9a-f]{26}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 3
+ min_entropy: 3.0
+ confidence: medium
+ examples:
+ - 'GHOST_CONTENT_API_KEY=22444f78447824223cefc48062'
+ - 'ghost_api_key: "a1b2c3d4e5f6a7b8c9d0e1f2a3"'
+ references:
+ - https://ghost.org/docs/content-api/
+ # No validation: Ghost Content API keys are site-specific and require the Ghost site URL.
diff --git a/crates/kingfisher-rules/data/rules/hetzner.yml b/crates/kingfisher-rules/data/rules/hetzner.yml
new file mode 100644
index 0000000..4fffdd8
--- /dev/null
+++ b/crates/kingfisher-rules/data/rules/hetzner.yml
@@ -0,0 +1,39 @@
+rules:
+ - name: Hetzner Cloud API Token
+ id: kingfisher.hetzner.1
+ pattern: |
+ (?xi)
+ \b(?:hetzner|hcloud)
+ (?:.|[\n\r]){0,48}?
+ (?:API[_-]?TOKEN|TOKEN|SECRET|KEY)
+ (?:.|[\n\r]){0,24}?
+ \b
+ (
+ [A-Za-z0-9]{64}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 3
+ min_uppercase: 3
+ min_lowercase: 3
+ min_entropy: 4.0
+ confidence: medium
+ examples:
+ - 'HETZNER_API_TOKEN=CqM049yakVZO8EndHyyawia3EjIboWMVeoEeMW0UVN0SpTXryKh0zrtnGpeyAjTs'
+ - 'HCLOUD_TOKEN=aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789aBcDeFgHiJkLmNoPqRsTuVwXy012'
+ references:
+ - https://docs.hetzner.cloud/
+ validation:
+ type: Http
+ content:
+ request:
+ method: GET
+ url: https://api.hetzner.cloud/v1/servers?per_page=1
+ headers:
+ Accept: application/json
+ Authorization: "Bearer {{ TOKEN }}"
+ response_matcher:
+ - report_response: true
+ - type: StatusMatch
+ status: [200]
+ - type: JsonValid
diff --git a/crates/kingfisher-rules/data/rules/livekit.yml b/crates/kingfisher-rules/data/rules/livekit.yml
new file mode 100644
index 0000000..9d50693
--- /dev/null
+++ b/crates/kingfisher-rules/data/rules/livekit.yml
@@ -0,0 +1,52 @@
+rules:
+ - name: LiveKit API Key
+ id: kingfisher.livekit.1
+ visible: false
+ pattern: |
+ (?xi)
+ \b(?:livekit|LIVEKIT)
+ (?:.|[\n\r]){0,32}?
+ (?:API[_-]?KEY|KEY|ACCESS)
+ (?:.|[\n\r]){0,16}?
+ \b
+ (
+ API[A-Za-z0-9]{12}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 1
+ min_uppercase: 3
+ min_entropy: 2.5
+ confidence: medium
+ examples:
+ - 'LIVEKIT_API_KEY=APIa3B4c5D6e7F8'
+ - 'livekit_key: "API2K4m6N8p3R5s"'
+ references:
+ - https://docs.livekit.io/home/get-started/authentication/
+
+ - name: LiveKit API Secret
+ id: kingfisher.livekit.2
+ pattern: |
+ (?xi)
+ \b(?:livekit|LIVEKIT)
+ (?:.|[\n\r]){0,32}?
+ (?:SECRET|PRIVATE|ACCESS)
+ (?:.|[\n\r]){0,16}?
+ \b
+ (
+ [A-Za-z0-9]{40,48}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 3
+ min_uppercase: 3
+ min_lowercase: 3
+ min_entropy: 4.0
+ confidence: medium
+ examples:
+ - 'LIVEKIT_API_SECRET=aBcDeFgHiJkLmNoPqRsTuVwXyZ01234567890abcde'
+ references:
+ - https://docs.livekit.io/home/get-started/authentication/
+ depends_on_rule:
+ - rule_id: kingfisher.livekit.1
+ variable: LIVEKIT_API_KEY
diff --git a/crates/kingfisher-rules/data/rules/loops.yml b/crates/kingfisher-rules/data/rules/loops.yml
new file mode 100644
index 0000000..97c3bde
--- /dev/null
+++ b/crates/kingfisher-rules/data/rules/loops.yml
@@ -0,0 +1,41 @@
+rules:
+ - name: Loops Email API Key
+ id: kingfisher.loops.1
+ pattern: |
+ (?xi)
+ \b
+ loops
+ (?:.|[\n\r]){0,32}?
+ (?:API[_-]?KEY|SECRET|TOKEN|KEY)
+ (?:.|[\n\r]){0,16}?
+ \b
+ (
+ [0-9a-f]{32}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 3
+ min_entropy: 3.5
+ confidence: medium
+ examples:
+ - 'LOOPS_API_KEY=d2d561f5ff80136f69b4b5a31b9fb3c9'
+ references:
+ - https://loops.so/docs/api-reference/intro
+ validation:
+ type: Http
+ content:
+ request:
+ method: GET
+ url: https://app.loops.so/api/v1/api-key
+ headers:
+ Accept: application/json
+ Authorization: "Bearer {{ TOKEN }}"
+ response_matcher:
+ - report_response: true
+ - type: StatusMatch
+ status: [200]
+ - type: WordMatch
+ words:
+ - '"success"'
+ - 'true'
+ match_all_words: true
diff --git a/crates/kingfisher-rules/data/rules/moralis.yml b/crates/kingfisher-rules/data/rules/moralis.yml
new file mode 100644
index 0000000..3a34d78
--- /dev/null
+++ b/crates/kingfisher-rules/data/rules/moralis.yml
@@ -0,0 +1,39 @@
+rules:
+ - name: Moralis API Key
+ id: kingfisher.moralis.1
+ pattern: |
+ (?xi)
+ \b
+ moralis
+ (?:.|[\n\r]){0,32}?
+ (?:API[_-]?KEY|SECRET|TOKEN|KEY|WEB3)
+ (?:.|[\n\r]){0,16}?
+ \b
+ (
+ [0-9a-zA-Z]{64}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 3
+ min_uppercase: 3
+ min_lowercase: 3
+ min_entropy: 4.0
+ confidence: medium
+ examples:
+ - 'MORALIS_API_KEY=aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789aBcDeFgHiJkLmNoPqRsTuVwXy012'
+ references:
+ - https://docs.moralis.io/web3-data-api/evm/reference
+ validation:
+ type: Http
+ content:
+ request:
+ method: GET
+ url: https://deep-index.moralis.io/api/v2.2/web3/version
+ headers:
+ Accept: application/json
+ X-API-Key: "{{ TOKEN }}"
+ response_matcher:
+ - report_response: true
+ - type: StatusMatch
+ status: [200]
+ - type: JsonValid
diff --git a/crates/kingfisher-rules/data/rules/pandadoc.yml b/crates/kingfisher-rules/data/rules/pandadoc.yml
new file mode 100644
index 0000000..d0c4fa0
--- /dev/null
+++ b/crates/kingfisher-rules/data/rules/pandadoc.yml
@@ -0,0 +1,38 @@
+rules:
+ - name: PandaDoc API Key
+ id: kingfisher.pandadoc.1
+ pattern: |
+ (?xi)
+ \b(?:pandadoc)
+ (?:.|[\n\r]){0,32}?
+ (?:API[_-]?KEY|SECRET|TOKEN|KEY)
+ (?:.|[\n\r]){0,16}?
+ \b
+ (
+ [a-zA-Z0-9]{40}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 3
+ min_uppercase: 3
+ min_lowercase: 3
+ min_entropy: 3.5
+ confidence: medium
+ examples:
+ - 'PANDADOC_API_KEY=aBcDeFgHiJkLmNoPqRsTuVwXyZ01234567890abc'
+ references:
+ - https://developers.pandadoc.com/reference/about
+ validation:
+ type: Http
+ content:
+ request:
+ method: GET
+ url: https://api.pandadoc.com/public/v1/documents?count=1
+ headers:
+ Accept: application/json
+ Authorization: "API-Key {{ TOKEN }}"
+ response_matcher:
+ - report_response: true
+ - type: StatusMatch
+ status: [200]
+ - type: JsonValid
diff --git a/crates/kingfisher-rules/data/rules/permitio.yml b/crates/kingfisher-rules/data/rules/permitio.yml
new file mode 100644
index 0000000..f0e267b
--- /dev/null
+++ b/crates/kingfisher-rules/data/rules/permitio.yml
@@ -0,0 +1,35 @@
+rules:
+ - name: Permit.io API Key
+ id: kingfisher.permitio.1
+ pattern: |
+ (?x)
+ \b
+ (
+ permit_key_[0-9A-Za-z]{85,86}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 2
+ min_uppercase: 2
+ min_lowercase: 2
+ min_entropy: 3.5
+ confidence: medium
+ examples:
+ - 'PERMIT_API_KEY=permit_key_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVW'
+ - 'permit_key: "permit_key_9876543210zyxwvutsrqponmlkjihgfedcbaZYXWVUTSRQPONMLKJIHGFEDCBA9876543210zyxwvutsrqponm"'
+ references:
+ - https://docs.permit.io/overview/get-api-key/
+ validation:
+ type: Http
+ content:
+ request:
+ method: GET
+ url: https://api.permit.io/v2/api-key/scope
+ headers:
+ Accept: application/json
+ Authorization: "Bearer {{ TOKEN }}"
+ response_matcher:
+ - report_response: true
+ - type: StatusMatch
+ status: [200]
+ - type: JsonValid
diff --git a/crates/kingfisher-rules/data/rules/pinata.yml b/crates/kingfisher-rules/data/rules/pinata.yml
new file mode 100644
index 0000000..b44cb6a
--- /dev/null
+++ b/crates/kingfisher-rules/data/rules/pinata.yml
@@ -0,0 +1,66 @@
+rules:
+ - name: Pinata API Key
+ id: kingfisher.pinata.1
+ visible: false
+ pattern: |
+ (?xi)
+ \b
+ pinata
+ (?:.|[\n\r]){0,32}?
+ (?:API[_-]?KEY|KEY)
+ (?:.|[\n\r]){0,16}?
+ \b
+ (
+ [0-9a-f]{64}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 4
+ min_entropy: 3.5
+ confidence: medium
+ examples:
+ - 'PINATA_API_KEY=a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2'
+
+ - name: Pinata API Secret
+ id: kingfisher.pinata.2
+ pattern: |
+ (?xi)
+ \b
+ pinata
+ (?:.|[\n\r]){0,32}?
+ (?:API[_-]?SECRET|SECRET[_-]?KEY|SECRET)
+ (?:.|[\n\r]){0,16}?
+ \b
+ (
+ [0-9a-f]{64}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 4
+ min_entropy: 3.5
+ confidence: medium
+ examples:
+ - 'PINATA_API_SECRET=f0e1d2c3b4a5f6e7d8c9b0a1f2e3d4c5b6a7f8e9d0c1b2a3f4e5d6c7b8a9f0e1'
+ references:
+ - https://docs.pinata.cloud/api-reference/introduction
+ depends_on_rule:
+ - rule_id: kingfisher.pinata.1
+ variable: PINATA_API_KEY
+ validation:
+ type: Http
+ content:
+ request:
+ method: GET
+ url: https://api.pinata.cloud/data/testAuthentication
+ headers:
+ Accept: application/json
+ pinata_api_key: "{{ PINATA_API_KEY }}"
+ pinata_secret_api_key: "{{ TOKEN }}"
+ response_matcher:
+ - report_response: true
+ - type: StatusMatch
+ status: [200]
+ - type: WordMatch
+ words:
+ - '"message"'
+ - 'Congratulations'
diff --git a/crates/kingfisher-rules/data/rules/portainer.yml b/crates/kingfisher-rules/data/rules/portainer.yml
new file mode 100644
index 0000000..4e48690
--- /dev/null
+++ b/crates/kingfisher-rules/data/rules/portainer.yml
@@ -0,0 +1,22 @@
+rules:
+ - name: Portainer API Token
+ id: kingfisher.portainer.1
+ pattern: |
+ (?x)
+ \b
+ (
+ ptr_[A-Za-z0-9/+_=-]{32,52}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 2
+ min_uppercase: 2
+ min_lowercase: 2
+ min_entropy: 3.5
+ confidence: medium
+ examples:
+ - 'PORTAINER_API_KEY=ptr_aBcDeFgHiJkLmNoPqRsTuVwXyZ012345678901'
+ - 'portainer_token: "ptr_xY9zW8vU7tS6rQ5pN4mL3kJ2iH1gF0eD9cB8aZ7"'
+ references:
+ - https://docs.portainer.io/api/access
+ # No validation: Portainer API tokens require the user's Portainer server URL.
diff --git a/crates/kingfisher-rules/data/rules/robinhood.yml b/crates/kingfisher-rules/data/rules/robinhood.yml
new file mode 100644
index 0000000..fd63eee
--- /dev/null
+++ b/crates/kingfisher-rules/data/rules/robinhood.yml
@@ -0,0 +1,21 @@
+rules:
+ - name: Robinhood Crypto API Key
+ id: kingfisher.robinhood.1
+ pattern: |
+ (?x)
+ \b
+ (
+ rh-api-
+ [0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 4
+ min_entropy: 3.0
+ confidence: medium
+ examples:
+ - 'ROBINHOOD_API_KEY=rh-api-a1b2c3d4-e5f6-7890-abcd-ef1234567890'
+ - 'rh_api_key: "rh-api-12345678-abcd-ef01-2345-6789abcdef01"'
+ references:
+ - https://docs.robinhood.com/crypto/trading/
+ # No validation: Robinhood Crypto requests require an API key plus Ed25519 request signing.
diff --git a/crates/kingfisher-rules/data/rules/saladcloud.yml b/crates/kingfisher-rules/data/rules/saladcloud.yml
new file mode 100644
index 0000000..56cbf3d
--- /dev/null
+++ b/crates/kingfisher-rules/data/rules/saladcloud.yml
@@ -0,0 +1,34 @@
+rules:
+ - name: SaladCloud API Key
+ id: kingfisher.saladcloud.1
+ pattern: |
+ (?x)
+ \b
+ (
+ salad_cloud_[0-9A-Za-z]{1,7}_[0-9A-Za-z]{7,40}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 2
+ min_lowercase: 4
+ min_entropy: 3.0
+ confidence: medium
+ examples:
+ - 'SALAD_API_KEY=salad_cloud_abc1234_xY9zW8vU7tS6rQ5pN4mL3kJ2iH1gF0e'
+ - 'salad_key: "salad_cloud_org42_a1B2c3D4e5F6g7H8i9J0"'
+ references:
+ - https://docs.salad.com/reference/api-reference
+ validation:
+ type: Http
+ content:
+ request:
+ method: GET
+ url: https://api.salad.com/api/public/organizations
+ headers:
+ Accept: application/json
+ Salad-Api-Key: "{{ TOKEN }}"
+ response_matcher:
+ - report_response: true
+ - type: StatusMatch
+ status: [200]
+ - type: JsonValid
diff --git a/crates/kingfisher-rules/data/rules/tigris.yml b/crates/kingfisher-rules/data/rules/tigris.yml
new file mode 100644
index 0000000..5a6040b
--- /dev/null
+++ b/crates/kingfisher-rules/data/rules/tigris.yml
@@ -0,0 +1,45 @@
+rules:
+ - name: Tigris Access Key ID
+ id: kingfisher.tigris.1
+ visible: false
+ pattern: |
+ (?x)
+ \b
+ (
+ tid_[A-Za-z0-9_]{43,55}
+ )
+ \b
+ pattern_requirements:
+ min_uppercase: 4
+ min_lowercase: 4
+ min_entropy: 3.5
+ confidence: medium
+ examples:
+ - 'TIGRIS_ACCESS_KEY=tid_zkrUeBLpqV_TOdaZzjYefcGEZJrZJqQHvmidyMx_VJtknmcWhC'
+ - 'AWS_ACCESS_KEY_ID=tid_sIYWNboOecJPzFPmgbOmxsfSqjwbmYmSoGAlrylliULbhiysCJ'
+ references:
+ - https://www.tigrisdata.com/docs/concepts/authnz/
+
+ - name: Tigris Secret Access Key
+ id: kingfisher.tigris.2
+ pattern: |
+ (?xi)
+ \b
+ (
+ tsec_[A-Za-z0-9_]{43,55}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 2
+ min_uppercase: 4
+ min_lowercase: 4
+ min_entropy: 3.5
+ confidence: medium
+ examples:
+ - 'TIGRIS_SECRET_KEY=tsec_pQrStUvWxYzAbCdEfGhIjKlMnOpQrStUvWxYz_012345678aB'
+ - 'AWS_SECRET_ACCESS_KEY=tsec_mNbVcXzAsWqErTyUiOpLkJhGfDsAzXcVbNmQwErTyUi_9876'
+ references:
+ - https://www.tigrisdata.com/docs/concepts/authnz/
+ depends_on_rule:
+ - rule_id: kingfisher.tigris.1
+ variable: TIGRIS_ACCESS_KEY
diff --git a/crates/kingfisher-rules/data/rules/unleash.yml b/crates/kingfisher-rules/data/rules/unleash.yml
new file mode 100644
index 0000000..bd49e6f
--- /dev/null
+++ b/crates/kingfisher-rules/data/rules/unleash.yml
@@ -0,0 +1,52 @@
+rules:
+ - name: Unleash Client/Admin API Token
+ id: kingfisher.unleash.1
+ pattern: |
+ (?xi)
+ \b
+ unleash
+ (?:.|[\n\r]){0,32}?
+ (?:API[_-]?TOKEN|CLIENT[_-]?KEY|ADMIN[_-]?TOKEN|TOKEN|KEY)
+ (?:.|[\n\r]){0,16}?
+ (
+ (?:\*|\[\]|[a-z][a-z0-9-]*)
+ :
+ [a-z][a-z0-9-]*
+ \.
+ [0-9a-f]{56}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 4
+ min_lowercase: 10
+ min_entropy: 3.0
+ confidence: medium
+ examples:
+ - 'UNLEASH_API_TOKEN=default:development.be44368985f7fb3237c584ef86f3d6bdada42ddbd63a019d26955178'
+ - 'unleash_token: "*:production.a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8"'
+ references:
+ - https://docs.getunleash.io/reference/api-tokens-and-client-keys
+
+ - name: Unleash Personal Access Token
+ id: kingfisher.unleash.2
+ pattern: |
+ (?xi)
+ \b
+ unleash
+ (?:.|[\n\r]){0,32}?
+ (?:PAT|PERSONAL[_-]?ACCESS[_-]?TOKEN|API[_-]?TOKEN|TOKEN|KEY)
+ (?:.|[\n\r]){0,16}?
+ \b
+ (
+ user:[0-9a-f]{56}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 4
+ min_entropy: 3.5
+ confidence: medium
+ examples:
+ - 'UNLEASH_PAT=user:be7536c3a160ff15e3a92da45de531dd54bc1ae15d8455c0476f086b'
+ - 'unleash_pat: "user:a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8"'
+ references:
+ - https://docs.getunleash.io/reference/api-tokens-and-client-keys
diff --git a/crates/kingfisher-rules/data/rules/upcloud.yml b/crates/kingfisher-rules/data/rules/upcloud.yml
new file mode 100644
index 0000000..113f9a8
--- /dev/null
+++ b/crates/kingfisher-rules/data/rules/upcloud.yml
@@ -0,0 +1,35 @@
+rules:
+ - name: UpCloud API Token
+ id: kingfisher.upcloud.1
+ pattern: |
+ (?xi)
+ \b
+ (
+ ucat_[0-9A-HJKMNP-TV-Z]{26}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 2
+ min_uppercase: 4
+ min_entropy: 3.5
+ confidence: medium
+ examples:
+ - 'UPCLOUD_API_TOKEN=ucat_01DQE3AJDEBFEKECFM558TGH2F'
+ - 'upcloud_token: "ucat_01J9K4BNZM3RGXW7VDQFTHY5PC"'
+ references:
+ - https://upcloud.com/docs/guides/managing-api-tokens/
+ - https://developers.upcloud.com/1.3/24-api-tokens/
+ validation:
+ type: Http
+ content:
+ request:
+ method: GET
+ url: https://api.upcloud.com/1.3/account
+ headers:
+ Accept: application/json
+ Authorization: "Bearer {{ TOKEN }}"
+ response_matcher:
+ - report_response: true
+ - type: StatusMatch
+ status: [200]
+ - type: JsonValid
diff --git a/crates/kingfisher-rules/data/rules/voiceflow.yml b/crates/kingfisher-rules/data/rules/voiceflow.yml
new file mode 100644
index 0000000..dbf372a
--- /dev/null
+++ b/crates/kingfisher-rules/data/rules/voiceflow.yml
@@ -0,0 +1,43 @@
+rules:
+ - name: Voiceflow API Key
+ id: kingfisher.voiceflow.1
+ pattern: |
+ (?xi)
+ \b
+ (
+ VF\.(?:(?:DM|WS)\.)
+ [0-9a-f]{24}
+ \.
+ [0-9a-zA-Z]{16}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 3
+ min_lowercase: 4
+ min_entropy: 3.0
+ confidence: medium
+ examples:
+ - 'VOICEFLOW_API_KEY=VF.DM.6421e3d5b1e4a9001d2b7c8f.a1B2c3D4e5F6g7H8'
+ - 'voiceflow_key: "VF.WS.53a1b2c3d4e5f6001a2b3c4d.xY9zW8vU7tS6rQ5p"'
+ references:
+ - https://developer.voiceflow.com/reference/overview
+ validation:
+ type: Http
+ content:
+ request:
+ method: POST
+ url: https://general-runtime.voiceflow.com/knowledge-base/query
+ headers:
+ Accept: application/json
+ Authorization: "{{ TOKEN }}"
+ Content-Type: application/json
+ body: |
+ {"question": "test"}
+ response_matcher:
+ - report_response: true
+ - type: StatusMatch
+ status: [200, 400, 404]
+ - type: WordMatch
+ negative: true
+ words:
+ - '"Unauthorized"'
diff --git a/crates/kingfisher-rules/data/rules/wistia.yml b/crates/kingfisher-rules/data/rules/wistia.yml
new file mode 100644
index 0000000..b4da6c8
--- /dev/null
+++ b/crates/kingfisher-rules/data/rules/wistia.yml
@@ -0,0 +1,36 @@
+rules:
+ - name: Wistia API Token
+ id: kingfisher.wistia.1
+ pattern: |
+ (?xi)
+ \b
+ wistia
+ (?:.|[\n\r]){0,32}?
+ (?:API[_-]?(?:KEY|TOKEN|PASSWORD)|TOKEN|SECRET|KEY)
+ (?:.|[\n\r]){0,16}?
+ \b
+ (
+ [0-9a-f]{64}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 4
+ min_entropy: 3.5
+ confidence: medium
+ examples:
+ - 'WISTIA_API_TOKEN=a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2'
+ references:
+ - https://wistia.com/support/developers/data-api
+ validation:
+ type: Http
+ content:
+ request:
+ method: GET
+ url: "https://api.wistia.com/v1/account.json?api_password={{ TOKEN }}"
+ headers:
+ Accept: application/json
+ response_matcher:
+ - report_response: true
+ - type: StatusMatch
+ status: [200]
+ - type: JsonValid
diff --git a/crates/kingfisher-rules/data/rules/zerotier.yml b/crates/kingfisher-rules/data/rules/zerotier.yml
new file mode 100644
index 0000000..23b9977
--- /dev/null
+++ b/crates/kingfisher-rules/data/rules/zerotier.yml
@@ -0,0 +1,40 @@
+rules:
+ - name: ZeroTier API Token
+ id: kingfisher.zerotier.1
+ pattern: |
+ (?xi)
+ \b
+ (?:zerotier|zt)
+ (?:.|[\n\r]){0,32}?
+ (?:API[_-]?(?:TOKEN|KEY)|TOKEN|SECRET|KEY|ACCESS)
+ (?:.|[\n\r]){0,16}?
+ \b
+ (
+ [A-Za-z0-9]{32}
+ )
+ \b
+ pattern_requirements:
+ min_digits: 3
+ min_uppercase: 3
+ min_lowercase: 3
+ min_entropy: 3.5
+ confidence: medium
+ examples:
+ - 'ZEROTIER_API_TOKEN=aBcDeFgHiJkLmNoPqRsTuVwXyZ012345'
+ - 'ZT_TOKEN=xY9zW8vU7tS6rQ5pN4mL3kJ2iH1gF0eD'
+ references:
+ - https://docs.zerotier.com/api/tokens/
+ validation:
+ type: Http
+ content:
+ request:
+ method: GET
+ url: https://api.zerotier.com/api/v1/status
+ headers:
+ Accept: application/json
+ Authorization: "token {{ TOKEN }}"
+ response_matcher:
+ - report_response: true
+ - type: StatusMatch
+ status: [200]
+ - type: JsonValid
diff --git a/docs-site/docs/changelog.md b/docs-site/docs/changelog.md
index ff04027..b9084ad 100644
--- a/docs-site/docs/changelog.md
+++ b/docs-site/docs/changelog.md
@@ -7,9 +7,13 @@ description: "Kingfisher release history: new features, rules, bug fixes, and im
All notable changes to this project will be documented in this file.
-## [v1.97.0]
+## [v1.96.0]
- Added live HTTP validation for 18 rules across 15 providers: Val Town, Polar, hCaptcha, Thunderstore, Elastic Cloud (2 rules), LlamaCloud, Gemfury (2 rules), Vonage, ThingsBoard, Zapier, Facebook Access Token, GitLab Session Cookie, PostHog Feature Flags, Unkey API Key, and Hop.io (2 rules).
- Added revocation support for 7 rules across 6 providers: Discord webhooks (single-step DELETE), DigitalOcean PATs (self-revoke via OAuth), and multi-step HttpMultiStep revocation for LaunchDarkly, Resend, Linode, and Netlify (2 rules). Built-in revocation coverage is now 34 provider families with 53 revocation-enabled rules.
+- Expanded Alibaba Cloud coverage with STS temporary credential detection for STS access key IDs, STS security tokens, and STS access key secrets. Built-in rule coverage is now 921 rules total.
+- Added 61 new detection rules across 46 providers: Axiom (API token + PAT), Trigger.dev (secret key + PAT), Dub.co, Svix webhook signing secret, Liveblocks, Inngest (signing key + event key), Seam, Courier, Cal.com, Arcjet, WarpStream, Mem0, Mintlify, Pirsch, Tinybird, Tolgee (project key + PAT), Ory (API key + session + OAuth2 tokens), Xendit, Xata, Crossmint (server + client keys), DeepL (Free + Pro), Flagsmith, E2B, Infisical, WooCommerce (consumer key + secret), Nightfall AI, Ramp (client ID + secret), Hex.pm (personal + workspace tokens), Convex deploy key, MiniMax, Mappedin (key + secret), Pollinations (secret + publishable), Fal.ai, Aikido, Hack Club, GuardSquare, Browser Use, Composio, Gamma, Hex.tech, Mastra, redirect.pizza, Upstash, and WorkOS. Also added new prefixed-token rules for Netlify (`nfp_`), Cloudflare (`cfut_`), and Supabase (`sb_publishable_`). Added live HTTP validation for 30 of these rules.
+- Added 32 new detection rules across 25 providers: Ghost CMS (admin + content keys), UpCloud (`ucat_`), Voiceflow (`VF.DM.`/`VF.WS.`), Robinhood Crypto (`rh-api-`), ClickUp (`pk_`), Unleash (client/admin + personal tokens), ConfigCat (standard + extended SDK keys), SaladCloud (`salad_cloud_`), Tigris (`tid_`/`tsec_`), Portainer (`ptr_`), Permit.io (`permit_key_`), Builder.io (`bpk-`), LiveKit (API key + secret), Close CRM (`api_`), Hetzner Cloud, Censys (API ID + secret), Wistia, PandaDoc, Pinata (key + secret), ZeroTier, Detectify, ChartMogul, Moralis, ButterCMS, and Loops. Includes HTTP validation for 19 of these rules.
+- Removed 17 direct dependencies from the root crate by dropping unused deps (`p256`, `ed25519-dalek`, `jsonwebtoken`, `gitlab`, `lazy_static`, `base32`, `pem`, `byteorder`, `reqwest-middleware`, `sha1`, `time`, `ring`, `num_cpus`, `strum_macros`), replacing `once_cell` with `std::sync::{LazyLock, OnceLock}`, and using `std::thread::available_parallelism()` in place of `num_cpus`. Salt generation now uses `rand` instead of `ring`, and all `strum_macros::Display` imports are consolidated under `strum::Display`.
## [v1.95.0]
- Fixed scan performance regression: the rule profiler was unconditionally active even without `--rule-stats`, causing RwLock contention across scan threads. Scans are now ~15% faster than v1.94.0.
diff --git a/docs-site/docs/index.md b/docs-site/docs/index.md
index afc7ea3..39c414d 100644
--- a/docs-site/docs/index.md
+++ b/docs-site/docs/index.md
@@ -2,7 +2,7 @@
title: Kingfisher — Open Source Secret Scanner with Live Validation
description: >-
Kingfisher is an open source secret scanner with live validation, blast radius
- mapping, and credential revocation. 825 detection rules. Built in Rust by MongoDB.
+ mapping, and credential revocation. 921 detection rules. Built in Rust by MongoDB.
template: home.html
hide:
- navigation
diff --git a/docs-site/docs/reference/library.md b/docs-site/docs/reference/library.md
index c9f0fa6..98e7ee1 100644
--- a/docs-site/docs/reference/library.md
+++ b/docs-site/docs/reference/library.md
@@ -268,7 +268,7 @@ flowchart TD
### Loading Builtin Rules
-Kingfisher currently ships with 825 built-in rules for common secret types:
+Kingfisher currently ships with 921 built-in rules for common secret types:
```rust
use kingfisher_rules::{get_builtin_rules, Confidence};
diff --git a/docs-site/docs/rules/builtin-rules.md b/docs-site/docs/rules/builtin-rules.md
index 1e1bf4e..075bd72 100644
--- a/docs-site/docs/rules/builtin-rules.md
+++ b/docs-site/docs/rules/builtin-rules.md
@@ -1,13 +1,13 @@
---
title: "Built-in Rules List"
-description: "Complete list of all 825 built-in secret detection rules in Kingfisher. Searchable and filterable by provider, confidence level, and validation support."
+description: "Complete list of all 921 built-in secret detection rules in Kingfisher. Searchable and filterable by provider, confidence level, and validation support."
---
# Built-in Rules
-Kingfisher ships with **825 detection rules** across **510 providers**
-(719 detectors + 106 dependent rules).
-Of these, **521** include live validation and **46** support direct revocation.
+Kingfisher ships with **921 detection rules** across **579 providers**
+(808 detectors + 113 dependent rules).
+Of these, **596** include live validation and **53** support direct revocation.
!!! tip "Search"
Use the search box below to filter rules by provider name, rule ID, or confidence level.
@@ -55,7 +55,7 @@ Of these, **521** include live validation and **46** support direct revocation.
kingfisher.adafruitio.1kingfisher.aikido.1kingfisher.airbrake.1kingfisher.akamai.1kingfisher.alibabacloud.3kingfisher.alibabacloud.4kingfisher.alibabacloud.5kingfisher.amazonmws.1kingfisher.anthropic.1kingfisher.arcjet.1kingfisher.artifactory.1kingfisher.axiom.1kingfisher.axiom.2kingfisher.azure.1kingfisher.browseruse.1kingfisher.builderio.1kingfisher.buildkite.1kingfisher.buttercms.1kingfisher.calcom.1kingfisher.calendly.1kingfisher.canva.1kingfisher.censys.1kingfisher.censys.2kingfisher.cerebras.1kingfisher.chartmogul.1kingfisher.checkout.1kingfisher.clickup.1kingfisher.clockwork.1kingfisher.closecrm.1kingfisher.cloudant.1kingfisher.cloudflare.3kingfisher.cloudinary.1kingfisher.composio.1kingfisher.configcat.1kingfisher.configcat.2kingfisher.confluent.1kingfisher.convex.1kingfisher.couchbase.1kingfisher.courier.1kingfisher.coveralls.1kingfisher.crossmint.1kingfisher.crossmint.2kingfisher.curl.1kingfisher.deepl.1kingfisher.deepl.2kingfisher.deepseek.1kingfisher.detectify.1kingfisher.devcycle.1kingfisher.digitalocean.1kingfisher.discord.1kingfisher.dub.1kingfisher.duffel.1kingfisher.e2b.1kingfisher.easypost.1kingfisher.elastic.1kingfisher.elastic.2kingfisher.facebook.3kingfisher.falai.1kingfisher.flagsmith.1kingfisher.fleetbase.1kingfisher.gamma.1kingfisher.gcnotify.1kingfisher.gemfury.1kingfisher.gemfury.2kingfisher.ghost.1kingfisher.ghost.2kingfisher.gitalk.1kingfisher.gitlab.15kingfisher.guardsquare.1kingfisher.gumroad.1kingfisher.hackclub.1kingfisher.harness.pat.1kingfisher.hcaptcha.1kingfisher.hetzner.1kingfisher.hex.1kingfisher.hexpm.1kingfisher.hexpm.2kingfisher.highnote.1kingfisher.hop.1kingfisher.hop.2kingfisher.infisical.1kingfisher.influxdb.1kingfisher.inngest.1kingfisher.inngest.2kingfisher.instagram.1kingfisher.launchdarkly.1kingfisher.linode.1kingfisher.liveblocks.1kingfisher.livekit.1kingfisher.livekit.2kingfisher.llamacloud.1kingfisher.loops.1kingfisher.mailchimp.1kingfisher.mappedin.1kingfisher.mappedin.2kingfisher.mariadb.1kingfisher.mastra.1kingfisher.mattermost.1kingfisher.mem0.1kingfisher.mercadopago.1kingfisher.minimax.1kingfisher.mintlify.1kingfisher.miro.1kingfisher.moralis.1kingfisher.mssql.1kingfisher.netlify.1kingfisher.netlify.2kingfisher.netlify.3kingfisher.nightfall.1kingfisher.notion.1kingfisher.ory.1kingfisher.ory.2kingfisher.ory.3kingfisher.ovh.1kingfisher.pandadoc.1kingfisher.pangea.1kingfisher.permitio.1kingfisher.perplexity.1kingfisher.pinata.1kingfisher.pinata.2kingfisher.pinecone.1kingfisher.pirsch.1kingfisher.plaid.1kingfisher.polar.1kingfisher.pollinations.1kingfisher.pollinations.2kingfisher.portainer.1kingfisher.positionstack.1kingfisher.posthog.3kingfisher.ramp.1kingfisher.ramp.2kingfisher.rapidapi.1kingfisher.redirectpizza.1kingfisher.redis.1kingfisher.resend.api_key.1kingfisher.robinhood.1kingfisher.rollbar.1kingfisher.saladcloud.1kingfisher.salesforce.1kingfisher.seam.1kingfisher.segment.1kingfisher.supabase.4kingfisher.surge.1kingfisher.svix.1kingfisher.tableau.1kingfisher.thingsboard.1kingfisher.thunderstore.1kingfisher.tigris.1kingfisher.tigris.2kingfisher.tinybird.1kingfisher.todoist.1kingfisher.tolgee.1kingfisher.tolgee.2kingfisher.travisci.1kingfisher.triggerdev.1kingfisher.triggerdev.2kingfisher.truenas.1kingfisher.unkey.2kingfisher.unleash.1kingfisher.unleash.2kingfisher.unsplash.1kingfisher.upcloud.1kingfisher.upstash.1kingfisher.upstash.2kingfisher.uptimerobot.1kingfisher.valtown.1kingfisher.voiceflow.1kingfisher.volcengine.1kingfisher.vonage.2kingfisher.warpstream.1kingfisher.weatherapi.1kingfisher.wistia.1kingfisher.wiz.1kingfisher.woocommerce.1kingfisher.woocommerce.2kingfisher.workato.1kingfisher.workos.1kingfisher.wpengine.1kingfisher.xata.1kingfisher.xendit.1kingfisher.yahoo.1kingfisher.zapier.1kingfisher.zerotier.1kingfisher.zhipu.1