diff --git a/.github/workflows/betterleaks.yaml b/.github/workflows/betterleaks.yaml new file mode 100644 index 00000000..c568abbb --- /dev/null +++ b/.github/workflows/betterleaks.yaml @@ -0,0 +1,17 @@ +name: Betterleaks Scan +on: + - push + - pull_request + +jobs: + betterleaks: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: dortort/betterleaks-action@v0.1.0 + id: betterleaks + with: + github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 22bcbcfa..558da68e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,71 +1,76 @@ # Pre-Commit hooks # See: https://pre-commit.com/hooks.html repos: -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 - hooks: - - id: check-added-large-files - - id: check-ast - - id: check-builtin-literals - - id: check-byte-order-marker - - id: check-json - - id: check-merge-conflict - - id: check-symlinks - - id: check-yaml - - id: debug-statements - - id: detect-aws-credentials - args: ['--allow-missing-credentials'] - - id: detect-private-key - exclude: > - (?x)^( - .bumpversion.cfg - )$ - - id: end-of-file-fixer - exclude: > - (?x)^( - \.bumpversion\.cfg - )$ - - id: forbid-new-submodules - - id: name-tests-test - args: ['--django'] - exclude: > - (?x)^( - cloudsmith/.*/tests/apps\.py| - cloudsmith/.*/tests/enums\.py| - cloudsmith/.*/tests/factories\.py| - cloudsmith/.*/tests/forms\.py| - cloudsmith/.*/tests/models\.py| - cloudsmith/.*/tests/mixins\.py| - cloudsmith_cli/.*/tests/utils\.py| - cloudsmith/.*/tests/views\.py - )$ - - id: trailing-whitespace + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: check-added-large-files + - id: check-ast + - id: check-builtin-literals + - id: check-byte-order-marker + - id: check-json + - id: check-merge-conflict + - id: check-symlinks + - id: check-yaml + - id: debug-statements + - id: detect-aws-credentials + args: ['--allow-missing-credentials'] + - id: detect-private-key + exclude: > + (?x)^( -- repo: https://github.com/asottile/pyupgrade - rev: v3.21.2 - hooks: - - id: pyupgrade - args: [--py310-plus] + .bumpversion.cfg + )$ + - id: end-of-file-fixer + exclude: > + (?x)^( -- repo: https://github.com/zizmorcore/zizmor-pre-commit - rev: v1.20.0 - hooks: - - id: zizmor + \.bumpversion\.cfg + )$ -- repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.16.1 - hooks: - - id: ruff-format - args: ['--check'] - - id: ruff-check - # excluding tests until all lints pass - args: - - '--output-format=github' - - '--exclude=cloudsmith_cli/cli/tests' - - '--exclude=cloudsmith_cli/core/tests' + - id: forbid-new-submodules + - id: name-tests-test + args: ['--django'] + exclude: > + (?x)^( -- repo: https://github.com/crate-ci/typos - rev: v1.42.1 - hooks: - - id: typos + cloudsmith/.*/tests/apps\.py| + cloudsmith/.*/tests/enums\.py| + cloudsmith/.*/tests/factories\.py| + cloudsmith/.*/tests/forms\.py| + cloudsmith/.*/tests/models\.py| + cloudsmith/.*/tests/mixins\.py| + cloudsmith_cli/.*/tests/utils\.py| + cloudsmith/.*/tests/views\.py + )$ + + - id: trailing-whitespace + - repo: https://github.com/asottile/pyupgrade + rev: v3.21.2 + hooks: + - id: pyupgrade + args: [--py310-plus] + - repo: https://github.com/zizmorcore/zizmor-pre-commit + rev: v1.20.0 + hooks: + - id: zizmor + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.16.1 + hooks: + - id: ruff-format + args: ['--check'] + - id: ruff-check + # excluding tests until all lints pass + args: + - '--output-format=github' + - '--exclude=cloudsmith_cli/cli/tests' + - '--exclude=cloudsmith_cli/core/tests' + - repo: https://github.com/crate-ci/typos + rev: v1.42.1 + hooks: + - id: typos + - repo: https://github.com/betterleaks/betterleaks + rev: v1.7.4 + hooks: + - id: betterleaks diff --git a/betterleaks.toml b/betterleaks.toml new file mode 100644 index 00000000..36b179f5 --- /dev/null +++ b/betterleaks.toml @@ -0,0 +1,9608 @@ +# This file has been auto-generated. Do not edit manually. +# If you would like to contribute new rules, please use +# cmd/generate/config/main.go and follow the contributing guidelines +# at https://github.com/betterleaks/betterleaks/blob/main/.github/CONTRIBUTING.md +# +# How the hell does secret scanning work? Read this: +# https://lookingatcomputer.substack.com/p/regex-is-almost-all-you-need +# +# This is the default betterleaks configuration file. +# Rules and filters are defined within this file. +# Rules instruct betterleaks on what should be considered a secret. +# Filters instruct betterleaks on what to skip (prefilter) or discard (filter). + +title = "betterleaks config" + +# minVersion indicates the minimum gitleaks config format version required. +# betterleaksMinVersion indicates the minimum betterleaks version required. +# If the running version is older, a warning will be logged. +minVersion = "v8.25.0" +betterleaksMinVersion = "v1.7.5" + + +prefilter = ''' +matchesAny(attributes["path"], [ + `gitleaks\.toml`, + `(?i)\.(?:bmp|gif|jpe?g|png|svg|tiff?)$`, + `(?i)\.(?:eot|[ot]tf|woff2?)$`, + `(?i)\.(?:docx?|xlsx?|pdf|bin|socket|vsidx|v2|suo|wsuo|dll|pdb|exe|gltf)$`, + `go\.(?:mod|sum|work(?:\.sum)?)$`, + `(?:^|/)vendor/modules\.txt$`, + `(?:^|/)vendor/(?:github\.com|golang\.org/x|google\.golang\.org|gopkg\.in|istio\.io|k8s\.io|sigs\.k8s\.io)(?:/.*)?$`, + `(?:^|/)gradlew(?:\.bat)?$`, + `(?:^|/)gradle\.lockfile$`, + `(?:^|/)mvnw(?:\.cmd)?$`, + `(?:^|/)\.mvn/wrapper/MavenWrapperDownloader\.java$`, + `(?:^|/)node_modules(?:/.*)?$`, + `(?:^|/)(?:deno\.lock|npm-shrinkwrap\.json|package-lock\.json|pnpm-lock\.yaml|yarn\.lock)$`, + `(?:^|/)bower_components(?:/.*)?$`, + `(?:^|/)(?:angular|bootstrap|jquery(?:-?ui)?|plotly|swagger-?ui)[a-zA-Z0-9.-]*(?:\.min)?\.js(?:\.map)?$`, + `(?:^|/)javascript\.json$`, + `(?:^|/)(?:Pipfile|poetry)\.lock$`, + `(?i)(?:^|/)(?:v?env|virtualenv)/lib(?:64)?(?:/.*)?$`, + `(?i)(?:^|/)(?:lib(?:64)?/python[23](?:\.\d{1,2})+|python/[23](?:\.\d{1,2})+/lib(?:64)?)(?:/.*)?$`, + `(?i)(?:^|/)[a-z0-9_.]+-[0-9.]+\.dist-info(?:/.+)?$`, + `(?:^|/)vendor/(?:bundle|ruby)(?:/.*?)?$`, + `\.gem$`, + `verification-metadata\.xml`, + `Database.refactorlog`, + `(?:^|/)\.git$` +]) + +''' + +filter = ''' +(matchesAny(finding["secret"], [ + `(?i)^true|false|null$`, + `^(?i:a+|b+|c+|d+|e+|f+|g+|h+|i+|j+|k+|l+|m+|n+|o+|p+|q+|r+|s+|t+|u+|v+|w+|x+|y+|z+|\*+|\.+)$`, + `^\$(?:\d+|{\d+})$`, + `^\$(?:[A-Z_]+|[a-z_]+)$`, + `^\${(?:[A-Z_]+|[a-z_]+)}$`, + `^\{\{[ \t]*[\w ().|]+[ \t]*}}$`, + `^\$\{\{[ \t]*(?:(?:env|github|secrets|vars)(?:\.[A-Za-z]\w+)+[\w "'&./=|]*)[ \t]*}}$`, + `^%(?:[A-Z_]+|[a-z_]+)%$`, + `^%[+\-# 0]?[bcdeEfFgGoOpqstTUvxX]$`, + `^\{\d{0,2}}$`, + `^@(?:[A-Z_]+|[a-z_]+)@$`, + `^/Users/(?i)[a-z0-9]+/[\w .-/]+$`, + `^/(?:bin|etc|home|opt|tmp|usr|var)/[\w ./-]+$` +]) || containsAny(finding["secret"], [ + "abcdefghijklmnopqrstuvwxyz", + "014df517-39d1-4453-b7b3-9930c563627c" +])) + +''' + +# ────────────────────────────────────────────────────────────────────────────── +# 1password-secret-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "1password-secret-key" +description = "Uncovered a possible 1Password secret key, potentially compromising access to secrets in vaults." +regex = '''\bA3-[A-Z0-9]{6}-(?:(?:[A-Z0-9]{11})|(?:[A-Z0-9]{6}-[A-Z0-9]{5}))-[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}\b''' +confidence = "high" +keywords = ["a3-"] +filter = ''' +entropy(finding["secret"]) <= 3.8 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# 1password-service-account-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "1password-service-account-token" +description = "Uncovered a possible 1Password service account token, potentially compromising access to secrets in vaults." +regex = '''ops_eyJ[a-zA-Z0-9+/]{250,}={0,3}''' +confidence = "high" +keywords = ["ops_eyj"] +validate = ''' +let r = http.get("https://events.1password.com/api/v2/auth/introspect", { + "Accept": "application/json", + "Authorization": "Bearer " + finding["secret"] + }); r.status == 200 && (r.body contains "\"features\"") ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 4.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# adafruit-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "adafruit-api-key" +description = "Identified a potential Adafruit API Key, which could lead to unauthorized access to Adafruit services and sensitive data exposure." +regex = '''(?i)(?:adafruit)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9_-]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["adafruit"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# adobe-client-id +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "adobe-client-id" +description = "Detected a pattern that resembles an Adobe OAuth Web Client ID, posing a risk of compromised Adobe integrations and data breaches." +regex = '''(?i)(?:adobe)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-f0-9]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["adobe"] +filter = ''' +filter.entropy(finding["secret"]) < 3.0 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# adobe-client-secret +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "adobe-client-secret" +description = "Discovered a potential Adobe Client Secret, which, if exposed, could allow unauthorized Adobe service access and data manipulation." +regex = '''\b(p8e-(?i)[a-z0-9]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["p8e-"] +filter = ''' +filter.entropy(finding["secret"]) < 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# age-secret-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "age-secret-key" +description = "Discovered a potential Age encryption tool secret key, risking data decryption and unauthorized access to sensitive information." +regex = '''AGE-SECRET-KEY-1[QPZRY9X8GF2TVDW0S3JN54KHCE6MUA7L]{58}''' +confidence = "high" +keywords = ["age-secret-key-1"] + +# ────────────────────────────────────────────────────────────────────────────── +# aikido-ci-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "aikido-ci-token" +description = "Detected an Aikido CI token, which may allow unauthorized CI scan integration activity in Aikido." +regex = '''\b(AIK_CI_[A-Za-z0-9]{20,44})\b''' +confidence = "high" +keywords = ["aik_ci_"] +filter = ''' +filter.entropy(finding["secret"]) < 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# aikido-client-id +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "aikido-client-id" +description = "Detected an Aikido client ID, used as a component of the aikido-client-secret composite rule." +regex = '''\b(AIK_CLIENT_[A-Za-z0-9]{24})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["aik_client_"] +skipReport = true +filter = ''' +filter.entropy(finding["secret"]) < 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# aikido-client-secret +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "aikido-client-secret" +description = "Detected an Aikido client secret, which may allow unauthorized access to Aikido APIs when paired with a client ID." +regex = '''\b(AIK_SECRET_[A-Za-z0-9]{64})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["aik_secret_"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 +''' +components = [ + { id = "aikido-client-id" }, +] + +# ────────────────────────────────────────────────────────────────────────────── +# airtable-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "airtable-api-key" +description = "Uncovered a possible Airtable API Key, potentially compromising database access and leading to data leakage or alteration." +regex = '''(?i)(?:airtable)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{17})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["airtable"] +filter = ''' +filter.entropy(finding["secret"]) < 3.0 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# airtable-oauth-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "airtable-oauth-token" +description = "Detected an Airtable OAuth token, which may allow unauthorized access to Airtable resources granted to an OAuth integration." +regex = '''(?i)(?:airtable)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([A-Z0-9]+\.v1\.[A-Z0-9_-]+\.[a-f0-9]+)(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["airtable"] +validate = ''' +let r = http.get("https://api.airtable.com/v0/meta/whoami", { + "Authorization": "Bearer " + finding["secret"] + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# airtable-personnal-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "airtable-personnal-access-token" +description = "Uncovered a possible Airtable Personal AccessToken, potentially compromising database access and leading to data leakage or alteration." +regex = '''\b(pat[[:alnum:]]{14}\.[a-f0-9]{64})\b''' +confidence = "high" +keywords = ["airtable"] +validate = ''' +let r = http.get("https://api.airtable.com/v0/meta/whoami", { + "Authorization": "Bearer " + finding["secret"] + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.3 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# aiven-auth-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "aiven-auth-token" +description = "Detected an Aiven authentication token, which may expose Aiven projects and services." +regex = '''(?i:aiven)[\s\S]{0,32}?\b([A-Za-z0-9/+=]{372})(?:[^A-Za-z0-9/+=]|$)''' +confidence = "high" +keywords = ["aiven"] +validate = ''' +let r = http.get("https://api.aiven.io/v1/project", { + "Authorization": "aivenv1 " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 4.0 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# algolia-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "algolia-api-key" +description = "Identified an Algolia API Key, which could result in unauthorized search operations and data exposure on Algolia-managed platforms." +regex = '''(?i)(?:algolia)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["algolia"] +validate = ''' +let r = http.get("https://" + (components["algolia-application-id"]?.secret ?? "") + ".algolia.net/1/keys/" + finding["secret"], { + "Accept": "application/json", + "X-Algolia-API-Key": finding["secret"], + "X-Algolia-Application-Id": (components["algolia-application-id"]?.secret ?? "") + }); let acl = r.json?.acl ?? []; + let public_acls = ["search", "browse", "listIndexes", "settings"]; + let has_sensitive_acl = any(acl, {# not in public_acls}); + r.status == 200 && has_sensitive_acl ? { + "result": "valid", + "acl": acl + } : r.status == 200 && "search" in acl ? { + "result": "invalid", + "reason": "Public Algolia Search API key", + "acl": acl + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' +components = [ + { id = "algolia-application-id" }, +] + +# ────────────────────────────────────────────────────────────────────────────── +# algolia-application-id +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "algolia-application-id" +description = "Detected an Algolia application ID, used as a component of the algolia-api-key composite rule." +regex = '''(?i)(?:algolia)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{10})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["algolia"] +skipReport = true +filter = ''' +filter.entropy(finding["secret"]) < 2.75 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# alibaba-access-key-id +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "alibaba-access-key-id" +description = "Detected an Alibaba Cloud AccessKey ID, posing a risk of unauthorized cloud resource access and potential data compromise." +regex = '''\b(LTAI[A-Za-z0-9]{17,21})\b''' +confidence = "high" +keywords = ["ltai"] +skipReport = true +filter = ''' +filter.entropy(finding["secret"]) < 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# alibaba-secret-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "alibaba-secret-key" +description = "Discovered a potential Alibaba Cloud Secret Key, potentially allowing unauthorized operations and data access within Alibaba Cloud." +regex = '''(?i)(?:alibaba|aliyun|secret|key)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([A-Za-z0-9]{30})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = [ + "alibaba", + "aliyun", +] +validate = ''' +let ts = time.nowRFC3339(); +let nonce = time.nowUnix(); +let params = + "AccessKeyId=" + strings.urlQueryEscape((components["alibaba-access-key-id"]?.secret ?? "")) + + "&Action=GetCallerIdentity&Format=JSON&SignatureMethod=HMAC-SHA1&SignatureNonce=" + nonce + + "&SignatureVersion=1.0&Timestamp=" + strings.urlQueryEscape(ts) + "&Version=2015-04-01"; +let string_to_sign = "GET&%2F&" + replace(replace(replace(strings.urlQueryEscape(params), "+", "%20"), "*", "%2A"), "%7E", "~"); +let sig = strings.urlQueryEscape(base64.encode(crypto.hmacSha1(bytes(finding["secret"] + "&"), bytes(string_to_sign)))); +let r = http.get("https://sts.aliyuncs.com/?" + params + "&Signature=" + sig, { + "Accept": "application/json" +}); +r.status == 200 && (r.body contains "\"Arn\"") ? { + "result": "valid" +} : r.status in [401, 403] || (r.body contains "InvalidAccessKeyId") || (r.body contains "SignatureDoesNotMatch") ? { + "result": "invalid", + "reason": "Unauthorized" +} : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' +components = [ + { id = "alibaba-access-key-id", within = "5L" }, +] + +# ────────────────────────────────────────────────────────────────────────────── +# alibaba-sts-access-key-id +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "alibaba-sts-access-key-id" +description = "Detected an Alibaba Cloud STS AccessKey ID, used as a component of the alibaba-sts-access-key-secret composite rule." +regex = '''\b(STS\.[A-Za-z0-9]{16,64})\b''' +confidence = "high" +keywords = ["sts."] +skipReport = true +filter = ''' +filter.entropy(finding["secret"]) < 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# alibaba-sts-access-key-secret +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "alibaba-sts-access-key-secret" +description = "Detected an Alibaba Cloud STS AccessKey secret, which may allow temporary Alibaba Cloud API access when paired with an STS AccessKey ID and security token." +regex = '''(?i)(?:alibaba|aliyun|secret|key)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([A-Za-z0-9]{30,64})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = [ + "alibaba", + "aliyun", +] +validate = ''' +let ts = time.nowRFC3339(); +let nonce = time.nowUnix(); +let params = + "AccessKeyId=" + strings.urlQueryEscape((components["alibaba-sts-access-key-id"]?.secret ?? "")) + + "&SecurityToken=" + strings.urlQueryEscape((components["alibaba-sts-security-token"]?.secret ?? "")) + + "&Action=GetCallerIdentity&Format=JSON&SignatureMethod=HMAC-SHA1&SignatureNonce=" + nonce + + "&SignatureVersion=1.0&Timestamp=" + strings.urlQueryEscape(ts) + "&Version=2015-04-01"; +let string_to_sign = "GET&%2F&" + replace(replace(replace(strings.urlQueryEscape(params), "+", "%20"), "*", "%2A"), "%7E", "~"); +let sig = strings.urlQueryEscape(base64.encode(crypto.hmacSha1(bytes(finding["secret"] + "&"), bytes(string_to_sign)))); +let r = http.get("https://sts.aliyuncs.com/?" + params + "&Signature=" + sig, { + "Accept": "application/json" +}); +r.status == 200 && (r.body contains "\"Arn\"") ? { + "result": "valid" +} : r.status in [401, 403] || (r.body contains "InvalidAccessKeyId") || (r.body contains "SignatureDoesNotMatch") ? { + "result": "invalid", + "reason": "Unauthorized" +} : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' +components = [ + { id = "alibaba-sts-access-key-id", within = "10L" }, + { id = "alibaba-sts-security-token", within = "10L" }, +] + +# ────────────────────────────────────────────────────────────────────────────── +# alibaba-sts-security-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "alibaba-sts-security-token" +description = "Detected an Alibaba Cloud STS security token, used as a component of the alibaba-sts-access-key-secret composite rule." +regex = '''(?i)(?:alibaba|aliyun|secret|key)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(CAIS[A-Za-z0-9+/_=-]{20,1000}[A-Za-z0-9+/_=-]{0,24})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = [ + "alibaba", + "aliyun", + "cais", +] +skipReport = true +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# amplitude-secret-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "amplitude-secret-key" +description = "Detected an Amplitude secret key, which may allow unauthorized event ingestion or access to Amplitude API functionality." +regex = '''(?i)\bamplitude(?:.|[\n\r]){0,32}?(?:SECRET|PRIVATE|ACCESS|KEY|TOKEN|AUTHORIZATION)(?:.|[\n\r]){0,16}?\b([a-f0-9]{32})\b''' +confidence = "medium" +keywords = ["amplitude"] +validate = ''' +let r = http.post("https://api2.amplitude.com/2/httpapi", { + "Content-Type": "application/json", + "Accept": "*/*" + }, + "{" + + "\"api_key\":" + json.string(finding["secret"]) + "," + + "\"events\":[{" + + "\"user_id\":\"203201202\"," + + "\"device_id\":\"C8F9E604-F01A-4BD9-95C6-8E5357DF265D\"," + + "\"event_type\":\"watch_tutorial\"" + + "}]" + + "}"); r.status == 200 && (r.body contains "\"code\":200") ? { + "result": "valid" + } : r.status in [400, 401, 403] ? { + "result": "invalid", + "reason": (r.json?.error ?? "Unauthorized") + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.3 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# anthropic-admin-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "anthropic-admin-api-key" +description = "Detected an Anthropic Admin API Key, risking unauthorized access to administrative functions and sensitive AI model configurations." +regex = '''\b(sk-ant-admin01-[a-zA-Z0-9_\-]{93}AA)(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["sk-ant-admin01"] +validate = ''' +let r = http.get("https://api.anthropic.com/v1/organizations/me", { + "x-api-key": finding["secret"], + "anthropic-version": "2023-06-01" + }); r.status == 200 && (r.json?.id ?? "") != "" && (r.json?.type ?? "") == "organization" ? { + "result": "valid", + "organization": (r.json?.name ?? "") + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' + +# ────────────────────────────────────────────────────────────────────────────── +# anthropic-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "anthropic-api-key" +description = "Identified an Anthropic API Key, which may compromise AI assistant integrations and expose sensitive data to unauthorized access." +regex = '''\b(sk-ant-api03-[a-zA-Z0-9_\-]{93}AA)(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["sk-ant-api03"] +validate = ''' +let r = http.get("https://api.anthropic.com/v1/models", { + "x-api-key": finding["secret"], + "anthropic-version": "2023-06-01" + }); r.status == 200 && (r.body contains '"data"') && (r.body contains '"type"') ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' + +# ────────────────────────────────────────────────────────────────────────────── +# apify-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "apify-api-token" +description = "Detected an Apify API token, which may expose actors, tasks, and stored data." +regex = '''\b(apify_api_[A-Za-z0-9]{34,38})\b''' +confidence = "high" +keywords = ["apify_api_"] +validate = ''' +let r = http.get("https://api.apify.com/v2/users/me", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); +r.status == 200 && ((r.body contains "\"data\"") && (r.body contains "\"username\"")) ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) + +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# artifactory-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "artifactory-api-key" +description = "Detected an Artifactory api key, posing a risk unauthorized access to the central repository." +regex = '''\bAKCp[A-Za-z0-9]{68,70}\b''' +confidence = "high" +keywords = ["akcp"] +validate = ''' +let r = http.get("https://" + (components["artifactory-jfrog-url"]?.secret ?? "") + "/artifactory/api/repositories", { + "X-JFrog-Art-Api": finding["secret"] + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 +''' +components = [ + { id = "artifactory-jfrog-url" }, +] + +# ────────────────────────────────────────────────────────────────────────────── +# artifactory-jfrog-url +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "artifactory-jfrog-url" +description = "Detected a JFrog Artifactory host, used as a component of Artifactory token validation." +regex = '''(?i)(?:^|[^a-z0-9-])([a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.jfrog\.io)(?:$|[^a-z0-9-])''' +confidence = "high" +keywords = ["jfrog.io"] +skipReport = true +filter = ''' +filter.entropy(finding["secret"]) < 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# artifactory-reference-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "artifactory-reference-token" +description = "Detected an Artifactory reference token, posing a risk of impersonation and unauthorized access to the central repository." +regex = '''\bcmVmd[A-Za-z0-9]{59}\b''' +confidence = "high" +keywords = ["cmvmd"] +validate = ''' +let r = http.get("https://" + (components["artifactory-jfrog-url"]?.secret ?? "") + "/artifactory/api/repositories", { + "Authorization": "Bearer " + finding["secret"] + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 +''' +components = [ + { id = "artifactory-jfrog-url" }, +] + +# ────────────────────────────────────────────────────────────────────────────── +# asaas-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "asaas-api-token" +description = "Detected an Asaas API token, which may expose payment and customer data." +regex = '''(?:^|[^A-Za-z0-9_-])(\$aact_(?:prod|hmlg)_[A-Za-z0-9_-]{20,100})(?:[^A-Za-z0-9_-]|$)''' +confidence = "high" +keywords = ["$aact_"] +validate = ''' +let url = finding["secret"].contains("$aact_hmlg_") ? "https://api-sandbox.asaas.com/v3/myAccount/commercialInfo/" : "https://api.asaas.com/v3/myAccount/commercialInfo/"; +let r = http.get(url, { + "access_token": finding["secret"], + "Accept": "application/json", + "User-Agent": "betterleaks" + }); r.status == 200 && (r.body contains "\"commercialInfo\"") ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# asana-client-id +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "asana-client-id" +description = "Discovered a potential Asana Client ID, risking unauthorized access to Asana projects and sensitive task information." +regex = '''(?i)(?:asana)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([0-9]{16})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["asana"] +filter = ''' +filter.entropy(finding["secret"]) < 2.75 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# asana-client-secret +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "asana-client-secret" +description = "Identified an Asana Client Secret, which could lead to compromised project management integrity and unauthorized access." +regex = '''(?i)(?:asana)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["asana"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# assemblyai-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "assemblyai-api-key" +description = "Detected an AssemblyAI API Key, which may expose speech-to-text services and associated audio data to unauthorized access." +regex = '''(?i)(?:assemblyai)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["assemblyai"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# atlassian-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "atlassian-api-token" +description = "Detected an Atlassian API token, posing a threat to project management and collaboration tool security and data confidentiality." +regex = '''(?i)(?:(?-i:ATLASSIAN|[Aa]tlassian)|(?-i:CONFLUENCE|[Cc]onfluence)|(?-i:JIRA|[Jj]ira))(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{20}[a-f0-9]{4})(?:\\?['"\x60]|[\s;]|\\[nr]|$)|\b(ATATT3[A-Za-z0-9_\-=]{186})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = [ + "atlassian", + "confluence", + "jira", + "atatt3", +] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# authress-service-client-access-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "authress-service-client-access-key" +description = "Uncovered a possible Authress Service Client Access Key, which may compromise access control services and sensitive data." +regex = '''(?i)\b((?:sc|ext|scauth|authress)_[a-z0-9]{5,30}\.[a-z0-9]{4,6}\.acc[_-][a-z0-9-]{10,32}\.[a-z0-9+/_=-]{30,120})\b''' +confidence = "high" +keywords = [ + ".acc_", + ".acc-", +] +validate = ''' +let r = http.get("https://api.authress.io/v1/users/me", { + "Authorization": "Bearer " + finding["secret"] + }); r.status == 200 && !(r.body contains "\"Unauthorized\"") ? { + "result": "valid" + } : r.status in [401, 403] || (r.body contains "\"Unauthorized\"") ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 4.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# aws-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "aws-access-token" +description = "Identified an AWS access key ID paired with a secret access key, which together can provide full access to AWS services." +regex = '''\b((?:A3T[A-Z0-9]|AKIA|ASIA|ABIA|ACCA)[A-Z2-7]{16})\b''' +confidence = "high" +keywords = [ + "a3t", + "akia", + "asia", + "abia", + "acca", +] +validate = ''' +let r = aws.validate(finding["secret"], (components["aws-secret-access-key"]?.secret ?? "")); r.status == 200 ? { + "result": "valid", + "arn": r.arn, + "account": r.account, + "userid": r.userid + } : r.status == 403 && r.error_code == "ExpiredToken" ? { + "result": "revoked", + "error_code": r.error_code, + "error_message": r.error_message + } : r.status == 403 ? { + "result": "invalid", + "error_code": r.error_code, + "error_message": r.error_message + } : validate.unknown(r) + +''' +filter = ''' +entropy(finding["secret"]) <= 3.0 +|| matchesAny(finding["secret"], [`.+EXAMPLE$`]) +''' +components = [ + { id = "aws-secret-access-key", within = "5L" }, +] + +# ────────────────────────────────────────────────────────────────────────────── +# aws-amazon-bedrock-api-key-long-lived +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "aws-amazon-bedrock-api-key-long-lived" +description = "Identified a pattern that may indicate long-lived Amazon Bedrock API keys, risking unauthorized Amazon Bedrock usage" +regex = '''\b(ABSK[A-Za-z0-9+/]{109,269}={0,2})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["absk"] +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# aws-amazon-bedrock-api-key-short-lived +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "aws-amazon-bedrock-api-key-short-lived" +description = "Identified a pattern that may indicate short-lived Amazon Bedrock API keys, risking unauthorized Amazon Bedrock usage" +regex = '''bedrock-api-key-YmVkcm9jay5hbWF6b25hd3MuY29t''' +confidence = "high" +keywords = ["bedrock-api-key-"] +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# aws-secret-access-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "aws-secret-access-key" +description = "Identified an AWS secret access key, used as a component of the aws-access-token composite rule." +regex = '''(?i:(?:secret|access|key|token)(?:[ \t\w.-]{0,20})[\s'"]{0,3})(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([A-Za-z0-9/+=]{40})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = [ + "secret", + "access", + "key", + "token", +] +skipReport = true +filter = ''' +entropy(finding["secret"]) <= 4.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# azure-ad-client-secret +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "azure-ad-client-secret" +description = "Azure AD Client Secret" +regex = '''(?:^|[\\'"\x60\s>=:(,)])([a-zA-Z0-9_~.]{3}\dQ~[a-zA-Z0-9_~.-]{31,34})(?:$|[\\'"\x60\s<),])''' +confidence = "high" +keywords = [ + "0q~", + "1q~", + "2q~", + "3q~", + "4q~", + "5q~", + "6q~", + "7q~", + "8q~", + "9q~", +] +validate = ''' +let r = azure.validateServicePrincipal((components["azure-tenant-id"]?.secret ?? ""), (components["azure-client-id"]?.secret ?? ""), finding["secret"]); r.status == 200 ? { + "result": "valid", + "tenant_id": r.tenant_id, + "client_id": r.client_id +} : r.status in [400, 401, 403, 404] ? { + "result": "invalid", + "error_code": r.error_code, + "error_message": r.error_message +} : validate.unknown(r) + +''' +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' +components = [ + { id = "azure-tenant-id", within = "8L" }, + { id = "azure-client-id", within = "8L" }, +] + +# ────────────────────────────────────────────────────────────────────────────── +# azure-app-configuration-connection-string +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "azure-app-configuration-connection-string" +description = "Detected an Azure App Configuration connection string." +regex = '''(?i)Endpoint=(?Phttps://[a-z0-9-]+\.azconfig\.io);Id=(?P[^;\s'"]{4,80});Secret=([A-Za-z0-9+/]{36,100}={0,2})''' +secretGroup = 3 +confidence = "high" +keywords = [ + "azconfig.io", + "endpoint=", + "secret=", +] +validate = ''' +let r = azure.validateAppConfig( + finding["captures"]?.azure_appconfig_endpoint ?? "", + finding["captures"]?.azure_appconfig_id ?? "", + finding["secret"] +); r.status == 200 ? { + "result": "valid", + "endpoint": r.endpoint, + "id": r.id +} : r.status in [400, 401, 403, 404] ? { + "result": "invalid", + "error_code": r.error_code, + "error_message": r.error_message +} : validate.unknown(r) + +''' +filter = ''' +entropy(finding["secret"]) <= 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# azure-client-id +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "azure-client-id" +description = "Detected an Azure client ID, used as a component of Azure service principal validation." +regex = '''(?i)\b(?:client[_\s.-]*id|AZURE_CLIENT_ID)\b(?s:.{0,24}?)([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\b''' +confidence = "medium" +keywords = ["client"] +skipReport = true +filter = ''' +entropy(finding["secret"]) <= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# azure-servicebus-connection-string +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "azure-servicebus-connection-string" +description = "Detected an Azure Service Bus or Event Hub shared access connection string." +regex = '''(?i)(Endpoint=sb://[a-z0-9-]+\.servicebus\.windows\.net/;SharedAccessKeyName=[^;=\s'"]{1,128};SharedAccessKey=[A-Za-z0-9+/]{32,100}={0,2}(?:;EntityPath=[^;\s'"]{1,128})?)''' +confidence = "high" +keywords = [ + "endpoint=sb://", + "sharedaccesskey", +] +validate = ''' +let r = azure.validateServiceBusSAS(finding["secret"]); r.status in [200, 201, 202, 204] ? { + "result": "valid", + "host": r.host, + "entity_path": r.entity_path +} : r.status in [400, 401, 403, 404] ? { + "result": "invalid", + "error_code": r.error_code, + "error_message": r.error_message +} : validate.unknown(r) + +''' +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# azure-storage-account-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "azure-storage-account-key" +description = "Detected an Azure Storage account key." +regex = '''(?i)\b(?:AccountKey|(?:azure[_\s.-]*)?(?:storage[_\s.-]*)?(?:account[_\s.-]*)?(?:access[_\s.-]*)?key)\b(?s:.{0,24}?)([A-Za-z0-9+/]{86}==)''' +confidence = "high" +keywords = [ + "accountkey", + "storage", + "key", +] +validate = ''' +let r = azure.validateStorage((components["azure-storage-account-name"]?.secret ?? ""), finding["secret"]); r.status == 200 ? { + "result": "valid", + "account": r.account, + "containers": r.containers +} : r.status in [400, 401, 403, 404] ? { + "result": "invalid", + "error_code": r.error_code, + "error_message": r.error_message +} : validate.unknown(r) + +''' +filter = ''' +entropy(finding["secret"]) <= 4.0 +''' +components = [ + { id = "azure-storage-account-name", within = "8L" }, +] + +# ────────────────────────────────────────────────────────────────────────────── +# azure-storage-account-name +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "azure-storage-account-name" +description = "Detected an Azure Storage account name, used as a component of Azure Storage key validation." +regex = '''(?i)(?:\bAccountName\s*=\s*([a-z0-9]{3,24})\b|https://([a-z0-9]{3,24})\.blob\.core\.windows\.net\b|\b(?:azure[_\s.-]*storage[_\s.-]*(?:account[_\s.-]*)?name|storage[_\s.-]*account[_\s.-]*name)\b(?s:.{0,24}?)([a-z0-9]{3,24})\b)''' +confidence = "medium" +keywords = [ + "accountname", + "blob.core.windows.net", + "storage", +] +skipReport = true +filter = ''' +entropy(finding["secret"]) <= 1.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# azure-tenant-id +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "azure-tenant-id" +description = "Detected an Azure tenant ID, used as a component of Azure service principal validation." +regex = '''(?i)\b(?:tenant[_\s.-]*(?:id)?|AZURE_TENANT_ID)\b(?s:.{0,24}?)([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\b''' +confidence = "medium" +keywords = ["tenant"] +skipReport = true +filter = ''' +entropy(finding["secret"]) <= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# beamer-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "beamer-api-token" +description = "Detected a Beamer API token, potentially compromising content management and exposing sensitive notifications and updates." +regex = '''(?i)(?:beamer)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(b_[a-z0-9=_\-]{44})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["beamer"] + +# ────────────────────────────────────────────────────────────────────────────── +# bitbucket-client-id +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "bitbucket-client-id" +description = "Discovered a potential Bitbucket Client ID, risking unauthorized repository access and potential codebase exposure." +regex = '''(?i)(?:bitbucket)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["bitbucket"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# bitbucket-client-secret +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "bitbucket-client-secret" +description = "Discovered a potential Bitbucket Client Secret, posing a risk of compromised code repositories and unauthorized access." +regex = '''(?i)(?:bitbucket)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9=_\-]{64})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["bitbucket"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# bitly-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "bitly-access-token" +description = "Detected a Bitly access token, which may allow unauthorized access to Bitly account and link management APIs." +regex = '''(?i)\bbitly(?:.|[\n\r]){0,32}?(?:SECRET|PRIVATE|ACCESS|KEY|TOKEN)(?:.|[\n\r]){0,32}?([a-f0-9]{40})\b''' +confidence = "high" +keywords = ["bitly"] +validate = ''' +let r = http.get("https://api-ssl.bitly.com/v4/user", { + "Authorization": "Bearer " + finding["secret"] + }); r.status == 200 && (r.body contains "\"login\":") ? { + "result": "valid", + "login": (r.json?.login ?? "") + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.3 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# bitrise-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "bitrise-access-token" +description = "Detected a Bitrise personal or workspace access token, which may expose CI/CD applications and builds." +regex = '''(?i:(?:bitrise(?:[ _-]*(?:personal|workspace))?(?:[ _-]*(?:access|api))?[ _-]*token)(?:[ \t\w.-]{0,20})[\s'"]{0,3})(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([A-Za-z0-9_-]{60,120})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["bitrise"] +validate = ''' +let r = http.get("https://api.bitrise.io/v0.1/apps", { + "Authorization": finding["secret"], + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# bittrex-access-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "bittrex-access-key" +description = "Identified a Bittrex Access Key, which could lead to unauthorized access to cryptocurrency trading accounts and financial loss." +regex = '''(?i)(?:bittrex)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["bittrex"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# bittrex-secret-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "bittrex-secret-key" +description = "Detected a Bittrex Secret Key, potentially compromising cryptocurrency transactions and financial security." +regex = '''(?i)(?:bittrex)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["bittrex"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# box-api-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "box-api-access-token" +description = "Detected a Box API access token, which may expose Box files and account data." +regex = '''(?i)(?:box)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = [ + "box_", + "box-", + "boxt", + "boxk", + "boxa", +] +validate = ''' +let r = http.get("https://api.box.com/2.0/users/me", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); +r.status == 200 && ((r.body contains "\"id\"")) ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) + +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# brave-search-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "brave-search-api-key" +description = "Detected a Brave Search API key, which may allow unauthorized use of Brave Search API quota." +regex = '''\b(BSA[A-Za-z0-9_-]{24,40})\b''' +confidence = "high" +keywords = ["bsa"] +validate = ''' +let r = http.get("https://api.search.brave.com/res/v1/web/search?q=betterleaks&count=1", { + "Accept": "application/json", + "X-Subscription-Token": finding["secret"] + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.2 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# buildkite-service-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "buildkite-service-token" +description = "Detected a Buildkite agent, package, or portal token, which may expose CI/CD workloads or packages." +regex = '''\b(bkaa_[A-Za-z0-9_-]{75}|bkaj_[A-Za-z0-9_-]{333}|bkar_[A-Za-z0-9_-]{73}|bkct_[A-Za-z0-9_-]{73}|bkpt_[A-Za-z0-9_-]{199}|bkpat_[A-Za-z0-9_-]{54}|bkps_[A-Za-z0-9_-]{64})(?:$|[^A-Za-z0-9_-])''' +confidence = "high" +keywords = [ + "bkaa_", + "bkaj_", + "bkar_", + "bkct_", + "bkpt_", + "bkpat_", + "bkps_", +] +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# buildkite-user-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "buildkite-user-access-token" +description = "Detected a Buildkite user access token, which may expose pipelines, builds, and organization data." +regex = '''\b(bkua_(?:[a-z0-9]{40}|[a-z0-9]{53}))\b''' +confidence = "high" +keywords = ["bkua_"] +validate = ''' +let r = http.get("https://api.buildkite.com/v2/access-token", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); +r.status == 200 && ((r.body contains "\"scopes\"")) ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) + +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# canadian-digital-service-notify-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "canadian-digital-service-notify-api-key" +description = "Detected a GC Notify API key, which may allow unauthorized notification access." +regex = '''(?i:\b(ApiKey-v1\s+gcntfy-[a-z0-9_]+-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\b)''' +confidence = "high" +keywords = ["gcntfy-"] +validate = ''' +let r = http.get("https://api.notification.canada.ca/v2/notifications", { + "Authorization": finding["secret"], + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# canva-client-id +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "canva-client-id" +description = "Detected a Canva Connect API client ID, used as a component of the canva-client-secret composite rule." +regex = '''(?i)\b(?:canva|CANVA_CLIENT_ID)(?:.|[\n\r]){0,32}?(?:client[_\s-]*id|app[_\s-]*id)(?:.|[\n\r]){0,16}?\b(OC-[A-Za-z0-9_-]{8,16})\b''' +confidence = "high" +keywords = ["canva"] +skipReport = true +filter = ''' +filter.entropy(finding["secret"]) < 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# canva-client-secret +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "canva-client-secret" +description = "Detected a Canva Connect API client secret, which may allow unauthorized OAuth client authentication when paired with a client ID." +regex = '''\b(cnvca[a-zA-Z0-9_-]{51})\b''' +confidence = "high" +keywords = ["cnvca"] +validate = ''' +let r = http.post("https://api.canva.com/rest/v1/oauth/token", { + "Content-Type": "application/x-www-form-urlencoded", + "Accept": "application/json" + }, + "grant_type=authorization_code&client_id=" + (components["canva-client-id"]?.secret ?? "") + + "&client_secret=" + finding["secret"] + + "&code_verifier=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~abcdefgh&code=invalid"); r.status == 400 && (r.body contains "\"invalid_grant\"") && !(r.body contains "\"invalid_client\"") ? { + "result": "valid" + } : r.status in [400, 401, 403] && (r.body contains "\"invalid_client\"") ? { + "result": "invalid", + "reason": "Invalid client" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 +''' +components = [ + { id = "canva-client-id" }, +] + +# ────────────────────────────────────────────────────────────────────────────── +# cerebras-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "cerebras-api-key" +description = "Identified a Cerebras AI API Key, which may expose AI inference services to unauthorized access." +regex = '''(?i)\b(csk-[a-z0-9]{48})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["csk-"] +validate = ''' +let r = http.get("https://api.cerebras.ai/v1/models", { + "Authorization": "Bearer " + finding["secret"] + }); r.status == 200 && (r.body contains '"object"') && (r.body contains '"data"') ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# checkout-secret-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "checkout-secret-key" +description = "Checkout.com secret key." +regex = '''(?i)(?:checkout)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(sk_[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["checkout"] +validate = ''' +let r = http.get("https://api.checkout.com/workflows", { + "Authorization": "Bearer " + finding["secret"] + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' + +# ────────────────────────────────────────────────────────────────────────────── +# circleci-personal-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "circleci-personal-token" +description = "CircleCI personal access token." +regex = '''\b(CCIPAT_[a-zA-Z0-9]{22}_[a-z0-9]{40})''' +confidence = "high" +keywords = ["ccipat_"] +validate = ''' +let r = http.get("https://circleci.com/api/v2/me", { + "Accept": "application/json", + "Circle-Token": finding["secret"] + }); r.status == 200 && (r.json?.id ?? "") != "" ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# circleci-project-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "circleci-project-token" +description = "CircleCI project token." +regex = '''(?i)(?:circleci)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-f0-9]{40})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["circleci"] +validate = ''' +let r = http.get("https://circleci.com/api/v1.1/projects", { + "Circle-Token": finding["secret"], + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.3 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# cisco-meraki-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "cisco-meraki-api-key" +description = "Cisco Meraki is a cloud-managed IT solution that provides networking, security, and device management through an easy-to-use interface." +regex = '''(?i:(?:(?-i:[Mm]eraki|MERAKI))(?:[ \t\w.-]{0,20})[\s'"]{0,3})(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([0-9a-f]{40})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["meraki"] +validate = ''' +let r = http.get("https://api.meraki.com/api/v1/organizations", { + "X-Cisco-Meraki-API-Key": finding["secret"], + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.3 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# civo-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "civo-api-key" +description = "Detected a Civo Cloud API key, which may expose Kubernetes clusters and compute resources to unauthorized access." +regex = '''(?i)(?:civo)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{50})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["civo"] +validate = ''' +let r = http.get("https://api.civo.com/v2/instances", { + "Authorization": "Bearer " + finding["secret"] + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# clerk-secret-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "clerk-secret-key" +description = "Detected a Clerk secret key, which may allow unauthorized access to Clerk backend APIs." +regex = '''(?i)(?:clerk)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(sk_(?:test|live)_[A-Za-z0-9]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["clerk"] +validate = ''' +let r = http.get("https://api.clerk.com/v1/users?limit=1", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.3 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# clickhouse-cloud-api-secret-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "clickhouse-cloud-api-secret-key" +description = "Identified a pattern that may indicate clickhouse cloud API secret key, risking unauthorized clickhouse cloud api access and data breaches on ClickHouse Cloud platforms." +regex = '''\b(4b1d[A-Za-z0-9]{38})\b''' +confidence = "high" +keywords = ["4b1d"] +validate = ''' +let r = http.get("https://api.clickhouse.cloud/v1/organizations", { + "Authorization": "Basic " + base64.encode(bytes((components["clickhouse-cloud-key-id"]?.secret ?? "") + ":" + finding["secret"])) + }); r.status == 200 && (r.body contains "\"id\":") && (r.body contains "\"name\":") ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 +''' +components = [ + { id = "clickhouse-cloud-key-id" }, +] + +# ────────────────────────────────────────────────────────────────────────────── +# clickhouse-cloud-key-id +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "clickhouse-cloud-key-id" +description = "Detected a ClickHouse Cloud key ID, used as a component of the clickhouse-cloud-api-secret-key composite rule." +regex = '''(?i)\bclickhouse(?:.|[\n\r]){0,16}?(?:ID|USER)(?:.|[\n\r]){0,16}?([a-z0-9]{20})''' +confidence = "high" +keywords = ["clickhouse"] +skipReport = true +filter = ''' +filter.entropy(finding["secret"]) < 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# clickup-personal-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "clickup-personal-api-token" +description = "Detected a ClickUp personal API token, which may allow unauthorized access to ClickUp workspaces and user data." +regex = '''(?i)(?:clickup)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(pk_[0-9]{8,9}_[a-z0-9]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["clickup"] +validate = ''' +let r = http.get("https://api.clickup.com/api/v2/user", { + "Accept": "application/json", + "Authorization": finding["secret"] + }); r.status == 200 ? { + "result": "valid", + "username": (r.json?.user?.username ?? ""), + "email": (r.json?.user?.email ?? "") + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# clojars-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "clojars-api-token" +description = "Uncovered a possible Clojars API token, risking unauthorized access to Clojure libraries and potential code manipulation." +regex = '''(?i)CLOJARS_[a-z0-9]{60}''' +confidence = "high" +keywords = ["clojars_"] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# cloudflare-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "cloudflare-api-key" +description = "Detected a Cloudflare API Key, potentially compromising cloud application deployments and operational security." +regex = '''(?i)(?:cloudflare)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9_-]{40})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["cloudflare"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# cloudflare-global-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "cloudflare-global-api-key" +description = "Detected a Cloudflare Global API Key, potentially compromising cloud application deployments and operational security." +regex = '''(?i)(?:cloudflare)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-f0-9]{37})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["cloudflare"] +filter = ''' +filter.entropy(finding["secret"]) < 3.3 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# cloudflare-origin-ca-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "cloudflare-origin-ca-key" +description = "Detected a Cloudflare Origin CA Key, potentially compromising cloud application deployments and operational security." +regex = '''\b(v1\.0-[a-f0-9]{24}-[a-f0-9]{146})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = [ + "cloudflare", + "v1.0-", +] +filter = ''' +filter.entropy(finding["secret"]) < 3.3 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# cloudinary-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "cloudinary-api-key" +description = "Detected a Cloudinary API key, used as a component of the cloudinary-api-secret composite rule." +regex = '''(?i)\bcloudinary(?:.|[\n\r]){0,32}?(?:API[_\s]?KEY|KEY)(?:.|[\n\r]){0,16}?\b([0-9]{15})\b''' +confidence = "high" +keywords = ["cloudinary"] +skipReport = true +filter = ''' +filter.entropy(finding["secret"]) < 2.75 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# cloudinary-api-secret +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "cloudinary-api-secret" +description = "Detected a Cloudinary API secret, which may allow unauthorized access to Cloudinary media and account APIs when paired with a cloud name and API key." +regex = '''(?i)\bcloudinary(?:.|[\n\r]){0,32}?(?:SECRET|PRIVATE|API[_\s]?SECRET)(?:.|[\n\r]){0,32}?\b([A-Za-z0-9]{32})\b''' +confidence = "high" +keywords = ["cloudinary"] +validate = ''' +let r = http.get("https://api.cloudinary.com/v1_1/" + (components["cloudinary-cloud-name"]?.secret ?? "") + "/usage", { + "Authorization": "Basic " + base64.encode(bytes((components["cloudinary-api-key"]?.secret ?? "") + ":" + finding["secret"])), + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' +components = [ + { id = "cloudinary-api-key" }, + { id = "cloudinary-cloud-name" }, +] + +# ────────────────────────────────────────────────────────────────────────────── +# cloudinary-cloud-name +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "cloudinary-cloud-name" +description = "Detected a Cloudinary cloud name, used as a component of the cloudinary-api-secret composite rule." +regex = '''(?i)\bcloudinary(?:.|[\n\r]){0,32}?(?:CLOUD[_\s]?NAME|CLOUD)(?:.|[\n\r]){0,16}?\b([a-z0-9_-]{3,32})\b''' +confidence = "high" +keywords = ["cloudinary"] +skipReport = true + +# ────────────────────────────────────────────────────────────────────────────── +# cloudsmith-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "cloudsmith-api-key" +description = "Detected a Cloudsmith API key, which may expose package repositories and artifact management operations to unauthorized access." +regex = '''\b(csa_[a-f0-9]{30}[A-Za-z0-9]{6})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["csa_"] +validate = ''' +let r = http.get("https://api.cloudsmith.io/user/self/", { + "Authorization": "Bearer " + finding["secret"] + }); r.status == 200 && (r.json?.authenticated ?? false) == true ? { + "result": "valid", + "account": (r.json?.slug ?? "") + } : r.status in [401, 403] || (r.status == 200 && (r.json?.authenticated ?? false) == false) ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' + +# ────────────────────────────────────────────────────────────────────────────── +# cockroachlabs-cloud-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "cockroachlabs-cloud-api-key" +description = "Detected a CockroachDB Cloud service account API key, which may allow unauthorized access to CockroachDB Cloud resources." +regex = '''\b(CCDB1_[A-Za-z0-9]{22}_[A-Za-z0-9]{40})\b''' +confidence = "high" +keywords = ["ccdb1_"] +validate = ''' +let r = http.get("https://cockroachlabs.cloud/api/v1/clusters", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 && (r.body contains "\"clusters\"") && (r.body contains "\"pagination\"") ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# codecov-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "codecov-access-token" +description = "Found a pattern resembling a Codecov Access Token, posing a risk of unauthorized access to code coverage reports and sensitive data." +regex = '''(?i)(?:codecov)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([A-Z0-9-]{36})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["codecov"] +validate = ''' +let r = http.get("https://api.codecov.io/api/v2/github/", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 && (r.body contains "\"count\":") ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# cohere-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "cohere-api-token" +description = "Identified a Cohere Token, posing a risk of unauthorized access to AI services and data manipulation." +regex = '''(?i:(?:cohere|CO_API_KEY)(?:[ \t\w.-]{0,20})[\s'"]{0,3})(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-zA-Z0-9]{40})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = [ + "cohere", + "co_api_key", +] +validate = ''' +let r = http.get("https://api.cohere.com/v1/connectors", { + "Authorization": "Bearer " + finding["secret"] + }); r.status == 200 && (r.body contains '"connectors"') && (r.body contains '"total_count"') ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 4.0 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# coinbase-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "coinbase-access-token" +description = "Detected a Coinbase Access Token, posing a risk of unauthorized access to cryptocurrency accounts and financial transactions." +regex = '''(?i)(?:coinbase)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9_-]{64})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["coinbase"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# configcat-sdk-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "configcat-sdk-key" +description = "Detected a ConfigCat SDK key, which may allow access to feature flag configuration data." +regex = '''(?i)(?:configcat)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([A-Za-z0-9_-]{22}/[A-Za-z0-9_-]{22})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["configcat"] +validate = ''' +let r = http.get("https://cdn-global.configcat.com/configuration-files/" + finding["secret"] + "/config_v6.json", { + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403, 404] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# configcat-sdk-key-extended +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "configcat-sdk-key-extended" +description = "Detected an extended ConfigCat SDK key, which may allow access to feature flag configuration data." +regex = '''\b(configcat-sdk-1/[A-Za-z0-9_-]{22}/[A-Za-z0-9_-]{22})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["configcat-sdk-1"] +validate = ''' +let r = http.get("https://cdn-global.configcat.com/configuration-files/" + finding["secret"] + "/config_v6.json", { + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403, 404] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# confluent-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "confluent-access-token" +description = "Identified a Confluent Access Token, which could compromise access to streaming data platforms and sensitive data flow." +regex = '''(?i)(?:confluent)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{16})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["confluent"] +filter = ''' +filter.entropy(finding["secret"]) < 3.0 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# confluent-secret-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "confluent-secret-key" +description = "Found a Confluent Secret Key, potentially risking unauthorized operations and data access within Confluent services." +regex = '''(?i)(?:confluent)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{64})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["confluent"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# contentful-delivery-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "contentful-delivery-api-token" +description = "Discovered a Contentful delivery API token, posing a risk to content management systems and data integrity." +regex = '''(?i)(?:contentful)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9=_\-]{43})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["contentful"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# couchbase-capella-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "couchbase-capella-api-key" +description = "Detected a Couchbase Capella API key secret, which may allow unauthorized access to Couchbase Capella management APIs." +regex = '''(?i)\b(?:couchbase|capella)(?:.|[\n\r]){0,32}?(?:api(?:.|[\n\r]){0,12}?(?:key|secret)|key(?:.|[\n\r]){0,12}?secret)(?:.|[\n\r]){0,32}?\b([A-Za-z0-9+/]{60,120}={0,2})\b''' +confidence = "high" +keywords = [ + "couchbase", + "capella", +] +validate = ''' +let r = http.get("https://cloudapi.cloud.couchbase.com/v4/organizations", { + "Accept": "application/json", + "Authorization": "Bearer " + finding["secret"] + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 4.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# coveralls-personal-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "coveralls-personal-api-token" +description = "Detected a Coveralls personal API token, which may expose repository coverage data." +regex = '''(?i)(?:coveralls)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([A-Za-z0-9-]{37})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["coveralls"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# crates-io-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "crates-io-api-key" +description = "crates.io API key." +regex = '''(?i)(?:crates(?:[_.-]?io)?)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(cio[A-Za-z0-9]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["crates"] +validate = ''' +let r = http.get("https://crates.io/api/v1/me", { + "Authorization": finding["secret"] + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' + +# ────────────────────────────────────────────────────────────────────────────── +# curl-auth-header +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "curl-auth-header" +description = "Discovered a potential authorization token provided in a curl command header, which could compromise the curl accessed resource." +regex = '''\bcurl\b(?:.*?|.*?(?:[\r\n]{1,2}.*?){1,5})[ \t\n\r](?:-H|--header)(?:=|[ \t]{0,5})(?:"(?i)(?:Authorization:[ \t]{0,5}(?:Basic[ \t]([a-z0-9+/]{8,}={0,3})|(?:Bearer|(?:Api-)?Token)[ \t]([\w=~@.+/-]{8,})|([\w=~@.+/-]{8,}))|(?:(?:X-(?:[a-z]+-)?)?(?:Api-?)?(?:Key|Token)):[ \t]{0,5}([\w=~@.+/-]{8,}))"|'(?i)(?:Authorization:[ \t]{0,5}(?:Basic[ \t]([a-z0-9+/]{8,}={0,3})|(?:Bearer|(?:Api-)?Token)[ \t]([\w=~@.+/-]{8,})|([\w=~@.+/-]{8,}))|(?:(?:X-(?:[a-z]+-)?)?(?:Api-?)?(?:Key|Token)):[ \t]{0,5}([\w=~@.+/-]{8,}))')(?:\B|\s|\z)''' +confidence = "high" +keywords = ["curl"] +filter = ''' +entropy(finding["secret"]) <= 2.75 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# curl-auth-user +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "curl-auth-user" +description = "Discovered a potential basic authorization token provided in a curl command, which could compromise the curl accessed resource." +regex = '''\bcurl\b(?:.*|.*(?:[\r\n]{1,2}.*){1,5})[ \t\n\r](?:-u|--user)(?:=|[ \t]{0,5})("(:[^"]{3,}|[^:"]{3,}:|[^:"]{3,}:[^"]{3,})"|'([^:']{3,}:[^']{3,})'|((?:"[^"]{3,}"|'[^']{3,}'|[\w$@.-]+):(?:"[^"]{3,}"|'[^']{3,}'|[\w${}@.-]+)))(?:\s|\z)''' +confidence = "high" +keywords = ["curl"] +filter = ''' +entropy(finding["secret"]) <= 2.0 +|| matchesAny(finding["secret"], [ + `[^:]+:(?:change(?:it|me)|pass(?:word)?|pwd|test|token|\*+|x+)`, + `['"]?<[^>]+>['"]?:['"]?<[^>]+>|<[^:]+:[^>]+>['"]?`, + `[^:]+:\[[^]]+]`, + `['"]?[^:]+['"]?:['"]?\$(?:\d|\w+|\{(?:\d|\w+)})['"]?`, + `['"]?\$\{(?:[^{}]|\{[^}]*\})*\}['"]?:['"]?\$\{(?:[^{}]|\{[^}]*\})*\}['"]?`, + `\$\([^)]+\):\$\([^)]+\)`, + `['"]?\$?{{[^}]+}}['"]?:['"]?\$?{{[^}]+}}['"]?` +]) +''' + +# ────────────────────────────────────────────────────────────────────────────── +# cursor-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "cursor-api-key" +description = "Detected a Cursor Integrations API Key, which may expose AI-assisted development services to unauthorized access." +regex = '''(?i)(?:cursor)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(key_[0-9a-f]{64})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["cursor"] +validate = ''' +let r = http.get("https://api.cursor.com/v0/me", { + "Accept": "application/json", + "Authorization": "Basic " + base64.encode(bytes(finding["secret"])) + }); r.status == 200 && (r.body contains '"userEmail"') ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# databento-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "databento-api-key" +description = "Databento API key." +regex = '''(?i)(?:databento)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(db-[A-Za-z0-9]{29})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["databento"] +validate = ''' +let r = http.get("https://hist.databento.com/v0/metadata.list_datasets", { + "Authorization": "Basic " + base64.encode(bytes(finding["secret"] + ":")) + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' + +# ────────────────────────────────────────────────────────────────────────────── +# databricks-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "databricks-api-token" +description = "Uncovered a Databricks API token, which may compromise big data analytics platforms and sensitive data processing." +regex = '''\b(dapi[a-f0-9]{32}(?:-\d)?)(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["dapi"] +filter = ''' +entropy(finding["secret"]) < 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# datadog-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "datadog-api-key" +description = "Detected a Datadog API key, potentially risking monitoring and analytics data exposure and manipulation." +regex = '''(?i)(?:datadog)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["datadog"] +validate = ''' +let r = http.get("https://api.datadoghq.com/api/v1/validate", { + "Accept": "application/json", + "DD-API-KEY": finding["secret"] + }); r.status == 200 && !(r.body contains "\"Forbidden\"") ? { + "result": "valid" + } : r.status in [401, 403] || (r.body contains "\"Forbidden\"") ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# datadog-application-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "datadog-application-key" +description = "Detected a Datadog application key, which may expose Datadog account and monitoring data when paired with an API key." +regex = '''(?i)(?:datadog)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([A-Za-z0-9-]{40})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["datadog"] +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# datagov-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "datagov-api-key" +description = "Detected a Data.gov API key, which may expose usage of Data.gov-backed APIs." +regex = '''(?i)(?:data\.gov)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{40})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["data.gov"] +validate = ''' +let r = http.get("https://developer.nrel.gov/api/alt-fuel-stations/v1.json?limit=1&api_key=" + finding["secret"], { + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# datastax-astra-application-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "datastax-astra-application-token" +description = "DataStax Astra application token." +regex = '''\b(AstraCS:[A-Za-z0-9]{20,})''' +confidence = "high" +keywords = ["astracs:"] +validate = ''' +let r = http.get("https://api.astra.datastax.com/v2/tokens", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status == 401 ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 4.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# deepgram-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "deepgram-api-key" +description = "Detected a Deepgram API Key, which may expose speech recognition services and audio data to unauthorized access." +regex = '''(?i)(?:deepgram)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-f0-9]{40})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["deepgram"] +filter = ''' +filter.entropy(finding["secret"]) < 3.3 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# deepseek-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "deepseek-api-key" +description = "Detected a DeepSeek API Key, which may expose AI model access and associated usage to unauthorized parties." +regex = '''(?i)(?:deepseek)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(sk-[a-f0-9]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["deepseek"] +validate = ''' +let r = http.get("https://api.deepseek.com/models", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 && (r.body contains '"data"') ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# defined-networking-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "defined-networking-api-token" +description = "Identified a Defined Networking API token, which could lead to unauthorized network operations and data breaches." +regex = '''(?i)(?:dnkey)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(dnkey-[a-z0-9=_\-]{26}-[a-z0-9=_\-]{52})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["dnkey"] + +# ────────────────────────────────────────────────────────────────────────────── +# deno-account-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "deno-account-token" +description = "Detected a Deno account token, which may expose Deno Deploy account access." +regex = '''\b(ddp_[A-Za-z0-9]{36})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["ddp_"] +validate = ''' +let r = http.get("https://api.deno.com/v1/user", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); +r.status == 200 && ((r.body contains "\"id\"")) ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) + +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# devcycle-client-sdk-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "devcycle-client-sdk-key" +description = "DevCycle client SDK key." +regex = '''\b(dvc_client_[A-Za-z0-9]{8,32})''' +confidence = "high" +keywords = ["dvc_client_"] +validate = ''' +let r = http.post("https://bucketing-api.devcycle.com/v1/variables", { + "Authorization": "Bearer " + finding["secret"], + "Content-Type": "application/json" + }, "{\"user_id\":\"betterleaks-validation-user\"}"); r.status == 200 ? { + "result": "valid" + } : r.status == 401 ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# devcycle-mobile-sdk-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "devcycle-mobile-sdk-key" +description = "DevCycle mobile SDK key." +regex = '''\b(dvc_mobile_[A-Za-z0-9]{8,32})''' +confidence = "high" +keywords = ["dvc_mobile_"] +validate = ''' +let r = http.post("https://bucketing-api.devcycle.com/v1/variables", { + "Authorization": "Bearer " + finding["secret"], + "Content-Type": "application/json" + }, "{\"user_id\":\"betterleaks-validation-user\"}"); r.status == 200 ? { + "result": "valid" + } : r.status == 401 ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# devcycle-server-sdk-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "devcycle-server-sdk-key" +description = "DevCycle server SDK key." +regex = '''\b(dvc_server_[A-Za-z0-9]{8,32})''' +confidence = "high" +keywords = ["dvc_server_"] +validate = ''' +let r = http.post("https://bucketing-api.devcycle.com/v1/variables", { + "Authorization": "Bearer " + finding["secret"], + "Content-Type": "application/json" + }, "{\"user_id\":\"betterleaks-validation-user\"}"); r.status == 200 ? { + "result": "valid" + } : r.status == 401 ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# devin-personal-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "devin-personal-api-key" +description = "Detected a Cognition Devin personal API key, which may expose Devin sessions and user data." +regex = '''\b(apk_user_[A-Za-z0-9+/]{120,180}={0,2})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["apk_user_"] +validate = ''' +let r = http.get("https://api.devin.ai/v1/sessions?limit=1", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); +r.status == 200 && ((r.body contains "\"sessions\"")) ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) + +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# devin-service-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "devin-service-api-key" +description = "Detected a Cognition Devin service API key, which may expose Devin sessions and organization access." +regex = '''\b(apk_[A-Za-z0-9+/]{80,100}={0,2})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["apk_"] +validate = ''' +let r = http.get("https://api.devin.ai/v1/sessions?limit=1", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); +r.status == 200 && ((r.body contains "\"sessions\"")) ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) + +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# devin-service-user-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "devin-service-user-token" +description = "Detected a Cognition Devin service user token, which may expose Devin service user access." +regex = '''\b(cog_[a-z2-7]{52})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["cog_"] +validate = ''' +let r = http.get("https://api.devin.ai/v3/self", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); +r.status == 200 && ((r.body contains "\"principal_type\"") || (r.body contains "\"service_user_id\"")) ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) + +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# digitalocean-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "digitalocean-access-token" +description = "Found a DigitalOcean OAuth Access Token, risking unauthorized cloud resource access and data compromise." +regex = '''\b(doo_v1_[a-f0-9]{64})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["doo_v1_"] +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# digitalocean-pat +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "digitalocean-pat" +description = "Discovered a DigitalOcean Personal Access Token, posing a threat to cloud infrastructure security and data privacy." +regex = '''\b(dop_v1_[a-f0-9]{64})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["dop_v1_"] +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# digitalocean-refresh-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "digitalocean-refresh-token" +description = "Uncovered a DigitalOcean OAuth Refresh Token, which could allow prolonged unauthorized access and resource manipulation." +regex = '''(?i)\b(dor_v1_[a-f0-9]{64})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["dor_v1_"] + +# ────────────────────────────────────────────────────────────────────────────── +# discord-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "discord-api-token" +description = "Detected a Discord API key, potentially compromising communication channels and user data privacy on Discord." +regex = '''(?i)(?:discord)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-f0-9]{64})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["discord"] +filter = ''' +filter.entropy(finding["secret"]) < 3.3 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# discord-client-id +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "discord-client-id" +description = "Identified a Discord client ID, which may lead to unauthorized integrations and data exposure in Discord applications." +regex = '''(?i)(?:discord)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([0-9]{18})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["discord"] +filter = ''' +filter.entropy(finding["secret"]) < 2.75 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# discord-client-secret +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "discord-client-secret" +description = "Discovered a potential Discord client secret, risking compromised Discord bot integrations and data leaks." +regex = '''(?i)(?:discord)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9=_\-]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["discord"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# disqus-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "disqus-api-key" +description = "Detected a Disqus API key, which may expose Disqus thread and account data." +regex = '''(?i)(?:disqus)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{64})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["disqus"] +validate = ''' +let r = http.get("https://disqus.com/api/3.0/threads/list.json?limit=1&api_secret=" + finding["secret"], { + "Accept": "application/json" + }); r.status == 200 && (r.body contains "\"code\":0") && (r.body contains "\"response\"") ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# docker-swarm-join-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "docker-swarm-join-token" +description = "Docker Swarm join token." +regex = '''\b(SWMTKN-1-[a-z0-9]{50,60}-[a-z0-9]{24,30})''' +confidence = "high" +keywords = ["swmtkn-1-"] +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# docker-swarm-unlock-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "docker-swarm-unlock-key" +description = "Docker Swarm unlock key." +regex = '''\b(SWMKEY-1-[A-Za-z0-9+/]{40,50})''' +confidence = "high" +keywords = ["swmkey-1-"] +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# dockerhub-organization-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "dockerhub-organization-access-token" +description = "Detected a Docker Hub organization access token, which may expose organization repositories." +regex = '''\b(dckr_oat_[A-Za-z0-9_-]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["dckr_oat_"] +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# dockerhub-personal-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "dockerhub-personal-access-token" +description = "Detected a Docker Hub personal access token, which may expose Docker Hub account access." +regex = '''\b(dckr_pat_[A-Za-z0-9_-]{27})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["dckr_pat_"] +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# doppler-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "doppler-api-token" +description = "Discovered a Doppler API token, posing a risk to environment and secrets management security." +regex = '''dp\.pt\.(?i)[a-z0-9]{43}''' +confidence = "high" +keywords = ["dp.pt."] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# droneci-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "droneci-access-token" +description = "Detected a Droneci Access Token, potentially compromising continuous integration and deployment workflows." +regex = '''(?i)(?:droneci)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["droneci"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# dropbox-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "dropbox-api-token" +description = "Identified a Dropbox API secret, which could lead to unauthorized file access and data breaches in Dropbox storage." +regex = '''(?i)(?:dropbox)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{15})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["dropbox"] +filter = ''' +filter.entropy(finding["secret"]) < 3.0 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# dropbox-long-lived-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "dropbox-long-lived-api-token" +description = "Found a Dropbox long-lived API token, risking prolonged unauthorized access to cloud storage and sensitive data." +regex = '''(?i)(?:dropbox)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{11}(AAAAAAAAAA)[a-z0-9\-_=]{43})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["dropbox"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# dropbox-short-lived-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "dropbox-short-lived-api-token" +description = "Discovered a Dropbox short-lived API token, posing a risk of temporary but potentially harmful data access and manipulation." +regex = '''(?i)(?:dropbox)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(sl\.[a-z0-9\-=_]{135})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["dropbox"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# duffel-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "duffel-api-token" +description = "Uncovered a Duffel API token, which may compromise travel platform integrations and sensitive customer data." +regex = '''duffel_(?:test|live)_(?i)[a-z0-9_\-=]{43}''' +confidence = "high" +keywords = ["duffel_"] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# dynatrace-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "dynatrace-api-token" +description = "Detected a Dynatrace API token, potentially risking application performance monitoring and data exposure." +regex = '''dt0c01\.(?i)[a-z0-9]{24}\.[a-z0-9]{64}''' +confidence = "high" +keywords = ["dt0c01."] +filter = ''' +entropy(finding["secret"]) <= 4.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# easypost-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "easypost-api-token" +description = "Identified an EasyPost API token, which could lead to unauthorized postal and shipment service access and data exposure." +regex = '''\bEZAK(?i)[a-z0-9]{54}\b''' +confidence = "high" +keywords = ["ezak"] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# easypost-test-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "easypost-test-api-token" +description = "Detected an EasyPost test API token, risking exposure of test environments and potentially sensitive shipment data." +regex = '''\bEZTK(?i)[a-z0-9]{54}\b''' +confidence = "high" +keywords = ["eztk"] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# ebay-client-id +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "ebay-client-id" +description = "eBay client ID, used as a component of the eBay client-secret composite rule." +regex = '''\b([a-zA-Z0-9_-]+-[a-zA-Z0-9_-]+-PRD-[a-f0-9]{8,12}-[a-f0-9]{8,12})''' +confidence = "high" +keywords = ["-prd-"] +skipReport = true +filter = ''' +entropy(finding["secret"]) < 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# ebay-client-secret +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "ebay-client-secret" +description = "eBay client secret." +regex = '''(?i:(?:ebay(?:[_. -]*(?:client|api))?[_. -]*(?:secret|key))(?:[ \t\w.-]{0,20})[\s'"]{0,3})(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(PRD-[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4,12})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["ebay"] +validate = ''' +let clientID = (components["ebay-client-id"]?.secret ?? ""); +let r = http.post("https://api.ebay.com/identity/v1/oauth2/token/introspect", { + "Authorization": "Basic " + base64.encode(bytes(clientID + ":" + finding["secret"])), + "Content-Type": "application/x-www-form-urlencoded", + "Accept": "application/json" +}, "token=betterleaks-validation-token&token_type_hint=access_token"); +r.status == 200 && (r.json?.active ?? true) == false ? { + "result": "valid" +} : r.status == 401 && (r.json?.error ?? "") == "invalid_client" ? { + "result": "invalid", + "reason": "Invalid client" +} : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.0 +''' +components = [ + { id = "ebay-client-id" }, +] + +# ────────────────────────────────────────────────────────────────────────────── +# elastic-cloud-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "elastic-cloud-api-key" +description = "Identified an Elastic Cloud Serverless API key, which may expose Elasticsearch and Kibana resources to unauthorized access." +regex = '''\b(essu_[A-Za-z0-9_\-]{60,200}={0,2})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["essu_"] +validate = ''' +let r = http.get("https://api.elastic-cloud.com/api/v1/deployments", { + "Authorization": "ApiKey " + finding["secret"] + }); r.status == 200 && (r.body contains '"deployments"') ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' + +# ────────────────────────────────────────────────────────────────────────────── +# elevenlabs-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "elevenlabs-api-key" +description = "Detected an ElevenLabs API Key, which may expose AI voice synthesis services to unauthorized access." +regex = '''(?i)(?:elevenlabs)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(sk_[0-9a-f]{48})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["elevenlabs"] +filter = ''' +entropy(finding["secret"]) <= 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# endorlabs-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "endorlabs-api-key" +description = "Detected an Endor Labs API Key, which may compromise supply chain security scanning and software composition analysis." +regex = '''(?i)(?:endor(?:labs)?|key)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(endr\+[A-Za-z0-9-]{16})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["endr+"] +filter = ''' +entropy(finding["secret"]) < 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# endorlabs-api-secret +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "endorlabs-api-secret" +description = "Detected an Endor Labs API Secret, which together with an API key grants full access to Endor Labs supply chain security services." +regex = '''(?i)(?:endor(?:labs)?|secret)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(endr\+[A-Za-z0-9-]{16})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["endr+"] +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# etsy-open-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "etsy-open-api-key" +description = "Found an Etsy Open API key, potentially compromising Etsy app access and shop integrations." +regex = '''(?i)(?:etsy|x-api-key)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{24}:[a-z0-9]{10,64})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = [ + "etsy", + "x-api-key", +] +validate = ''' +let k = finding["secret"].split(":")[0]; (let r = http.get("https://api.etsy.com/v3/application/openapi-ping", { + "x-api-key": k, + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r)) +''' +filter = ''' +entropy(finding["secret"]) < 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# exoscale-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "exoscale-api-key" +description = "Identified an Exoscale API key paired with a secret, which together grant programmatic access to Exoscale cloud resources." +regex = '''\b(EXO[a-zA-Z0-9]{24,30})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["exo"] +validate = ''' +let ts = time.nowUnix(); (let sig = crypto.hmacSha256( + bytes((components["exoscale-api-secret"]?.secret ?? "")), + bytes("GET /v2/zone\n\n\n\n" + ts) + ); (let r = http.get("https://api-ch-gva-2.exoscale.com/v2/zone", { + "Authorization": "EXO2-HMAC-SHA256 credential=" + finding["secret"] + ",expires=" + ts + ",signature=" + base64.encode(sig) + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r))) +''' +components = [ + { id = "exoscale-api-secret", within = "5L" }, +] + +# ────────────────────────────────────────────────────────────────────────────── +# exoscale-api-secret +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "exoscale-api-secret" +description = "Identified an Exoscale API secret, used as a component of the exoscale-api-key composite rule." +regex = '''(?i)(?:exoscale)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([A-Za-z0-9_\-]{40,60})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["exoscale"] +skipReport = true + +# ────────────────────────────────────────────────────────────────────────────── +# facebook-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "facebook-access-token" +description = "Discovered a Facebook Access Token, posing a risk of unauthorized access to Facebook accounts and personal data exposure." +regex = '''(?i)\b(\d{15,16}(\||%)[0-9a-z\-_]{27,40})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["facebook"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# facebook-page-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "facebook-page-access-token" +description = "Discovered a Facebook Page Access Token, posing a risk of unauthorized access to Facebook accounts and personal data exposure." +regex = '''\b(EAA[MC](?i)[a-z0-9]{100,})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = [ + "eaam", + "eaac", +] +filter = ''' +filter.entropy(finding["secret"]) < 4.0 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# facebook-secret +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "facebook-secret" +description = "Discovered a Facebook Application secret, posing a risk of unauthorized access to Facebook accounts and personal data exposure." +regex = '''(?i)(?:facebook)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-f0-9]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["facebook"] +filter = ''' +filter.entropy(finding["secret"]) < 3.0 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# fastly-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "fastly-api-token" +description = "Uncovered a Fastly API key, which may compromise CDN and edge cloud services, leading to content delivery and security issues." +regex = '''(?i)(?:fastly)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9_-]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["fastly"] +validate = ''' +let r = http.get("https://api.fastly.com/current_user", { + "Fastly-Key": finding["secret"] + }); r.status == 200 ? { + "result": "valid", + "login": (r.json?.login ?? ""), + "name": (r.json?.name ?? ""), + "customer_id": (r.json?.customer_id ?? "") + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# figma-personal-access-header-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "figma-personal-access-header-token" +description = "Uncovered a Figma Personal Access Token in a header, which may compromise design assets and team collaboration." +regex = '''(?i)(?:x-figma-token|xfigmatoken|x_figma_token)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([0-9A-F]{4}-[0-9A-F]{8}(?:-[0-9A-F]{4}){3}-[0-9A-F]{12})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = [ + "x-figma-token", + "xfigmatoken", + "x_figma_token", +] +validate = ''' +let r = http.get("https://api.figma.com/v1/me", { + "X-Figma-Token": finding["secret"] + }); r.status == 200 && !(r.body contains "Invalid token") ? { + "result": "valid", + "email": (r.json?.email ?? ""), + "handle": (r.json?.handle ?? ""), + "id": (r.json?.id ?? "") + } : r.status in [401, 403] || (r.body contains "Invalid token") ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' + +# ────────────────────────────────────────────────────────────────────────────── +# figma-personal-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "figma-personal-access-token" +description = "Uncovered a Figma Personal Access Token, which may compromise design assets and team collaboration." +regex = '''(?i)\b(figd_[A-Z0-9_-]{38,42})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["figd_"] +validate = ''' +let r = http.get("https://api.figma.com/v1/me", { + "X-Figma-Token": finding["secret"] + }); r.status == 200 && !(r.body contains "Invalid token") ? { + "result": "valid", + "email": (r.json?.email ?? ""), + "handle": (r.json?.handle ?? ""), + "id": (r.json?.id ?? "") + } : r.status in [401, 403] || (r.body contains "Invalid token") ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# finicity-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "finicity-api-token" +description = "Detected a Finicity API token, potentially risking financial data access and unauthorized financial operations." +regex = '''(?i)(?:finicity)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-f0-9]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["finicity"] +filter = ''' +filter.entropy(finding["secret"]) < 3.3 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# finicity-client-secret +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "finicity-client-secret" +description = "Identified a Finicity Client Secret, which could lead to compromised financial service integrations and data breaches." +regex = '''(?i)(?:finicity)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{20})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["finicity"] +filter = ''' +filter.entropy(finding["secret"]) < 3.0 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# finnhub-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "finnhub-access-token" +description = "Found a Finnhub Access Token, risking unauthorized access to financial market data and analytics." +regex = '''(?i)(?:finnhub)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{20})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["finnhub"] +filter = ''' +filter.entropy(finding["secret"]) < 3.0 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# flickr-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "flickr-access-token" +description = "Discovered a Flickr Access Token, posing a risk of unauthorized photo management and potential data leakage." +regex = '''(?i)(?:flickr)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["flickr"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# flutterwave-encryption-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "flutterwave-encryption-key" +description = "Uncovered a Flutterwave Encryption Key, which may compromise payment processing and sensitive financial information." +regex = '''FLWSECK_TEST-(?i)[a-h0-9]{12}''' +confidence = "high" +keywords = ["flwseck_test"] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# flutterwave-public-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "flutterwave-public-key" +description = "Detected a Flutterwave Public Key, potentially exposing public cryptographic operations and integrations." +regex = '''FLWPUBK_TEST-(?i)[a-h0-9]{32}-X''' +confidence = "high" +keywords = ["flwpubk_test"] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# flutterwave-secret-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "flutterwave-secret-key" +description = "Identified a Flutterwave Secret Key, risking unauthorized financial transactions and data breaches." +regex = '''FLWSECK_TEST-(?i)[a-h0-9]{32}-X''' +confidence = "high" +keywords = ["flwseck_test"] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# flyio-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "flyio-access-token" +description = "Uncovered a Fly.io API key" +regex = '''\b(FlyV1\s[A-Za-z0-9=_\-,/+]{100,})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["flyv1"] +validate = ''' +let r = http.post("https://api.fly.io/graphql", { + "Authorization": "Bearer " + finding["secret"], + "Content-Type": "application/json" + }, "{\"query\": \"query { viewer { id email name } }\"}"); r.status == 200 && (r.body contains "\"data\"") && (r.body contains "\"viewer\"") && (r.body contains "\"email\"") ? { + "result": "valid", + "email": (r.json?.data?.viewer?.email ?? ""), + "name": (r.json?.data?.viewer?.name ?? "") + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 4.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# frameio-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "frameio-api-token" +description = "Found a Frame.io API token, potentially compromising video collaboration and project management." +regex = '''fio-u-(?i)[a-z0-9\-_=]{64}''' +confidence = "high" +keywords = ["fio-u-"] +validate = ''' +let r = http.get("https://api.frame.io/v2/me", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status == 401 ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.3 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# freemius-secret-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "freemius-secret-key" +description = "Detected a Freemius secret key, potentially exposing sensitive information." +regex = '''(?i)["']secret_key["']\s*=>\s*["'](sk_[\S]{29})["']''' +path = '''(?i)\.php$''' +confidence = "medium" +keywords = ["secret_key"] + +# ────────────────────────────────────────────────────────────────────────────── +# freshbooks-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "freshbooks-access-token" +description = "Discovered a Freshbooks Access Token, posing a risk to accounting software access and sensitive financial data exposure." +regex = '''(?i)(?:freshbooks)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{64})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["freshbooks"] +validate = ''' +let r = http.get("https://api.freshbooks.com/auth/api/v1/users/me", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); +r.status == 200 && (true) ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) + +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# fullstory-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "fullstory-api-key" +description = "FullStory API key." +regex = '''(?i)(?:(?:fullstory|fs_api|fullstory_api))(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}((?:na1|eu1)\.[A-Za-z0-9]{20,})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = [ + "fullstory", + "fs_api", +] +validate = ''' +let r = http.get("https://api.fullstory.com/me", { + "Authorization": "Basic " + base64.encode(bytes(finding["secret"] + ":")), + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status == 401 ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.3 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# gcp-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "gcp-api-key" +description = "Uncovered a GCP API key, which could lead to unauthorized access to Google Cloud services and data breaches." +regex = '''\b(AIza[\w-]{35})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["aiza"] +validate = ''' +let k = http.get("https://www.googleapis.com/identitytoolkit/v3/relyingparty/getProjectConfig?key=" + finding["secret"], {}); k.status == 400 ? { + "result": "invalid", + "reason": "Unauthorized" + } : (let r = http.get("https://generativelanguage.googleapis.com/v1beta/models?key=" + finding["secret"], {}); r.status == 200 && (r.body contains '"models"') ? { + "result": "valid", + "active_google_key": true, + "gemini_access": true + } : r.status == 403 && (r.body contains "API_KEY_HTTP_REFERRER_BLOCKED") ? { + "result": "needs_validation", + "reason": "Active Google API key blocked by HTTP referrer restriction", + "active_google_key": true, + "gemini_access": "unknown", + "restriction": "http_referrer" + } : r.status == 403 && (r.body contains "API_KEY_IP_ADDRESS_BLOCKED") ? { + "result": "needs_validation", + "reason": "Active Google API key blocked by IP address restriction", + "active_google_key": true, + "gemini_access": "unknown", + "restriction": "ip_address" + } : r.status == 403 && (r.body contains "API_KEY_IOS_APP_BLOCKED") ? { + "result": "needs_validation", + "reason": "Active Google API key blocked by iOS app restriction", + "active_google_key": true, + "gemini_access": "unknown", + "restriction": "ios_app" + } : r.status == 403 && (r.body contains "API_KEY_ANDROID_APP_BLOCKED") ? { + "result": "needs_validation", + "reason": "Active Google API key blocked by Android app restriction", + "active_google_key": true, + "gemini_access": "unknown", + "restriction": "android_app" + } : r.status == 403 && (r.body contains "API_KEY_SERVICE_BLOCKED") ? { + "result": "needs_validation", + "reason": "Active Google API key blocked from Gemini API", + "active_google_key": true, + "gemini_access": false + } : r.status == 403 ? { + "result": "needs_validation", + "reason": "Active Google API key with unknown Gemini access", + "active_google_key": true, + "gemini_access": "unknown" + } : r.status == 400 && k.status in [200, 403] ? { + "result": "needs_validation", + "reason": "Active Google API key not accepted by Gemini API", + "active_google_key": true, + "gemini_access": false + } : r.status == 400 && (r.body contains "API_KEY_INVALID") ? { + "result": "invalid", + "reason": "Unauthorized" + } : r.status == 400 ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r)) +''' +filter = ''' +entropy(finding["secret"]) <= 4.0 +|| matchesAny(finding["secret"], [ + `AIzaSyabcdefghijklmnopqrstuvwxyz1234567`, + `AIzaSyAnLA7NfeLquW1tJFpx_eQCxoX-oo6YyIs`, + `AIzaSyCkEhVjf3pduRDt6d1yKOMitrUEke8agEM`, + `AIzaSyDMAScliyLx7F0NPDEJi1QmyCgHIAODrlU`, + `AIzaSyD3asb-2pEZVqMkmL6M9N6nHZRR_znhrh0`, + `AIzayDNSXIbFmlXbIE6mCzDLQAqITYefhixbX4A`, + `AIzaSyAdOS2zB6NCsk1pCdZ4-P6GBdi_UUPwX7c`, + `AIzaSyASWm6HmTMdYWpgMnjRBjxcQ9CKctWmLd4`, + `AIzaSyANUvH9H9BsUccjsu2pCmEkOPjjaXeDQgY`, + `AIzaSyA5_iVawFQ8ABuTZNUdcwERLJv_a_p4wtM`, + `AIzaSyA4UrcGxgwQFTfaI3no3t7Lt1sjmdnP5sQ`, + `AIzaSyDSb51JiIcB6OJpwwMicseKRhhrOq1cS7g`, + `AIzaSyBF2RrAIm4a0mO64EShQfqfd2AFnzAvvuU`, + `AIzaSyBcE-OOIbhjyR83gm4r2MFCu4MJmprNXsw`, + `AIzaSyB8qGxt4ec15vitgn44duC5ucxaOi4FmqE`, + `AIzaSyA8vmApnrHNFE0bApF4hoZ11srVL_n0nvY` +]) +''' + +# ────────────────────────────────────────────────────────────────────────────── +# gcp-application-default-credentials +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "gcp-application-default-credentials" +description = "Google (GCP) Application Default Credentials" +regex = '''\{[^{]+(?:(?:"client_secret"\s*:\s*"[^"]+"[^}]+"refresh_token"\s*:\s*"[^"]+")|(?:"refresh_token"\s*:\s*"[^"]+"[^}]+"client_secret"\s*:\s*"[^"]+"))[^}]+\}''' +confidence = "high" +keywords = [".apps.googleusercontent.com"] +validate = ''' +let r = gcp.validate(finding["secret"]); r.status == 200 ? { + "result": "valid", + "credential_type": r.credential_type, + "client_id": r.client_id + } : r.status in [400, 401] ? { + "result": "invalid", + "error_code": r.error_code, + "error_message": r.error_message + } : validate.unknown(r) + +''' + +# ────────────────────────────────────────────────────────────────────────────── +# gcp-gemini-api +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "gcp-gemini-api" +description = "Detected a Google Gemini API key, which may expose Gemini model access and usage to unauthorized parties." +regex = '''\b(AQ\.Ab8RN6[A-Za-z0-9_-]{44})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["aq.ab8rn6"] +validate = ''' +let k = http.get("https://www.googleapis.com/identitytoolkit/v3/relyingparty/getProjectConfig?key=" + finding["secret"], {}); k.status == 400 ? { + "result": "invalid", + "reason": "Unauthorized" + } : (let r = http.get("https://generativelanguage.googleapis.com/v1beta/models?key=" + finding["secret"], {}); r.status == 200 && (r.body contains '"models"') ? { + "result": "valid", + "active_google_key": true, + "gemini_access": true + } : r.status == 403 && (r.body contains "API_KEY_HTTP_REFERRER_BLOCKED") ? { + "result": "needs_validation", + "reason": "Active Google API key blocked by HTTP referrer restriction", + "active_google_key": true, + "gemini_access": "unknown", + "restriction": "http_referrer" + } : r.status == 403 && (r.body contains "API_KEY_IP_ADDRESS_BLOCKED") ? { + "result": "needs_validation", + "reason": "Active Google API key blocked by IP address restriction", + "active_google_key": true, + "gemini_access": "unknown", + "restriction": "ip_address" + } : r.status == 403 && (r.body contains "API_KEY_IOS_APP_BLOCKED") ? { + "result": "needs_validation", + "reason": "Active Google API key blocked by iOS app restriction", + "active_google_key": true, + "gemini_access": "unknown", + "restriction": "ios_app" + } : r.status == 403 && (r.body contains "API_KEY_ANDROID_APP_BLOCKED") ? { + "result": "needs_validation", + "reason": "Active Google API key blocked by Android app restriction", + "active_google_key": true, + "gemini_access": "unknown", + "restriction": "android_app" + } : r.status == 403 && (r.body contains "API_KEY_SERVICE_BLOCKED") ? { + "result": "needs_validation", + "reason": "Active Google API key blocked from Gemini API", + "active_google_key": true, + "gemini_access": false + } : r.status == 403 ? { + "result": "needs_validation", + "reason": "Active Google API key with unknown Gemini access", + "active_google_key": true, + "gemini_access": "unknown" + } : r.status == 400 && k.status in [200, 403] ? { + "result": "needs_validation", + "reason": "Active Google API key not accepted by Gemini API", + "active_google_key": true, + "gemini_access": false + } : r.status == 400 && (r.body contains "API_KEY_INVALID") ? { + "result": "invalid", + "reason": "Unauthorized" + } : r.status == 400 ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r)) +''' +filter = ''' +entropy(finding["secret"]) <= 4.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# gcp-service-account +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "gcp-service-account" +description = "Google (GCP) Service-account" +regex = '''\{[^{]+(?:(?:"private_key"\s*:\s*"-----BEGIN (?:RSA )?PRIVATE KEY-----[^}]+auth_provider_x509_cert_url)|(?:auth_provider_x509_cert_url[^}]+"private_key"\s*:\s*"-----BEGIN (?:RSA )?PRIVATE KEY-----))[^}]+\}''' +confidence = "high" +keywords = ["provider_x509"] +validate = ''' +let r = gcp.validate(finding["secret"]); r.status == 200 ? { + "result": "valid", + "credential_type": r.credential_type, + "project_id": r.project_id, + "client_email": r.client_email + } : r.status in [400, 401] ? { + "result": "invalid", + "error_code": r.error_code, + "error_message": r.error_message + } : validate.unknown(r) + +''' +filter = ''' +containsAny(finding["secret"], ["image-pulling@authenticated-image-pulling.iam.gserviceaccount.com"]) +''' + +# ────────────────────────────────────────────────────────────────────────────── +# generic-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "generic-api-key" +description = "Detected a Generic API Key, potentially exposing access to various services and sensitive operations." +regex = '''(?i)(?:access|auth|(?-i:[Aa]pi|API)|credential|creds|key|passw(?:or)?d|secret|token)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([\w.=-]{10,150}|[a-z0-9][a-z0-9+/]{11,}={0,3})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +specificity = 0 +confidence = "low" +keywords = [ + "access", + "api", + "auth", + "key", + "credential", + "creds", + "passwd", + "password", + "secret", + "token", +] +filter = ''' +// Provider checks use a fixed window around the match, clamped to its line. +let providerMatchContext = finding["fragment_raw"][ + max(finding["match_start_idx"] - 150, finding["match_line_start_idx"]): + min(finding["match_end_idx"] + 50, finding["match_line_end_idx"]) +]; + +// Recreate the generic rule's former [\w.-]{0,50} preamble. Only the +// contiguous word, dot, and hyphen suffix immediately before the match counts. +let genericMatchPrefix = filter.findMatch( + finding["fragment_raw"][ + max(finding["match_start_idx"] - 50, finding["match_line_start_idx"]): + finding["match_start_idx"] + ], + `[\w.-]{0,50}$` +); + +// Recreate the generic rule's former regex which includes the [\w.-]{0,50} preamble. +let genericMatchContext = + genericMatchPrefix + + finding["fragment_raw"][finding["match_start_idx"]:finding["match_end_idx"]]; + +let level = filter.matchesAny(genericMatchContext, [ + `(?i)\b[a-z0-9]+[_.-]+token\b` +]) ? "medium" : "low"; +let _ = filter.setConfidence(level); + +// big ol expression to filter out FPs +entropy(finding["secret"]) <= 3.5 +|| filter.failsTokenEfficiency(finding["secret"]) +|| matchesAny(finding["secret"], [`^[a-zA-Z_.-]+$`]) +|| (containsAny(finding["secret"], [ + "000000", + "aaaaaa", + "about", + "abstract", + "academy", + "acces", + "account", + "act-", + "act.", + "act_", + "action", + "active", + "actively", + "activity", + "adapter", + "add-", + "add.", + "add_", + "add-on", + "addon", + "addres", + "admin", + "adobe", + "advanced", + "adventure", + "agent", + "agile", + "air-", + "air.", + "air_", + "ajax", + "akka", + "alert", + "alfred", + "algorithm", + "all-", + "all.", + "all_", + "alloy", + "alpha", + "amazon", + "amqp", + "analysi", + "analytic", + "analyzer", + "android", + "angular", + "angularj", + "animate", + "animation", + "another", + "ansible", + "answer", + "ant-", + "ant.", + "ant_", + "any-", + "any.", + "any_", + "apache", + "app-", + "app.", + "app_", + "apple", + "arch", + "archive", + "archived", + "arduino", + "array", + "art-", + "art.", + "art_", + "article", + "asp-", + "asp.", + "asp_", + "asset", + "async", + "atom", + "attention", + "audio", + "audit", + "aura", + "auth", + "author", + "authorize", + "auto", + "automated", + "automatic", + "awesome", + "aws_", + "azure", + "back", + "backbone", + "backend", + "backup", + "bar-", + "bar.", + "bar_", + "base", + "based", + "bash", + "basic", + "batch", + "been", + "beer", + "behavior", + "being", + "benchmark", + "best", + "beta", + "better", + "big-", + "big.", + "big_", + "binary", + "binding", + "bit-", + "bit.", + "bit_", + "bitcoin", + "block", + "blog", + "board", + "book", + "bookmark", + "boost", + "boot", + "bootstrap", + "bosh", + "bot-", + "bot.", + "bot_", + "bower", + "box-", + "box.", + "box_", + "boxen", + "bracket", + "branch", + "bridge", + "browser", + "brunch", + "buffer", + "bug-", + "bug.", + "bug_", + "build", + "builder", + "building", + "buildout", + "buildpack", + "built", + "bundle", + "busines", + "but-", + "but.", + "but_", + "button", + "cache", + "caching", + "cakephp", + "calendar", + "call", + "camera", + "campfire", + "can-", + "can.", + "can_", + "canva", + "captcha", + "capture", + "card", + "carousel", + "case", + "cassandra", + "cat-", + "cat.", + "cat_", + "category", + "center", + "cento", + "challenge", + "change", + "changelog", + "channel", + "chart", + "chat", + "cheat", + "check", + "checker", + "chef", + "ches", + "chinese", + "chosen", + "chrome", + "ckeditor", + "clas", + "classe", + "classic", + "clean", + "cli-", + "cli.", + "cli_", + "client", + "clojure", + "clone", + "closure", + "cloud", + "club", + "cluster", + "cms-", + "cms_", + "coco", + "code", + "coding", + "coffee", + "color", + "combination", + "combo", + "command", + "commander", + "comment", + "commit", + "common", + "community", + "compas", + "compiler", + "complete", + "component", + "composer", + "computer", + "computing", + "con-", + "con.", + "con_", + "concept", + "conf", + "config", + "connect", + "connector", + "console", + "contact", + "container", + "contao", + "content", + "contest", + "context", + "control", + "convert", + "converter", + "conway'", + "cookbook", + "cookie", + "cool", + "copy", + "cordova", + "core", + "couchbase", + "couchdb", + "countdown", + "counter", + "course", + "craft", + "crawler", + "create", + "creating", + "creator", + "credential", + "crm-", + "crm.", + "crm_", + "cros", + "crud", + "csv-", + "csv.", + "csv_", + "cube", + "cucumber", + "cuda", + "current", + "currently", + "custom", + "daemon", + "dark", + "dart", + "dash", + "dashboard", + "data", + "database", + "date", + "day-", + "day.", + "day_", + "dead", + "debian", + "debug", + "debugger", + "deck", + "define", + "del-", + "del.", + "del_", + "delete", + "demo", + "deploy", + "design", + "designer", + "desktop", + "detection", + "detector", + "dev-", + "dev.", + "dev_", + "develop", + "developer", + "device", + "devise", + "diff", + "digital", + "directive", + "directory", + "discovery", + "display", + "django", + "dns-", + "dns_", + "doc-", + "doc.", + "doc_", + "docker", + "docpad", + "doctrine", + "document", + "doe-", + "doe.", + "doe_", + "dojo", + "dom-", + "dom.", + "dom_", + "domain", + "done", + "don't", + "dot-", + "dot.", + "dot_", + "dotfile", + "download", + "draft", + "drag", + "drill", + "drive", + "driven", + "driver", + "drop", + "dropbox", + "drupal", + "dsl-", + "dsl.", + "dsl_", + "dynamic", + "easy", + "_ec2_", + "ecdsa", + "eclipse", + "edit", + "editing", + "edition", + "editor", + "element", + "emac", + "email", + "embed", + "embedded", + "ember", + "emitter", + "emulator", + "encoding", + "endpoint", + "engine", + "english", + "enhanced", + "entity", + "entry", + "env_", + "episode", + "erlang", + "error", + "espresso", + "event", + "evented", + "example", + "exchange", + "exercise", + "experiment", + "expire", + "exploit", + "explorer", + "export", + "exporter", + "expres", + "ext-", + "ext.", + "ext_", + "extended", + "extension", + "external", + "extra", + "extractor", + "fabric", + "facebook", + "factory", + "fake", + "fast", + "feature", + "feed", + "fewfwef", + "ffmpeg", + "field", + "file", + "filter", + "find", + "finder", + "firefox", + "firmware", + "first", + "fish", + "fix-", + "fix_", + "flash", + "flask", + "flat", + "flex", + "flexible", + "flickr", + "flow", + "fluent", + "fluentd", + "fluid", + "folder", + "font", + "force", + "foreman", + "fork", + "form", + "format", + "formatter", + "forum", + "foundry", + "framework", + "free", + "friend", + "friendly", + "front-end", + "frontend", + "ftp-", + "ftp.", + "ftp_", + "fuel", + "full", + "fun-", + "fun.", + "fun_", + "func", + "future", + "gaia", + "gallery", + "game", + "gateway", + "gem-", + "gem.", + "gem_", + "gen-", + "gen.", + "gen_", + "general", + "generator", + "generic", + "genetic", + "get-", + "get.", + "get_", + "getenv", + "getting", + "ghost", + "gist", + "git-", + "git.", + "git_", + "github", + "gitignore", + "gitlab", + "glas", + "gmail", + "gnome", + "gnu-", + "gnu.", + "gnu_", + "goal", + "golang", + "gollum", + "good", + "google", + "gpu-", + "gpu.", + "gpu_", + "gradle", + "grail", + "graph", + "graphic", + "great", + "grid", + "groovy", + "group", + "grunt", + "guard", + "gui-", + "gui.", + "gui_", + "guide", + "guideline", + "gulp", + "gwt-", + "gwt.", + "gwt_", + "hack", + "hackathon", + "hacker", + "hacking", + "hadoop", + "haml", + "handler", + "hardware", + "has-", + "has_", + "hash", + "haskell", + "have", + "haxe", + "hello", + "help", + "helper", + "here", + "hero", + "heroku", + "high", + "hipchat", + "history", + "home", + "homebrew", + "homepage", + "hook", + "host", + "hosting", + "hot-", + "hot.", + "hot_", + "house", + "how-", + "how.", + "how_", + "html", + "http", + "hub-", + "hub.", + "hub_", + "hubot", + "human", + "icon", + "ide-", + "ide.", + "ide_", + "idea", + "identity", + "idiomatic", + "image", + "impact", + "import", + "important", + "importer", + "impres", + "index", + "infinite", + "info", + "injection", + "inline", + "input", + "inside", + "inspector", + "instagram", + "install", + "installer", + "instant", + "intellij", + "interface", + "internet", + "interview", + "into", + "intro", + "ionic", + "iphone", + "ipython", + "irc-", + "irc_", + "iso-", + "iso.", + "iso_", + "issue", + "jade", + "jasmine", + "java", + "jbos", + "jekyll", + "jenkin", + "jetbrains", + "job-", + "job.", + "job_", + "joomla", + "jpa-", + "jpa.", + "jpa_", + "jquery", + "json", + "just", + "kafka", + "karma", + "kata", + "kernel", + "keyboard", + "kindle", + "kit-", + "kit.", + "kit_", + "kitchen", + "knife", + "koan", + "kohana", + "lab-", + "lab.", + "lab_", + "lambda", + "lamp", + "language", + "laravel", + "last", + "latest", + "latex", + "launcher", + "layer", + "layout", + "lazy", + "ldap", + "leaflet", + "league", + "learn", + "learning", + "led-", + "led.", + "led_", + "leetcode", + "les-", + "les.", + "les_", + "level", + "leveldb", + "lib-", + "lib.", + "lib_", + "librarie", + "library", + "license", + "life", + "liferay", + "light", + "lightbox", + "like", + "line", + "link", + "linked", + "linkedin", + "linux", + "lisp", + "list", + "lite", + "little", + "load", + "loader", + "local", + "location", + "lock", + "log-", + "log.", + "log_", + "logger", + "logging", + "logic", + "login", + "logstash", + "longer", + "look", + "love", + "lua-", + "lua.", + "lua_", + "mac-", + "mac.", + "mac_", + "machine", + "made", + "magento", + "magic", + "mail", + "make", + "maker", + "making", + "man-", + "man.", + "man_", + "manage", + "manager", + "manifest", + "manual", + "map-", + "map.", + "map_", + "mapper", + "mapping", + "markdown", + "markup", + "master", + "math", + "matrix", + "maven", + "md5", + "mean", + "media", + "mediawiki", + "meetup", + "memcached", + "memory", + "menu", + "merchant", + "message", + "messaging", + "meta", + "metadata", + "meteor", + "method", + "metric", + "micro", + "middleman", + "migration", + "minecraft", + "miner", + "mini", + "minimal", + "mirror", + "mit-", + "mit.", + "mit_", + "mobile", + "mocha", + "mock", + "mod-", + "mod.", + "mod_", + "mode", + "model", + "modern", + "modular", + "module", + "modx", + "money", + "mongo", + "mongodb", + "mongoid", + "mongoose", + "monitor", + "monkey", + "more", + "motion", + "moved", + "movie", + "mozilla", + "mqtt", + "mule", + "multi", + "multiple", + "music", + "mustache", + "mvc-", + "mvc.", + "mvc_", + "mysql", + "nagio", + "name", + "native", + "need", + "neo-", + "neo.", + "neo_", + "nest", + "nested", + "net-", + "net.", + "net_", + "nette", + "network", + "new-", + "new.", + "new_", + "next", + "nginx", + "ninja", + "nlp-", + "nlp.", + "nlp_", + "node", + "nodej", + "nosql", + "not-", + "not.", + "not_", + "note", + "notebook", + "notepad", + "notice", + "notifier", + "now-", + "now.", + "now_", + "number", + "oauth", + "object", + "objective", + "obsolete", + "ocaml", + "octopres", + "official", + "old-", + "old.", + "old_", + "onboard", + "online", + "only", + "open", + "opencv", + "opengl", + "openshift", + "openwrt", + "option", + "oracle", + "org-", + "org.", + "org_", + "origin", + "original", + "orm-", + "orm.", + "orm_", + "osx-", + "osx_", + "our-", + "our.", + "our_", + "out-", + "out.", + "out_", + "output", + "over", + "overview", + "own-", + "own.", + "own_", + "pack", + "package", + "packet", + "page", + "panel", + "paper", + "paperclip", + "para", + "parallax", + "parallel", + "parse", + "parser", + "parsing", + "particle", + "party", + "password", + "patch", + "path", + "pattern", + "payment", + "paypal", + "pdf-", + "pdf.", + "pdf_", + "pebble", + "people", + "perl", + "personal", + "phalcon", + "phoenix", + "phone", + "phonegap", + "photo", + "php-", + "php.", + "php_", + "physic", + "picker", + "pipeline", + "platform", + "play", + "player", + "please", + "plu-", + "plu.", + "plu_", + "plug-in", + "plugin", + "plupload", + "png-", + "png.", + "png_", + "poker", + "polyfill", + "polymer", + "pool", + "pop-", + "pop.", + "pop_", + "popcorn", + "popup", + "port", + "portable", + "portal", + "portfolio", + "post", + "power", + "powered", + "powerful", + "prelude", + "pretty", + "preview", + "principle", + "print", + "pro-", + "pro.", + "pro_", + "problem", + "proc", + "product", + "profile", + "profiler", + "program", + "progres", + "project", + "protocol", + "prototype", + "provider", + "proxy", + "public", + "pull", + "puppet", + "pure", + "purpose", + "push", + "pusher", + "pyramid", + "python", + "quality", + "query", + "queue", + "quick", + "rabbitmq", + "rack", + "radio", + "rail", + "railscast", + "random", + "range", + "raspberry", + "rdf-", + "rdf.", + "rdf_", + "react", + "reactive", + "read", + "reader", + "readme", + "ready", + "real", + "reality", + "real-time", + "realtime", + "recipe", + "recorder", + "red-", + "red.", + "red_", + "reddit", + "redi", + "redmine", + "reference", + "refinery", + "refresh", + "registry", + "related", + "release", + "remote", + "rendering", + "repo", + "report", + "request", + "require", + "required", + "requirej", + "research", + "resource", + "response", + "resque", + "rest", + "restful", + "resume", + "reveal", + "reverse", + "review", + "riak", + "rich", + "right", + "ring", + "robot", + "role", + "room", + "router", + "routing", + "rpc-", + "rpc.", + "rpc_", + "rpg-", + "rpg.", + "rpg_", + "rspec", + "ruby-", + "ruby.", + "ruby_", + "rule", + "run-", + "run.", + "run_", + "runner", + "running", + "runtime", + "rust", + "rvm-", + "rvm.", + "rvm_", + "salt", + "sample", + "sandbox", + "sas-", + "sas.", + "sas_", + "sbt-", + "sbt.", + "sbt_", + "scala", + "scalable", + "scanner", + "schema", + "scheme", + "school", + "science", + "scraper", + "scratch", + "screen", + "script", + "scroll", + "scs-", + "scs.", + "scs_", + "sdk-", + "sdk.", + "sdk_", + "sdl-", + "sdl.", + "sdl_", + "search", + "secure", + "security", + "see-", + "see.", + "see_", + "seed", + "select", + "selector", + "selenium", + "semantic", + "sencha", + "send", + "sentiment", + "serie", + "server", + "service", + "session", + "set-", + "set.", + "set_", + "setting", + "setup", + "sha1", + "sha2", + "sha256", + "share", + "shared", + "sharing", + "sheet", + "shell", + "shield", + "shipping", + "shop", + "shopify", + "shortener", + "should", + "show", + "showcase", + "side", + "silex", + "simple", + "simulator", + "single", + "site", + "skeleton", + "sketch", + "skin", + "slack", + "slide", + "slider", + "slim", + "small", + "smart", + "smtp", + "snake", + "snapshot", + "snippet", + "soap", + "social", + "socket", + "software", + "solarized", + "solr", + "solution", + "solver", + "some", + "soon", + "source", + "space", + "spark", + "spatial", + "spec", + "sphinx", + "spine", + "spotify", + "spree", + "spring", + "sprite", + "sql-", + "sql.", + "sql_", + "sqlite", + "ssh-", + "ssh.", + "ssh_", + "stack", + "staging", + "standard", + "stanford", + "start", + "started", + "starter", + "startup", + "stat", + "statamic", + "state", + "static", + "statistic", + "statsd", + "statu", + "steam", + "step", + "still", + "stm-", + "stm.", + "stm_", + "storage", + "store", + "storm", + "story", + "strategy", + "stream", + "streaming", + "string", + "stripe", + "structure", + "studio", + "study", + "stuff", + "style", + "sublime", + "sugar", + "suite", + "summary", + "super", + "support", + "supported", + "svg-", + "svg.", + "svg_", + "svn-", + "svn.", + "svn_", + "swagger", + "swift", + "switch", + "switcher", + "symfony", + "symphony", + "sync", + "synopsi", + "syntax", + "system", + "tab-", + "tab.", + "tab_", + "table", + "tag-", + "tag.", + "tag_", + "talk", + "target", + "task", + "tcp-", + "tcp.", + "tcp_", + "tdd-", + "tdd.", + "tdd_", + "team", + "tech", + "template", + "term", + "terminal", + "testing", + "tetri", + "text", + "textmate", + "theme", + "theory", + "three", + "thrift", + "time", + "timeline", + "timer", + "tiny", + "tinymce", + "tip-", + "tip.", + "tip_", + "title", + "todo", + "todomvc", + "token", + "tool", + "toolbox", + "toolkit", + "top-", + "top.", + "top_", + "tornado", + "touch", + "tower", + "tracker", + "tracking", + "traffic", + "training", + "transfer", + "translate", + "transport", + "tree", + "trello", + "try-", + "try.", + "try_", + "tumblr", + "tut-", + "tut.", + "tut_", + "tutorial", + "tweet", + "twig", + "twitter", + "type", + "typo", + "ubuntu", + "uiview", + "ultimate", + "under", + "unit", + "unity", + "universal", + "unix", + "update", + "updated", + "upgrade", + "upload", + "uploader", + "uri-", + "uri.", + "uri_", + "url-", + "url.", + "url_", + "usage", + "usb-", + "usb.", + "usb_", + "use-", + "use.", + "use_", + "used", + "useful", + "user", + "using", + "util", + "utilitie", + "utility", + "vagrant", + "validator", + "value", + "variou", + "varnish", + "version", + "via-", + "via.", + "via_", + "video", + "view", + "viewer", + "vim-", + "vim.", + "vim_", + "vimrc", + "virtual", + "vision", + "visual", + "vpn", + "want", + "warning", + "watch", + "watcher", + "wave", + "way-", + "way.", + "way_", + "weather", + "web-", + "web_", + "webapp", + "webgl", + "webhook", + "webkit", + "webrtc", + "website", + "websocket", + "welcome", + "what", + "what'", + "when", + "where", + "which", + "why-", + "why.", + "why_", + "widget", + "wifi", + "wiki", + "win-", + "win.", + "win_", + "window", + "wip-", + "wip.", + "wip_", + "within", + "without", + "wizard", + "word", + "wordpres", + "work", + "worker", + "workflow", + "working", + "workshop", + "world", + "wrapper", + "write", + "writer", + "writing", + "written", + "www-", + "www.", + "www_", + "xamarin", + "xcode", + "xml-", + "xml.", + "xml_", + "xmpp", + "xxxxxx", + "yahoo", + "yaml", + "yandex", + "yeoman", + "yet-", + "yet.", + "yet_", + "yii-", + "yii.", + "yii_", + "youtube", + "yui-", + "yui.", + "yui_", + "zend", + "zero", + "zip-", + "zip.", + "zip_", + "zsh-", + "zsh.", + "zsh_", + "6fe4476ee5a1832882e326b506d14126" +]) || filter.matchesAny(genericMatchContext, [`(?i)(?:access(?:ibility|or)|access[_.-]?id|random[_.-]?access|api[_.-]?(?:id|name|version)|rapid|capital|[a-z0-9-]*?api[a-z0-9-]*?:jar:|author|X-MS-Exchange-Organization-Auth|Authentication-Results|(?:credentials?[_.-]?id|withCredentials)|(?:bucket|foreign|hot|idx|natural|primary|pub(?:lic)?|schema|sequence)[_.-]?key|(?:turkey)|key[_.-]?(?:alias|board|code|frame|id|length|mesh|name|pair|press(?:ed)?|ring|selector|signature|size|stone|storetype|word|up|down|left|right)|key[_.-]?vault[_.-]?(?:id|name)|keyVaultToStoreSecrets|key(?:store|tab)[_.-]?(?:file|path)|issuerkeyhash|(?-i:[DdMm]onkey|[DM]ONKEY)|keying|(?:secret)[_.-]?(?:length|name|size)|UserSecretsId|(?:csrf)[_.-]?token|(?:io\.jsonwebtoken[ \t]?:[ \t]?[\w-]+)|(?:api|credentials|token)[_.-]?(?:endpoint|ur[il])|public[_.-]?token|(?:key|token)[_.-]?file|(?-i:(?:[A-Z_]+=\n[A-Z_]+=|[a-z_]+=\n[a-z_]+=)(?:\n|\z))|(?-i:(?:[A-Z.]+=\n[A-Z.]+=|[a-z.]+=\n[a-z.]+=)(?:\n|\z)))`])) +|| matchesAny(finding["line"], [ + `--mount=type=secret,`, + `import[ \t]+{[ \t\w,]+}[ \t]+from[ \t]+['"][^'"]+['"]` +]) +|| (matchesAny(attributes["path"], [ + `\.bb$`, + `\.bbappend$`, + `\.bbclass$`, + `\.inc$` +]) && matchesAny(finding["line"], [ + `LICENSE[^=]*=\s*"[^"]+`, + `LIC_FILES_CHKSUM[^=]*=\s*"[^"]+`, + `SRC[^=]*=\s*"[a-zA-Z0-9]+` +])) +|| matchesAny(finding["secret"], [ + `^sb_publishable_[A-Za-z0-9_-]{31}$`, + `^0x4AAAAAA[A-Za-z0-9_-]{15}$`, + `^FCM[a-zA-Z0-9]{13}$`, + `^ysc1_[A-Za-z0-9_-]{48}$`, + `^phc_[A-Za-z0-9_-]{43,44}$`, + `^APP_USR-[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}$`, + `^access-(sandbox|development)-[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}$`, + `^asset-report-(sandbox|development)-[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}$`, + `^public-(sandbox|development|production)-[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}$`, + `^link-(sandbox|development)-[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}$`, + `^hbp_[0-9a-zA-Z]{36}$`, + `^woos-[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}$`, + `^(https://)?[0-9a-zA-Z]{32}\@sentry\.io$`, + `^sub-c-[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}$`, + `^pub-c-[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}$`, + `^hc[a-z]ik_([a-z0-9]{26,58})$`, + `^mob-[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}$`, + `^public-token-test-[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}$`, + `^public-token-live-[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}$`, + `^pdl_sdbx_apikey_[a-z\d]{26}_[a-zA-Z\d]{22}_[a-zA-Z\d]{3}$`, + `^8c6803164dbc395fb7131c9d54843627$` +]) +|| (matchesAny(finding["secret"], [`^pk_test_[A-Za-z0-9]{24}(?:[A-Za-z0-9]{10})?(?:[A-Za-z0-9]{65})?$`]) && filter.containsAny(providerMatchContext, ["stripe", "woo", "wcm"])) +|| (matchesAny(finding["secret"], [`^rk_test_[A-Za-z0-9]{24}(?:[A-Za-z0-9]{10})?(?:[A-Za-z0-9]{65})?$`]) && filter.containsAny(providerMatchContext, ["stripe"])) +|| (matchesAny(finding["secret"], [`^pk_live_[A-Za-z0-9]{24}(?:[A-Za-z0-9]{10})?(?:[A-Za-z0-9]{65})?$`]) && filter.containsAny(providerMatchContext, ["stripe", "woo", "wcm"])) +|| (matchesAny(finding["secret"], [`^pk_test_[A-Za-z0-9_-]{40}$`]) && filter.containsAny(providerMatchContext, ["paystack"])) +|| (matchesAny(finding["secret"], [`^pk_live_[A-Za-z0-9_-]{40}$`]) && filter.containsAny(providerMatchContext, ["paystack"])) +|| (matchesAny(finding["secret"], [`^sandbox_[A-Za-z0-9]{8}_[A-Za-z0-9_-]{16}$`]) && filter.containsAny(providerMatchContext, ["braintree"])) +|| (matchesAny(finding["secret"], [`^production_[A-Za-z0-9]{8}_[A-Za-z0-9_-]{16}$`]) && filter.containsAny(providerMatchContext, ["braintree"])) +|| (matchesAny(finding["secret"], [`^test_[0-9a-zA-Z]{32}$`]) && filter.containsAny(providerMatchContext, ["adyen"])) +|| (matchesAny(finding["secret"], [`^live_[0-9a-zA-Z]{32}$`]) && filter.containsAny(providerMatchContext, ["adyen"])) +|| (matchesAny(finding["secret"], [`^[A-Za-z0-9]{32}$`]) && filter.containsAny(providerMatchContext, ["bugsnag"])) +|| (matchesAny(finding["secret"], [`^[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}$`]) && filter.containsAny(providerMatchContext, ["hcaptcha", "site_key", "sitekey"])) +|| (matchesAny(finding["secret"], [`^[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}$`]) && filter.containsAny(providerMatchContext, ["pendo"])) +|| (matchesAny(finding["secret"], [`^[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}$`]) && filter.containsAny(providerMatchContext, ["instrumentation"])) +|| (matchesAny(finding["secret"], [`^TEST-[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}$`]) && filter.containsAny(providerMatchContext, ["mercado"])) +|| (matchesAny(finding["secret"], [`^[0-9a-fA-F]{32}$`]) && filter.containsAny(providerMatchContext, ["mixpanel"])) +|| (matchesAny(finding["secret"], [`^[0-9a-z]{6}\/[a-z_-]{2,100}$`]) && filter.containsAny(providerMatchContext, ["logrocket"])) +|| (len(finding["secret"]) == 8 && matchesAny(finding["secret"], [`^[0-9a-f]{8}$`]) && filter.containsAny(providerMatchContext, ["honeybadger"])) +|| ((len(finding["secret"]) >= 21 && len(finding["secret"]) <= 24) && matchesAny(finding["secret"], [`^[a-zA-Z0-9=+]{21,24}$`]) && filter.containsAny(providerMatchContext, ["raygun"])) +|| (matchesAny(finding["secret"], [`^key_live_[0-9a-zA-Z]{32}$`]) && filter.containsAny(providerMatchContext, ["branch"])) +|| (matchesAny(finding["secret"], [`^key_test_[0-9a-zA-Z]{32}$`]) && filter.containsAny(providerMatchContext, ["branch"])) +|| (matchesAny(finding["secret"], [`^pub[0-9a-zA-Z]{32}$`]) && filter.containsAny(providerMatchContext, ["datadog", "dd"])) +|| (len(finding["secret"]) == 6 && matchesAny(finding["secret"], [`^[0-9a-zA-Z]{6}$`]) && filter.containsAny(providerMatchContext, ["klaviyo"])) +|| (matchesAny(finding["secret"], [`^[0-9a-zA-Z]{32}$`]) && filter.containsAny(providerMatchContext, ["storefront"])) +|| (matchesAny(finding["secret"], [`^search-[0-9a-zA-Z_-]{24}$`]) && filter.containsAny(providerMatchContext, ["swiftype"])) +|| (len(finding["secret"]) == 20 && matchesAny(finding["secret"], [`^[0-9a-zA-Z_-]{20}$`]) && filter.containsAny(providerMatchContext, ["swiftype"])) +|| (matchesAny(finding["secret"], [`^pk.eyJ1Ijoi[0-9a-zA-Z_-]{1,}\.[0-9a-zA-Z-_]{1,}$`]) && filter.containsAny(providerMatchContext, ["map"])) +|| (matchesAny(finding["secret"], [`^[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}$`]) && filter.containsAny(providerMatchContext, ["crisp"])) +|| (matchesAny(finding["secret"], [`^client-[a-zA-Z0-9]{43}$`]) && filter.containsAny(providerMatchContext, ["statsdig"])) +|| (matchesAny(finding["secret"], [`^sdk-[a-zA-Z0-9]{15,16}$`]) && filter.containsAny(providerMatchContext, ["growthbook"])) +|| (len(finding["secret"]) == 24 && matchesAny(finding["secret"], [`^[a-zA-Z0-9\/=]{24}$`]) && filter.containsAny(providerMatchContext, ["growthbook"])) +|| ((len(finding["secret"]) >= 21 && len(finding["secret"]) <= 22) && matchesAny(finding["secret"], [`^[a-zA-Z0-9]{21,22}$`]) && filter.containsAny(providerMatchContext, ["optimizely"])) +|| (len(finding["secret"]) == 24 && matchesAny(finding["secret"], [`^[0-9a-fA-F]{24}$`]) && filter.containsAny(providerMatchContext, ["launchdarkly"])) +|| (matchesAny(finding["secret"], [`^pk_test_[0-9a-zA-Z]{20,70}$`]) && filter.containsAny(providerMatchContext, ["clerk"])) +|| (matchesAny(finding["secret"], [`^pk_live_[0-9a-zA-Z]{20,70}$`]) && filter.containsAny(providerMatchContext, ["clerk"])) +|| (len(finding["secret"]) == 40 && matchesAny(finding["secret"], [`^[0-9a-zA-Z]{40}$`]) && filter.containsAny(providerMatchContext, ["smartlook"])) +|| ((len(finding["secret"]) >= 5 && len(finding["secret"]) <= 6) && matchesAny(finding["secret"], [`^[0-9A-Z]{5,6}$`]) && filter.containsAny(providerMatchContext, ["fullstory"])) +|| (matchesAny(finding["secret"], [`^[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}$`]) && filter.containsAny(providerMatchContext, ["zendesk", "zdassets.com"])) +|| (len(finding["secret"]) == 27 && matchesAny(finding["secret"], [`^[0-9a-zA-Z]{27}$`]) && filter.containsAny(providerMatchContext, ["rudderstack"])) +|| (matchesAny(finding["secret"], [`^[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}$`]) && filter.containsAny(providerMatchContext, ["web3forms"])) +|| (len(finding["secret"]) == 12 && matchesAny(finding["secret"], [`^[0-9]{12}$`]) && filter.containsAny(providerMatchContext, ["2checkout", "twocheckout"])) +|| (matchesAny(finding["secret"], [`^test_[a-zA-Z0-9]{27}$`]) && filter.containsAny(providerMatchContext, ["paddle"])) +|| (matchesAny(finding["secret"], [`^live_[a-zA-Z0-9]{27}$`]) && filter.containsAny(providerMatchContext, ["paddle"])) +|| (matchesAny(finding["secret"], [`^pk_live_[0-9A-F]{16}$`]) && filter.containsAny(providerMatchContext, ["magic"])) +''' + +# ────────────────────────────────────────────────────────────────────────────── +# gitea-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "gitea-access-token" +description = "Detected a Gitea Access Token, which may expose self-hosted Git repositories and associated code to unauthorized access." +regex = '''(?i)(?:gitea[_.-]?(?:token|key|secret|access))(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-f0-9]{40})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["gitea"] +filter = ''' +filter.entropy(finding["secret"]) < 3.3 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# github-app-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "github-app-token" +description = "Identified a GitHub App Token, which may compromise GitHub application integrations and source code security." +regex = '''(?:ghu|ghs)_[0-9a-zA-Z]{36}''' +confidence = "high" +keywords = [ + "ghu_", + "ghs_", +] +validate = ''' +let base_url = env.getOrDefault("GITHUB_BASE_URL", "https://api.github.com"); (let r = http.get(base_url + "/app", { + "Accept": "application/vnd.github+json", + "Authorization": "Bearer " + finding["secret"] + }); r.status == 200 && (r.json?.slug ?? "") != "" ? { + "result": "valid", + "slug": (r.json?.slug ?? ""), + "name": (r.json?.name ?? ""), + "html_url": (r.json?.html_url ?? ""), + "external_url": (r.json?.external_url ?? "") + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r)) +''' +filter = ''' +entropy(finding["secret"]) <= 3.0 +|| matchesAny(attributes["path"], [`(?:^|/)@octokit/auth-token/README\.md$`]) +''' + +# ────────────────────────────────────────────────────────────────────────────── +# github-fine-grained-pat +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "github-fine-grained-pat" +description = "Found a GitHub Fine-Grained Personal Access Token, risking unauthorized repository access and code manipulation." +regex = '''github_pat_\w{82}''' +confidence = "high" +keywords = ["github_pat_"] +validate = ''' +let base_url = env.getOrDefault("GITHUB_BASE_URL", "https://api.github.com"); (let r = http.get(base_url + "/user", { + "Accept": "application/vnd.github+json", + "Authorization": "token " + finding["secret"] + }); r.status == 200 && (r.json?.login ?? "") != "" ? { + "result": "valid", + "username": (r.json?.login ?? ""), + "name": (r.json?.name ?? ""), + "scopes": (r.headers["x-oauth-scopes"] ?? "") + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r)) +''' +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# github-oauth +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "github-oauth" +description = "Discovered a GitHub OAuth Access Token, posing a risk of compromised GitHub account integrations and data leaks." +regex = '''gho_[0-9a-zA-Z]{36}''' +confidence = "high" +keywords = ["gho_"] +validate = ''' +let base_url = env.getOrDefault("GITHUB_BASE_URL", "https://api.github.com"); (let r = http.get(base_url + "/user", { + "Accept": "application/vnd.github+json", + "Authorization": "token " + finding["secret"] + }); r.status == 200 && (r.json?.login ?? "") != "" ? { + "result": "valid", + "username": (r.json?.login ?? ""), + "name": (r.json?.name ?? ""), + "scopes": (r.headers["x-oauth-scopes"] ?? "") + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r)) +''' +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# github-pat +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "github-pat" +description = "Uncovered a GitHub Personal Access Token, potentially leading to unauthorized repository access and sensitive content exposure." +regex = '''ghp_[0-9a-zA-Z]{36}''' +confidence = "high" +keywords = ["ghp_"] +validate = ''' +let base_url = env.getOrDefault("GITHUB_BASE_URL", "https://api.github.com"); (let r = http.get(base_url + "/user", { + "Accept": "application/vnd.github+json", + "Authorization": "token " + finding["secret"] + }); r.status == 200 && (r.json?.login ?? "") != "" ? { + "result": "valid", + "username": (r.json?.login ?? ""), + "name": (r.json?.name ?? ""), + "scopes": (r.headers["x-oauth-scopes"] ?? "") + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r)) +''' +filter = ''' +entropy(finding["secret"]) <= 3.0 +|| matchesAny(attributes["path"], [`(?:^|/)@octokit/auth-token/README\.md$`]) +''' + +# ────────────────────────────────────────────────────────────────────────────── +# github-refresh-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "github-refresh-token" +description = "Detected a GitHub Refresh Token, which could allow prolonged unauthorized access to GitHub services." +regex = '''ghr_[0-9a-zA-Z]{36}''' +confidence = "high" +keywords = ["ghr_"] +validate = ''' +let base_url = env.getOrDefault("GITHUB_BASE_URL", "https://api.github.com"); (let r = http.get(base_url + "/user", { + "Accept": "application/vnd.github+json", + "Authorization": "token " + finding["secret"] + }); r.status == 200 && (r.json?.login ?? "") != "" ? { + "result": "valid", + "username": (r.json?.login ?? ""), + "name": (r.json?.name ?? ""), + "scopes": (r.headers["x-oauth-scopes"] ?? "") + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r)) +''' +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# gitlab-cicd-job-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "gitlab-cicd-job-token" +description = "Identified a GitLab CI/CD Job Token, potential access to projects and some APIs on behalf of a user while the CI job is running." +regex = '''glcbt-[0-9a-zA-Z]{1,5}_[0-9a-zA-Z_-]{20}''' +confidence = "high" +keywords = ["glcbt-"] +validate = ''' +let r = http.get("https://gitlab.com/api/v4/user", { + "PRIVATE-TOKEN": finding["secret"] + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# gitlab-deploy-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "gitlab-deploy-token" +description = "Identified a GitLab Deploy Token, risking access to repositories, packages and containers with write access." +regex = '''gldt-[0-9a-zA-Z_\-]{20}''' +confidence = "high" +keywords = ["gldt-"] +validate = ''' +let r = http.get("https://gitlab.com/api/v4/user", { + "PRIVATE-TOKEN": finding["secret"] + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# gitlab-feature-flag-client-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "gitlab-feature-flag-client-token" +description = "Identified a GitLab feature flag client token, risks exposing user lists and features flags used by an application." +regex = '''glffct-[0-9a-zA-Z_\-]{20}''' +confidence = "high" +keywords = ["glffct-"] +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# gitlab-feed-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "gitlab-feed-token" +description = "Identified a GitLab feed token, risking exposure of user data." +regex = '''glft-[0-9a-zA-Z_\-]{20}''' +confidence = "high" +keywords = ["glft-"] +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# gitlab-incoming-mail-address-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "gitlab-incoming-mail-address-token" +description = "Identified a GitLab incoming mail token embedded in an email address, risking manipulation of data sent by mail." +regex = '''incoming\+(?:[A-Za-z0-9._-]+-)?\d+-([A-Za-z0-9_-]+)-(?:issue(?:-\d+)?|merge-request)@''' +specificity = 50 +confidence = "high" +keywords = ["incoming+"] +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# gitlab-incoming-mail-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "gitlab-incoming-mail-token" +description = "Identified a GitLab incoming mail token, risking manipulation of data sent by mail." +regex = '''glimt-[0-9a-zA-Z_\-]{25}''' +confidence = "high" +keywords = ["glimt-"] +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# gitlab-kubernetes-agent-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "gitlab-kubernetes-agent-token" +description = "Identified a GitLab Kubernetes Agent token, risking access to repos and registry of projects connected via agent." +regex = '''glagent-[0-9a-zA-Z_\-]{50}''' +confidence = "high" +keywords = ["glagent-"] +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# gitlab-oauth-app-secret +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "gitlab-oauth-app-secret" +description = "Identified a GitLab OIDC Application Secret, risking access to apps using GitLab as authentication provider." +regex = '''gloas-[0-9a-zA-Z_\-]{64}''' +confidence = "high" +keywords = ["gloas-"] +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# gitlab-pat +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "gitlab-pat" +description = "Identified a GitLab Personal Access Token, risking unauthorized access to GitLab repositories and codebase exposure." +regex = '''glpat-[\w-]{20}''' +confidence = "high" +keywords = ["glpat-"] +validate = ''' +let r = http.get("https://gitlab.com/api/v4/personal_access_tokens/self", { + "PRIVATE-TOKEN": finding["secret"] + }); r.status == 200 ? { + "result": "valid", + "name": (r.json?.name ?? "") + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# gitlab-pat-routable +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "gitlab-pat-routable" +description = "Identified a GitLab Personal Access Token (routable), risking unauthorized access to GitLab repositories and codebase exposure." +regex = '''\bglpat-[0-9a-zA-Z_-]{27,300}\.[0-9a-z]{2}[0-9a-z]{7}\b''' +confidence = "high" +keywords = ["glpat-"] +validate = ''' +let r = http.get("https://gitlab.com/api/v4/personal_access_tokens/self", { + "PRIVATE-TOKEN": finding["secret"] + }); r.status == 200 ? { + "result": "valid", + "name": (r.json?.name ?? "") + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 4.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# gitlab-pat-routable-versioned +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "gitlab-pat-routable-versioned" +description = "Identified a GitLab Personal Access Token (routable, versioned), risking unauthorized access to GitLab repositories and codebase exposure." +regex = '''\bglpat-[0-9a-zA-Z_-]{27,300}\.[0-9a-z]{2}\.[0-9a-z]{9}\b''' +confidence = "high" +keywords = ["glpat-"] +validate = ''' +let r = http.get("https://gitlab.com/api/v4/personal_access_tokens/self", { + "PRIVATE-TOKEN": finding["secret"] + }); r.status == 200 ? { + "result": "valid", + "name": (r.json?.name ?? "") + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 4.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# gitlab-ptt +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "gitlab-ptt" +description = "Found a GitLab Pipeline Trigger Token, potentially compromising continuous integration workflows and project security." +regex = '''glptt-[0-9a-f]{40}''' +confidence = "high" +keywords = ["glptt-"] +validate = ''' +let r = http.get("https://gitlab.com/api/v4/user", { + "PRIVATE-TOKEN": finding["secret"] + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# gitlab-rrt +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "gitlab-rrt" +description = "Discovered a GitLab Runner Registration Token, posing a risk to CI/CD pipeline integrity and unauthorized access." +regex = '''GR1348941[\w-]{20}''' +confidence = "high" +keywords = ["gr1348941"] +validate = ''' +let r = http.post("https://gitlab.com/api/v4/runners/verify", { + "Content-Type": "application/x-www-form-urlencoded" + }, "token=" + finding["secret"]); r.status == 200 && !(r.body contains "token is missing") && !(r.body contains "403 Forbidden") ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# gitlab-runner-authentication-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "gitlab-runner-authentication-token" +description = "Discovered a GitLab Runner Authentication Token, posing a risk to CI/CD pipeline integrity and unauthorized access." +regex = '''glrt-[0-9a-zA-Z_\-]{20}''' +confidence = "high" +keywords = ["glrt-"] +validate = ''' +let r = http.get("https://gitlab.com/api/v4/user", { + "PRIVATE-TOKEN": finding["secret"] + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# gitlab-runner-authentication-token-routable +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "gitlab-runner-authentication-token-routable" +description = "Discovered a GitLab Runner Authentication Token (Routable), posing a risk to CI/CD pipeline integrity and unauthorized access." +regex = '''\bglrt-t\d_[0-9a-zA-Z_\-]{27,300}\.[0-9a-z]{2}[0-9a-z]{7}\b''' +confidence = "high" +keywords = ["glrt-"] +validate = ''' +let r = http.get("https://gitlab.com/api/v4/user", { + "PRIVATE-TOKEN": finding["secret"] + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 4.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# gitlab-scim-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "gitlab-scim-token" +description = "Discovered a GitLab SCIM Token, posing a risk to unauthorized access for a organization or instance." +regex = '''glsoat-[0-9a-zA-Z_\-]{20}''' +confidence = "high" +keywords = ["glsoat-"] +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# gitlab-session-cookie +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "gitlab-session-cookie" +description = "Discovered a GitLab Session Cookie, posing a risk to unauthorized access to a user account." +regex = '''_gitlab_session=[0-9a-z]{32}''' +confidence = "high" +keywords = ["_gitlab_session="] +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# gitter-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "gitter-access-token" +description = "Uncovered a Gitter Access Token, which may lead to unauthorized access to chat and communication services." +regex = '''(?i)(?:gitter)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9_-]{40})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["gitter"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# gocardless-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "gocardless-api-token" +description = "Detected a GoCardless API token, potentially risking unauthorized direct debit payment operations and financial data exposure." +regex = '''(?i)(?:gocardless)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(live_(?i)[a-z0-9\-_=]{40})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = [ + "live_", + "gocardless", +] +validate = ''' +let r = http.get("https://api.gocardless.com/customers?limit=1", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json", + "GoCardless-Version": "2015-07-06" + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# grafana-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "grafana-api-key" +description = "Identified a Grafana API key, which could compromise monitoring dashboards and sensitive data analytics." +regex = '''\b(eyJrIjoi[A-Za-z0-9+/]{40,380}={0,2})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["eyjrijoi"] +filter = ''' +entropy(finding["secret"]) < 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# grafana-cloud-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "grafana-cloud-api-token" +description = "Found a Grafana cloud API token, risking unauthorized access to cloud-based monitoring services and data exposure." +regex = '''\b(glc_[A-Za-z0-9+/]{40,150}={0,2})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["glc_"] +validate = ''' +let r = http.get("https://grafana.com/api/stack-regions", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); +r.status == 200 && (true) ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) + +''' +filter = ''' +entropy(finding["secret"]) < 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# grafana-service-account-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "grafana-service-account-token" +description = "Discovered a Grafana service account token, posing a risk of compromised monitoring services and data integrity." +regex = '''\b(glsa_[A-Za-z0-9]{32}_[A-Fa-f0-9]{8})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["glsa_"] +filter = ''' +entropy(finding["secret"]) < 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# greptile-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "greptile-api-key" +description = "Detected a Greptile API Key, which may expose AI-powered code search and analysis services to unauthorized access." +regex = '''(?i)(?:greptile)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-zA-Z0-9+/]{48})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["greptile"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# groq-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "groq-api-key" +description = "Identified a Groq API Key, which may expose high-speed AI inference services to unauthorized access." +regex = '''(?i)\b(gsk_[A-Z0-9]{52})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["gsk_"] +validate = ''' +let r = http.get("https://api.groq.com/openai/v1/models", { + "Authorization": "Bearer " + finding["secret"] + }); r.status == 200 && (r.body contains '"id"') && (r.body contains '"data"') ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# gumroad-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "gumroad-access-token" +description = "Detected a Gumroad access token, which may expose Gumroad account and product data." +regex = '''(?i)(?:gumroad)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}((?:[a-f0-9]{64}|[A-Za-z0-9-]{43}))(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["gumroad"] +validate = ''' +let r = http.get("https://api.gumroad.com/v2/user?access_token=" + finding["secret"], { + "Accept": "application/json" + }); r.status == 200 && (r.body contains "\"success\":true") && (r.body contains "\"user\"") ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# harness-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "harness-api-key" +description = "Identified a Harness Access Token (PAT or SAT), risking unauthorized access to a Harness account." +regex = '''(?:pat|sat)\.[a-zA-Z0-9_-]{22}\.[0-9a-f]{24}\.[a-zA-Z0-9]{20}''' +confidence = "high" +keywords = [ + "pat.", + "sat.", +] +validate = ''' +let r = http.get("https://app.harness.io/v1/orgs?limit=1&page=1", { + "Accept": "application/json", + "x-api-key": finding["secret"] + }); r.status in [200, 403] ? { + "result": "valid" + } : r.status == 401 ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 3.4 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# hashicorp-tf-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "hashicorp-tf-api-token" +description = "Uncovered a HashiCorp Terraform user/org API token, which may lead to unauthorized infrastructure management and security breaches." +regex = '''(?i)[a-z0-9]{14}\.(?-i:atlasv1)\.[a-z0-9\-_=]{60,70}''' +confidence = "high" +keywords = ["atlasv1"] +filter = ''' +entropy(finding["secret"]) <= 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# hashicorp-tf-password +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "hashicorp-tf-password" +description = "Identified a HashiCorp Terraform password field, risking unauthorized infrastructure configuration and security breaches." +regex = '''(?i)(?:administrator_login_password|password)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}("[a-z0-9=_\-]{8,20}")(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +path = '''(?i)\.(?:tf|hcl)$''' +confidence = "medium" +keywords = [ + "administrator_login_password", + "password", +] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# heroku-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "heroku-api-key" +description = "Detected a Heroku API Key, potentially compromising cloud application deployments and operational security." +regex = '''(?i)(?:heroku)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["heroku"] + +# ────────────────────────────────────────────────────────────────────────────── +# heroku-api-key-v2 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "heroku-api-key-v2" +description = "Detected a Heroku API Key, potentially compromising cloud application deployments and operational security." +regex = '''\b((HRKU-AA[0-9a-zA-Z_-]{58}))(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["hrku-aa"] +filter = ''' +entropy(finding["secret"]) <= 4.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# highnote-secret-live-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "highnote-secret-live-key" +description = "Highnote secret API key for the live environment." +regex = '''(?i:(?:highnote(?:[_. -]*(?:api))?[_. -]*(?:secret|key|token|sk[_. -]*live))(?:[ \t\w.-]{0,20})[\s'"]{0,3})(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(sk_live_a2V5Xz[A-Za-z0-9+/]{69}={0,2})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["highnote"] +validate = ''' +let r = http.post("https://api.us.highnote.com/graphql", { + "Authorization": "Basic " + base64.encode(bytes(finding["secret"])), + "Content-Type": "application/json", + "Accept": "application/json" + }, "{\"query\":\"query { ping }\"}"); r.status == 200 && (r.json?.data?.ping ?? "") == "pong" ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# honeycomb-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "honeycomb-api-key" +description = "Detected a Honeycomb API key, which may expose Honeycomb telemetry and environment data." +regex = '''(?i)(?:honeycomb)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}((?:[a-f0-9]{32}|[a-z0-9]{22}))(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["honeycomb"] +validate = ''' +let r = http.get("https://api.honeycomb.io/1/auth", { + "X-Honeycomb-Team": finding["secret"], + "Accept": "application/json" + }); r.status == 200 && (r.body contains "\"team\"") ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# hubspot-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "hubspot-api-key" +description = "Found a HubSpot API Token, posing a risk to CRM data integrity and unauthorized marketing operations." +regex = '''(?i)(?:hubspot)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["hubspot"] + +# ────────────────────────────────────────────────────────────────────────────── +# huggingface-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "huggingface-access-token" +description = "Discovered a Hugging Face Access token, which could lead to unauthorized access to AI models and sensitive data." +regex = '''\b(hf_(?i:[a-z]{34}))(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["hf_"] +validate = ''' +let r = http.get("https://huggingface.co/api/whoami-v2", { + "Authorization": "Bearer " + finding["secret"] + }); r.status == 200 ? { + "result": "valid", + "username": (r.json?.name ?? "") + } : r.status == 401 && (r.body contains "expired") ? { + "result": "revoked", + "reason": "Token expired" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# huggingface-organization-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "huggingface-organization-api-token" +description = "Uncovered a Hugging Face Organization API token, potentially compromising AI organization accounts and associated data." +regex = '''\b(api_org_(?i:[a-z]{34}))(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["api_org_"] +validate = ''' +let r = http.get("https://huggingface.co/api/whoami-v2", { + "Authorization": "Bearer " + finding["secret"] + }); r.status == 200 ? { + "result": "valid", + "username": (r.json?.name ?? "") + } : r.status == 401 && (r.body contains "expired") ? { + "result": "revoked", + "reason": "Token expired" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# ibm-cloud-user-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "ibm-cloud-user-api-key" +description = "Detected an IBM Cloud user API key, which may expose IBM Cloud account resources." +regex = '''(?i)(?:ibm(?:cloud)?|bx)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9_-]{42,44})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["ibm"] +validate = ''' +let r = http.get("https://iam.cloud.ibm.com/v1/apikeys/details?apikey=" + finding["secret"], { + "Authorization": "Basic Yng6Yng=", + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# influxdb-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "influxdb-api-token" +description = "Detected an InfluxDB API token, which may allow unauthorized access to time-series data and InfluxDB organization resources." +regex = '''(?i)(?:\binflux(?:db)?\b(?:.|[\n\r]){0,64}?\b(?:token|api[_-]?key)\b(?:.|[\n\r]){0,32}?)[=:"'\s]{1,8}([A-Za-z0-9+/=_-]{88,})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["influx"] +validate = ''' +let r = http.get("https://us-east-1-1.aws.cloud2.influxdata.com/api/v2/orgs", { + "Authorization": "Token " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 4.0 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# infomaniak-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "infomaniak-api-token" +description = "Detected an Infomaniak API token, which may expose hosting, mail, and cloud services to unauthorized access." +regex = '''(?i)(?:infomaniak)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([A-Za-z0-9_\-]{60,100})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["infomaniak"] +validate = ''' +let r = http.get("https://api.infomaniak.com/1/profile", { + "Authorization": "Bearer " + finding["secret"] + }); r.status == 200 && (r.body contains '"result"') ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 4.0 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# infracost-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "infracost-api-token" +description = "Detected an Infracost API Token, risking unauthorized access to cloud cost estimation tools and financial data." +regex = '''\b(ico-[a-zA-Z0-9]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["ico-"] +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# intercom-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "intercom-api-key" +description = "Identified an Intercom API Token, which could compromise customer communication channels and data privacy." +regex = '''(?i)(?:intercom)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9=_\-]{60})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["intercom"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# intra42-client-secret +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "intra42-client-secret" +description = "Found a Intra42 client secret, which could lead to unauthorized access to the 42School API and sensitive data." +regex = '''\b(s-s4t2(?:ud|af)-(?i)[abcdef0123456789]{64})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = [ + "intra", + "s-s4t2ud-", + "s-s4t2af-", +] +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# ionic-personal-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "ionic-personal-access-token" +description = "Ionic personal access token." +regex = '''\b(ion_[A-Za-z0-9]{42})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["ion_"] +validate = ''' +let r = http.post("https://api.ionic.io/graphql", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json", + "Content-Type": "application/json" + }, "{\"query\":\"query ValidateToken { viewer { __typename } }\"}"); r.status == 200 && (r.body contains "\"data\":{\"viewer\":{\"__typename\":") ? { + "result": "valid" + } : r.status in [401, 403] || (r.body contains "\"Unauthorized\"") ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# jumpcloud-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "jumpcloud-api-key" +description = "Detected a JumpCloud API key, which may expose JumpCloud directory data." +regex = '''(?i)(?:jumpcloud)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{40})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["jumpcloud"] +validate = ''' +let r = http.get("https://console.jumpcloud.com/api/systemusers?limit=1&skip=0", { + "x-api-key": finding["secret"], + "Accept": "application/json" + }); r.status == 200 && (r.body contains "\"results\"") ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# jwt +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "jwt" +description = "Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data." +regex = '''\b(ey[a-zA-Z0-9]{17,}\.ey[a-zA-Z0-9\/\\_-]{17,}\.(?:[a-zA-Z0-9\/\\_-]{10,}={0,2})?)(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["eyj"] +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# jwt-base64 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "jwt-base64" +description = "Detected a Base64-encoded JSON Web Token, posing a risk of exposing encoded authentication and data exchange information." +regex = '''\bZXlK(?:(?PaGJHY2lPaU)|(?PaGNIVWlPaU)|(?PaGNIWWlPaU)|(?PaGRXUWlPaU)|(?PaU5qUWlP)|(?PamNtbDBJanBi)|(?PamRIa2lPaU)|(?PbGNHc2lPbn)|(?PbGJtTWlPaU)|(?PcWEzVWlPaU)|(?PcWQyc2lPb)|(?PcGMzTWlPaU)|(?PcGRpSTZJ)|(?PcmFXUWlP)|(?PclpYbGZiM0J6SWpwY)|(?PcmRIa2lPaUp)|(?PdWIyNWpaU0k2)|(?Pd01tTWlP)|(?Pd01uTWlPaU)|(?Pd2NIUWlPaU)|(?PemRXSWlPaU)|(?PemRuUWlP)|(?PMFlXY2lPaU)|(?PMGVYQWlPaUp)|(?PMWNtd2l)|(?PMWMyVWlPaUp)|(?PMlpYSWlPaU)|(?PMlpYSnphVzl1SWpv)|(?PNElqb2)|(?PNE5XTWlP)|(?PNE5YUWlPaU)|(?PNE5YUWpVekkxTmlJNkl)|(?PNE5YVWlPaU)|(?PNmFYQWlPaU))[a-zA-Z0-9\/\\_+\-\r\n]{40,}={0,2}''' +confidence = "high" +keywords = ["zxlk"] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# kagi-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "kagi-api-key" +description = "Detected a Kagi API key, which may expose Kagi API usage." +regex = '''(?i)(?:kagi)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9_-]{11}\.[a-z0-9_-]{43})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["kagi"] +validate = ''' +let r = http.get("https://kagi.com/api/v0/search?q=test", { + "Authorization": "Bot " + finding["secret"] + }); r.status == 200 && (r.body contains "\"data\":") && (r.body contains "\"results\":") ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# kimi-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "kimi-api-key" +description = "Detected a Kimi API key, which may expose Moonshot AI model access and usage to unauthorized parties." +regex = '''(?i)(?:kimi|moonshot)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(sk-[A-Za-z0-9_-]{48})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = [ + "kimi", + "moonshot", +] +validate = ''' +let r = http.get("https://api.moonshot.ai/v1/models", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 && (r.body contains '"data"') ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# klaviyo-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "klaviyo-api-key" +description = "Detected a Klaviyo API key, which may expose Klaviyo account and marketing data." +regex = '''(?i)(?:klaviyo)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(pk_[a-z0-9]{34})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["klaviyo"] +validate = ''' +let r = http.get("https://a.klaviyo.com/api/accounts", { + "Revision": "2023-02-22", + "Authorization": "Klaviyo-API-Key " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 && (r.body contains "\"data\"") ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# kraken-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "kraken-access-token" +description = "Identified a Kraken Access Token, potentially compromising cryptocurrency trading accounts and financial security." +regex = '''(?i)(?:kraken)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9\/=_\+\-]{80,90})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["kraken"] +filter = ''' +filter.entropy(finding["secret"]) < 4.0 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# kubernetes-secret-yaml +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "kubernetes-secret-yaml" +description = "Possible Kubernetes Secret detected, posing a risk of leaking credentials/tokens from your deployments" +regex = '''(?i)(?:\bkind:[ \t]*["']?\bsecret\b["']?(?s:.){0,1000}?\bdata:(?s:.){0,100}?\s+([\w.-]+:(?:[ \t]*(?:\||>[-+]?)\s+)?[ \t]*(?:["']?[a-z0-9+/]{10,}={0,3}["']?|\{\{[ \t\w"|$:=,.-]+}}|""|''))|\bdata:(?s:.){0,100}?\s+([\w.-]+:(?:[ \t]*(?:\||>[-+]?)\s+)?[ \t]*(?:["']?[a-z0-9+/]{10,}={0,3}["']?|\{\{[ \t\w"|$:=,.-]+}}|""|''))(?s:.){0,1000}?\bkind:[ \t]*["']?\bsecret\b["']?)''' +path = '''(?i)\.ya?ml$''' +confidence = "high" +keywords = ["secret"] +filter = ''' +matchesAny(finding["secret"], [`[\w.-]+:(?:[ \t]*(?:\||>[-+]?)\s+)?[ \t]*(?:\{\{[ \t\w"|$:=,.-]+}}|""|'')`]) +|| matchesAny(finding["match"], [`(kind:(?s:.)+\n---\n(?s:.)+\bdata:|data:(?s:.)+\n---\n(?s:.)+\bkind:)`]) +''' + +# ────────────────────────────────────────────────────────────────────────────── +# kucoin-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "kucoin-access-token" +description = "Found a Kucoin Access Token, risking unauthorized access to cryptocurrency exchange services and transactions." +regex = '''(?i)(?:kucoin)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-f0-9]{24})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["kucoin"] +filter = ''' +filter.entropy(finding["secret"]) < 3.0 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# kucoin-secret-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "kucoin-secret-key" +description = "Discovered a Kucoin Secret Key, which could lead to compromised cryptocurrency operations and financial data breaches." +regex = '''(?i)(?:kucoin)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["kucoin"] +filter = ''' +filter.entropy(finding["secret"]) < 3.3 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# langchain-langsmith-personal-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "langchain-langsmith-personal-access-token" +description = "LangSmith personal access token." +regex = '''\b(lsv2_pt_[0-9a-fA-F]{32}_[0-9a-fA-F]{10})''' +confidence = "high" +keywords = ["lsv2_pt_"] +validate = ''' +let r = http.get("https://api.smith.langchain.com/api/v1/api-key/current", { + "X-API-Key": finding["secret"], + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 4.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# langchain-langsmith-service-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "langchain-langsmith-service-key" +description = "LangSmith service API key." +regex = '''\b(lsv2_sk_[0-9a-fA-F]{32}_[0-9a-fA-F]{10})''' +confidence = "high" +keywords = ["lsv2_sk_"] +validate = ''' +let r = http.get("https://api.smith.langchain.com/api/v1/orgs/current", { + "X-API-Key": finding["secret"], + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 4.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# lark-app-id +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "lark-app-id" +description = "Lark application ID, used as a component of the Lark application-secret rule." +regex = '''\b(cli_[A-Za-z0-9]{16})''' +confidence = "high" +keywords = ["cli_"] +skipReport = true +filter = ''' +filter.entropy(finding["secret"]) < 3.0 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# lark-app-secret +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "lark-app-secret" +description = "Lark application secret." +regex = '''(?i)(?:lark|larksuite)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([A-Za-z0-9]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["lark"] +validate = ''' +let r = http.post("https://open.larksuite.com/open-apis/auth/v3/tenant_access_token/internal", { + "Content-Type": "application/json", + "Accept": "application/json" + }, "{\"app_id\":" + json.string((components["lark-app-id"]?.secret ?? "")) + ",\"app_secret\":" + json.string(finding["secret"]) + "}"); +let code = r.json?.code ?? -1; +r.status == 200 && code == 0 ? { + "result": "valid" + } : r.status == 200 && code in [10003, 10005, 10014, 10015] ? { + "result": "invalid", + "reason": (r.json?.msg ?? "Invalid application credentials") + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' +components = [ + { id = "lark-app-id" }, +] + +# ────────────────────────────────────────────────────────────────────────────── +# launchdarkly-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "launchdarkly-access-token" +description = "Uncovered a Launchdarkly Access Token, potentially compromising feature flag management and application functionality." +regex = '''(?i)(?:launchdarkly)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9=_\-]{40})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["launchdarkly"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# lichess-personal-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "lichess-personal-access-token" +description = "Lichess personal access token." +regex = '''\b(lip_[A-Za-z0-9_]{16,60})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["lip_"] +validate = ''' +let r = http.get("https://lichess.org/api/account", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid", + "username": (r.json?.username ?? "") + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# lighton-paradigm-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "lighton-paradigm-api-key" +description = "Detected a LightOn Paradigm API key, which may expose enterprise LLM services to unauthorized access." +regex = '''(?i)(?:lighton|paradigm)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([A-Za-z0-9_\-]{40,80})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = [ + "lighton", + "paradigm", +] +validate = ''' +let r = http.get("https://paradigm.lighton.ai/api/v2/models", { + "Authorization": "Bearer " + finding["secret"] + }); r.status == 200 && (r.body contains '"object"') ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# linear-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "linear-api-key" +description = "Detected a Linear API Token, posing a risk to project management tools and sensitive task data." +regex = '''lin_api_(?i)[a-z0-9]{40}''' +confidence = "high" +keywords = ["lin_api_"] +validate = ''' +let r = http.post("https://api.linear.app/graphql", { + "Authorization": finding["secret"], + "Content-Type": "application/json" + }, "{\"query\": \"query { viewer { id name email } }\"}"); r.status == 200 && (r.body contains "\"data\"") && (r.body contains "\"viewer\"") ? { + "result": "valid", + "email": (r.json?.data?.viewer?.email ?? ""), + "name": (r.json?.data?.viewer?.name ?? "") + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# linear-client-secret +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "linear-client-secret" +description = "Identified a Linear Client Secret, which may compromise secure integrations and sensitive project management data." +regex = '''(?i)(?:linear)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-f0-9]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["linear"] +filter = ''' +filter.entropy(finding["secret"]) < 3.3 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# linkedin-client-id +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "linkedin-client-id" +description = "Found a LinkedIn Client ID, risking unauthorized access to LinkedIn integrations and professional data exposure." +regex = '''(?i)(?:linked[_-]?in)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{14})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = [ + "linkedin", + "linked_in", + "linked-in", +] +filter = ''' +filter.entropy(finding["secret"]) < 3.0 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# linkedin-client-secret +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "linkedin-client-secret" +description = "Discovered a LinkedIn Client secret, potentially compromising LinkedIn application integrations and user data." +regex = '''(?i)(?:linked[_-]?in)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{16})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = [ + "linkedin", + "linked_in", + "linked-in", +] +filter = ''' +filter.entropy(finding["secret"]) < 3.0 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# lob-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "lob-api-key" +description = "Uncovered a Lob API Key, which could lead to unauthorized access to mailing and address verification services." +regex = '''(?i)(?:lob)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}((live|test)_[a-f0-9]{35})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = [ + "test_", + "live_", +] + +# ────────────────────────────────────────────────────────────────────────────── +# lob-pub-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "lob-pub-api-key" +description = "Detected a Lob Publishable API Key, posing a risk of exposing mail and print service integrations." +regex = '''(?i)(?:lob)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}((test|live)_pub_[a-f0-9]{31})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = [ + "test_pub_", + "live_pub_", +] + +# ────────────────────────────────────────────────────────────────────────────── +# looker-client-id +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "looker-client-id" +description = "Found a Looker Client ID, risking unauthorized access to a Looker account and exposing sensitive data." +regex = '''(?i)(?:looker)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{20})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["looker"] +filter = ''' +filter.entropy(finding["secret"]) < 3.0 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# looker-client-secret +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "looker-client-secret" +description = "Found a Looker Client Secret, risking unauthorized access to a Looker account and exposing sensitive data." +regex = '''(?i)(?:looker)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{24})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["looker"] +filter = ''' +filter.entropy(finding["secret"]) < 3.0 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# mailchimp-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "mailchimp-api-key" +description = "Identified a Mailchimp API key, potentially compromising email marketing campaigns and subscriber data." +regex = '''(?i)(?:MailchimpSDK.initialize|mailchimp)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-f0-9]{32}-us\d\d)(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["mailchimp"] +validate = ''' +let dc = substring(finding["secret"], lastIndexOf(finding["secret"], "-") + 1); (let r = http.get("https://" + dc + ".api.mailchimp.com/3.0/ping", { + "Accept": "application/json", + "Authorization": "Basic " + base64.encode(bytes("x:" + finding["secret"])) + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r)) +''' + +# ────────────────────────────────────────────────────────────────────────────── +# mailersend-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "mailersend-api-token" +description = "MailerSend API token." +regex = '''\b(mlsn\.[A-Za-z0-9]{30,100})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["mlsn."] +validate = ''' +let r = http.get("https://api.mailersend.com/v1/api-quota", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# mailgun-private-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "mailgun-private-api-token" +description = "Found a Mailgun private API token, risking unauthorized email service operations and data breaches." +regex = '''(?i)(?:mailgun)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(key-[a-f0-9]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["mailgun"] +validate = ''' +let r = http.get("https://api.mailgun.net/v3/domains", { + "Accept": "application/json", + "Authorization": "Basic " + base64.encode(bytes("api:" + finding["secret"])) + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' + +# ────────────────────────────────────────────────────────────────────────────── +# mailgun-pub-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "mailgun-pub-key" +description = "Discovered a Mailgun public validation key, which could expose email verification processes and associated data." +regex = '''(?i)(?:mailgun)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(pubkey-[a-f0-9]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["mailgun"] + +# ────────────────────────────────────────────────────────────────────────────── +# mailgun-signing-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "mailgun-signing-key" +description = "Uncovered a Mailgun webhook signing key, potentially compromising email automation and data integrity." +regex = '''(?i)(?:mailgun)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-h0-9]{32}-[a-h0-9]{8}-[a-h0-9]{8})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["mailgun"] + +# ────────────────────────────────────────────────────────────────────────────── +# mapbox-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "mapbox-api-token" +description = "Detected a MapBox API token, posing a risk to geospatial services and sensitive location data exposure." +regex = '''(?i)(?:mapbox)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(pk\.[a-z0-9]{60}\.[a-z0-9]{22})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["mapbox"] + +# ────────────────────────────────────────────────────────────────────────────── +# mattermost-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "mattermost-access-token" +description = "Identified a Mattermost Access Token, which may compromise team communication channels and data privacy." +regex = '''(?i)(?:mattermost)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{26})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["mattermost"] +filter = ''' +filter.entropy(finding["secret"]) < 3.0 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# maxmind-license-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "maxmind-license-key" +description = "Discovered a potential MaxMind license key." +regex = '''\b([A-Za-z0-9]{6}_[A-Za-z0-9]{29}_mmk)(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["_mmk"] +filter = ''' +entropy(finding["secret"]) <= 4.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# mercury-production-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "mercury-production-api-token" +description = "Mercury production API token." +regex = '''\b(mercury_production_[a-z]{3,6}_[A-Za-z0-9]{40,50}_yrucrem)(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["mercury_production_"] +validate = ''' +let r = http.get("https://api.mercury.com/api/v1/accounts", { + "Authorization": "Bearer secret-token:" + finding["secret"], + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# mergify-application-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "mergify-application-key" +description = "Mergify application API key." +regex = '''\b(mergify_application_key_[A-Za-z0-9_-]{40,200})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["mergify_application_key_"] +validate = ''' +let r = http.get("https://api.mergify.com/v1/application", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 && (r.body contains "\"id\"") && (r.body contains "\"name\"") && (r.body contains "\"scope\"") ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.2 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# messagebird-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "messagebird-api-token" +description = "Found a MessageBird API token, risking unauthorized access to communication platforms and message data." +regex = '''(?i)(?:message[_-]?bird)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{25})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = [ + "messagebird", + "message-bird", + "message_bird", +] +filter = ''' +filter.entropy(finding["secret"]) < 3.0 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# messagebird-client-id +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "messagebird-client-id" +description = "Discovered a MessageBird client ID, potentially compromising API integrations and sensitive communication data." +regex = '''(?i)(?:message[_-]?bird)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = [ + "messagebird", + "message-bird", + "message_bird", +] +filter = ''' +filter.entropy(finding["secret"]) < 3.3 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# microsoft-teams-webhook +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "microsoft-teams-webhook" +description = "Uncovered a Microsoft Teams Webhook, which could lead to unauthorized access to team collaboration tools and data leaks." +regex = '''https://[a-z0-9]+\.webhook\.office\.com/webhookb2/[a-z0-9]{8}-([a-z0-9]{4}-){3}[a-z0-9]{12}@[a-z0-9]{8}-([a-z0-9]{4}-){3}[a-z0-9]{12}/IncomingWebhook/[a-z0-9]{32}/[a-z0-9]{8}-([a-z0-9]{4}-){3}[a-z0-9]{12}''' +confidence = "high" +keywords = [ + "webhook.office.com", + "webhookb2", + "incomingwebhook", +] + +# ────────────────────────────────────────────────────────────────────────────── +# midtrans-production-server-client-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "midtrans-production-server-client-key" +description = "Midtrans production server or client key." +regex = '''(?i)(?:midtrans|mid[_-]?)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(Mid-(?:server|client)-[A-Za-z0-9_]{10,20})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = [ + "mid-server-", + "mid-client-", +] +validate = ''' +let r = http.get("https://api.midtrans.com/v2/betterleaks-validation-nonexistent/status", { + "Authorization": "Basic " + base64.encode(bytes(finding["secret"] + ":")), + "Accept": "application/json" + }); r.status == 200 || (r.status == 404 + && (r.json?.status_code ?? "") == "404" + && (r.json?.status_message ?? "") == "The requested resource is not found") ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 2.8 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# minimax-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "minimax-api-key" +description = "Detected a MiniMax API key, which may expose AI model, speech, image, video, or file services to unauthorized access." +regex = '''(?i)\b(sk-api-[A-Za-z0-9_-]{119})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = [ + "sk-api-", + "minimax", +] +validate = ''' +let r = http.get("https://api.minimax.io/v1/models", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 && (r.body contains '"data"') ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# mistral-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "mistral-api-key" +description = "Detected a Mistral AI API Key, which may expose AI language model services to unauthorized access." +regex = '''(?i)(?:mistral)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([A-Z0-9]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["mistral"] +validate = ''' +let r = http.get("https://api.mistral.ai/v1/models", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 && (r.body contains '"data"') ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# mongodb-atlas-service-account-id +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "mongodb-atlas-service-account-id" +description = "Found a MongoDB Atlas service account client ID." +regex = '''\b(mdb_sa_id_[a-f0-9]{24})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["mdb_sa_id_"] +skipReport = true +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# mongodb-atlas-service-account-secret +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "mongodb-atlas-service-account-secret" +description = "Detected a MongoDB Atlas service account client secret, which could allow unauthorized Atlas administration API access when paired with a service account client ID." +regex = '''\b(mdb_sa_sk_[A-Za-z0-9_-]{40})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["mdb_sa_sk_"] +validate = ''' +let r = http.post("https://cloud.mongodb.com/api/oauth/token", { + "Accept": "application/json", + "Content-Type": "application/x-www-form-urlencoded", + "Authorization": "Basic " + base64.encode(bytes((components["mongodb-atlas-service-account-id"]?.secret ?? "") + ":" + finding["secret"])) + }, "grant_type=client_credentials"); r.status == 200 && (r.json?.access_token ?? "") != "" ? { + "result": "valid" + } : r.status == 401 ? { + "result": "invalid", + "reason": (r.json?.error ?? "Unauthorized") + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 3.0 +|| matchesAny(finding["secret"], [`^mdb_sa_sk_[0-9]{40}$`]) +''' +components = [ + { id = "mongodb-atlas-service-account-id" }, +] + +# ────────────────────────────────────────────────────────────────────────────── +# mongodb-connection-string +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "mongodb-connection-string" +description = "Detected a MongoDB connection string with embedded credentials, potentially exposing direct database access and sensitive application data." +regex = '''\b(mongodb(?:\+srv)?://(?P[!-9;-~]{3,50}):(?P[!-?A-~]{3,88})@(?P(?:[a-zA-Z0-9][\w.-]+|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(?::\d{1,5})?(?:,(?:[a-zA-Z0-9][\w.-]+|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(?::\d{1,5})?)*)/?(?:(?P[\w-]+)?(?P\?\w+=[\w@/.$-]+(?:&(?:amp;)?\w+=[\w@/.$-]+)*)?)?)(?:['"\s;\x60]|\\[nr]|\b|$)''' +confidence = "high" +keywords = [ + "mongodb://", + "mongodb+srv://", +] +filter = ''' +entropy(finding["secret"]) <= 4.0 +|| matchesAny(finding["secret"], [ + `(?i)\bmongodb(?:\+srv)?:\/\/(?:user(?:name)?|foo):(?:pass(?:word)?|bar)(?:[^@\/]*)?@`, + `(?i)\bmongodb(?:\+srv)?:\/\/[^\s'"\x60]*(?:\$\{\{[^}]+}}|\$\{[^}]+}|\$[A-Za-z_][A-Za-z0-9_]*|{{[^}]+}}|<[^>]+>|\[[^]]+])[^\s'"\x60]*` +]) +''' + +# ────────────────────────────────────────────────────────────────────────────── +# neon-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "neon-api-key" +description = "Neon API key." +regex = '''\b(napi_[A-Za-z0-9]{64})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["napi_"] +validate = ''' +let r = http.get("https://console.neon.tech/api/v2/projects", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 || (r.status == 400 + && (r.json?.message ?? "") == "org_id is required, you can find it on your organization settings page") ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# netlify-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "netlify-access-token" +description = "Detected a Netlify Access Token, potentially compromising web hosting services and site management." +regex = '''(?i)(?:netlify)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9=_\-]{40,46})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["netlify"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# new-relic-browser-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "new-relic-browser-api-token" +description = "Identified a New Relic ingest browser API token, risking unauthorized access to application performance data and analytics." +regex = '''(?i)(?:new-relic|newrelic|new_relic)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(NRJS-[a-f0-9]{19})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["nrjs-"] +filter = ''' +filter.entropy(finding["secret"]) < 3.0 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# new-relic-insert-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "new-relic-insert-key" +description = "Discovered a New Relic insight insert key, compromising data injection into the platform." +regex = '''(?i)(?:new-relic|newrelic|new_relic)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(NRII-[a-z0-9-]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["nrii-"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# new-relic-user-api-id +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "new-relic-user-api-id" +description = "Found a New Relic user API ID, posing a risk to application monitoring services and data integrity." +regex = '''(?i)(?:new-relic|newrelic|new_relic)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{64})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = [ + "new-relic", + "newrelic", + "new_relic", +] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# new-relic-user-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "new-relic-user-api-key" +description = "Discovered a New Relic user API Key, which could lead to compromised application insights and performance monitoring." +regex = '''(?i)(?:new-relic|newrelic|new_relic)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(NRAK-[a-z0-9]{27})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["nrak"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# notion-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "notion-api-token" +description = "Notion API token" +regex = '''\b(ntn_[0-9]{11}[A-Za-z0-9]{32}[A-Za-z0-9]{3})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["ntn_"] +filter = ''' +entropy(finding["secret"]) <= 4.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# npm-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "npm-access-token" +description = "Uncovered an npm access token, potentially compromising package management and code repository access." +regex = '''(?i)\b(npm_[a-z0-9]{36})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["npm_"] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# nuget-config-password +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "nuget-config-password" +description = "Identified a password within a Nuget config file, potentially compromising package management access." +regex = '''(?i)''' +path = '''(?i)nuget\.config$''' +confidence = "high" +keywords = ["|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9=_\-]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = [ + "nytimes", + "new-york-times", + "newyorktimes", +] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# octopus-deploy-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "octopus-deploy-api-key" +description = "Discovered a potential Octopus Deploy API key, risking application deployments and operational security." +regex = '''\b(API-[A-Z0-9]{26})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["api-"] +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# okta-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "okta-access-token" +description = "Identified an Okta Access Token, which may compromise identity management services and user authentication data." +regex = '''(?i:(?:(?-i:[Oo]kta|OKTA))(?:[ \t\w.-]{0,20})[\s'"]{0,3})(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(00[\w=\-]{40})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["okta"] +filter = ''' +entropy(finding["secret"]) <= 4.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# ollama-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "ollama-api-key" +description = "Detected an Ollama API Key, which may expose local and hosted AI model serving to unauthorized access." +regex = '''(?i)(?:ollama)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-f0-9]{32}\.[a-zA-Z0-9_-]{24})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["ollama"] +filter = ''' +entropy(finding["secret"]) <= 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# onesignal-rich-authentication-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "onesignal-rich-authentication-token" +description = "OneSignal rich authentication token." +regex = '''\b(os_v2_(?:app|org)_[a-z2-7]{103})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = [ + "os_v2_app_", + "os_v2_org_", +] +validate = ''' +let r = http.get("https://api.onesignal.com/apps", { + "Authorization": "Key " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 || (r.status == 403 && size(r.json?.errors ?? []) > 0) ? { + "result": "valid" + } : r.status == 401 ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# onfido-live-api-token-ca +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "onfido-live-api-token-ca" +description = "Onfido live API token." +regex = '''\b(api_live_ca\.[A-Za-z0-9_-]{20,80})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["api_live_ca."] +validate = ''' +let r = http.get("https://api.ca.onfido.com/v3.6/webhooks/", { + "Authorization": "Token token=" + finding["secret"], + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# onfido-live-api-token-eu +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "onfido-live-api-token-eu" +description = "Onfido live API token." +regex = '''\b(api_live\.[A-Za-z0-9_-]{20,80})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["api_live."] +validate = ''' +let r = http.get("https://api.eu.onfido.com/v3.6/webhooks/", { + "Authorization": "Token token=" + finding["secret"], + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# onfido-live-api-token-us +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "onfido-live-api-token-us" +description = "Onfido live API token." +regex = '''\b(api_live_us\.[A-Za-z0-9_-]{20,80})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["api_live_us."] +validate = ''' +let r = http.get("https://api.us.onfido.com/v3.6/webhooks/", { + "Authorization": "Token token=" + finding["secret"], + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# openai-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "openai-api-key" +description = "Found an OpenAI API Key, posing a risk of unauthorized access to AI services and data manipulation." +regex = '''\b(sk-(?:proj|svcacct|admin)-(?:[A-Za-z0-9_-]{74}|[A-Za-z0-9_-]{58}|[A-Za-z0-9_-]{20})T3BlbkFJ(?:[A-Za-z0-9_-]{74}|[A-Za-z0-9_-]{58}|[A-Za-z0-9_-]{20})\b|sk-[a-zA-Z0-9]{20}T3BlbkFJ[a-zA-Z0-9]{20})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["t3blbkfj"] +validate = ''' +let r = http.get("https://api.openai.com/v1/models", { + "Authorization": "Bearer " + finding["secret"] + }); r.status == 200 && (r.json?.object ?? "") == "list" ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# openrouter-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "openrouter-api-key" +description = "Detected an OpenRouter API Key, which may expose access to multiple AI models through the OpenRouter gateway." +regex = '''(?i)\b(sk-or-v1-[0-9a-f]{64})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["sk-or-v1-"] +filter = ''' +entropy(finding["secret"]) <= 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# openshift-user-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "openshift-user-token" +description = "Found an OpenShift user token, potentially compromising an OpenShift/Kubernetes cluster." +regex = '''\b(sha256~[\w-]{43})(?:[^\w-]|\z)''' +confidence = "high" +keywords = ["sha256~"] +filter = ''' +entropy(finding["secret"]) <= 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# openweather-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "openweather-api-key" +description = "OpenWeather API key." +regex = '''(?i:(?:openweather|pyowm)(?:[ \t\w.-]{0,20})[\s'"]{0,3})(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = [ + "openweather", + "pyowm", +] +validate = ''' +let r = http.get("https://api.openweathermap.org/data/2.5/forecast?q=London&appid=" + finding["secret"], { + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# ovh-application-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "ovh-application-key" +description = "OVHcloud Application Key - component of authenticated OVH API requests." +regex = '''(?i)(?:app(?:lication)?[_.-]{0,1}key)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([A-Za-z0-9-]{16})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["ovh"] +skipReport = true +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# ovh-application-secret +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "ovh-application-secret" +description = "OVHcloud Application Secret - component of authenticated OVH API requests, which could allow unauthorized access to OVHcloud infrastructure when combined with Application and Consumer keys." +regex = '''(?i)(?:app(?:lication)?[_.-]{0,1}secret)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([A-Za-z0-9-]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["ovh"] +validate = ''' +let ts = time.nowUnix(); (let url = "https://api.us.ovhcloud.com/1.0/auth/details"; (let sig_payload = finding["secret"] + "+" + (components["ovh-consumer-key"]?.secret ?? "") + "+GET+" + url + "++" + ts; (let sig = "$1$" + hex.encode(crypto.sha1(bytes(sig_payload))); (let r = http.get(url, { + "X-Ovh-Application": (components["ovh-application-key"]?.secret ?? ""), + "X-Ovh-Consumer": (components["ovh-consumer-key"]?.secret ?? ""), + "X-Ovh-Timestamp": ts, + "X-Ovh-Signature": sig + }); r.status == 200 ? { + "result": "valid" + } : r.status in [400, 401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r))))) +''' +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' +components = [ + { id = "ovh-application-key", within = "20L" }, + { id = "ovh-consumer-key", within = "20L" }, +] + +# ────────────────────────────────────────────────────────────────────────────── +# ovh-consumer-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "ovh-consumer-key" +description = "OVHcloud Consumer Key - component of authenticated OVH API requests." +regex = '''(?i)(?:consumer[_.-]{0,1}key)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([A-Za-z0-9-]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["ovh"] +skipReport = true +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# paddle-live-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "paddle-live-api-key" +description = "Paddle live API key." +regex = '''\b(pdl_live_apikey_[a-z0-9]{26}_[A-Za-z0-9]{22}_[A-Za-z0-9]{3})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["pdl_live_apikey_"] +validate = ''' +let r = http.get("https://api.paddle.com/event-types", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status == 401 || (r.status == 403 + && (r.json?.error?.code ?? "") in ["authentication_malformed", "authentication_invalid"]) ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# perplexity-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "perplexity-api-key" +description = "Detected a Perplexity API key, which could lead to unauthorized access to Perplexity AI services and data exposure." +regex = '''\b(pplx-[a-zA-Z0-9]{48})(?:[\x60'"\s;]|\\[nr]|$|\b)''' +confidence = "high" +keywords = ["pplx-"] +validate = ''' +let r = http.post("https://api.perplexity.ai/chat/completions", { + "Authorization": "Bearer " + finding["secret"], + "Content-Type": "application/json" + }, "{\"model\":\"invalid-model-for-validation\",\"messages\":[{\"role\":\"user\",\"content\":\".\"}]}"); r.status in [200, 400, 404, 422] ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 4.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# persona-production-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "persona-production-api-key" +description = "Persona production API key." +regex = '''\b(persona_production_[a-z0-9_-]{20,80})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["persona_production_"] +validate = ''' +let r = http.get("https://api.withpersona.com/api/v1/accounts?page[size]=1", { + "Authorization": "Bearer " + finding["secret"], + "Persona-Version": "2023-01-05", + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status == 403 && size(r.json?.errors ?? []) > 0 ? { + "result": "valid", + "reason": "Authenticated but access is restricted" + } : r.status == 401 ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# pinecone-api-key.1 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "pinecone-api-key.1" +description = "Pinecone API key version 1 (UUID format)." +regex = '''(?i:(?:pinecone(?:[_. -]*(?:api))?[_. -]*(?:secret|key|token))(?:[ \t\w.-]{0,20})[\s'"]{0,3})(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([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})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["pinecone"] +validate = ''' +let r = http.get("https://api.pinecone.io/indexes", { + "Api-Key": finding["secret"], + "X-Pinecone-Api-Version": "2025-10", + "Accept": "application/json" + }); r.status == 200 && (r.body contains "\"indexes\"") ? { + "result": "valid" + } : r.status == 403 ? { + "result": "valid", + "reason": "Authenticated but control-plane access is restricted" + } : r.status == 401 ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# pinecone-api-key.2 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "pinecone-api-key.2" +description = "Pinecone API key version 2 (pcsk format)." +regex = '''\b(pcsk_[A-Za-z0-9]{5,6}_[A-Za-z0-9]{63})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["pcsk_"] +validate = ''' +let r = http.get("https://api.pinecone.io/indexes", { + "Api-Key": finding["secret"], + "X-Pinecone-Api-Version": "2025-10", + "Accept": "application/json" + }); r.status == 200 && (r.body contains "\"indexes\"") ? { + "result": "valid" + } : r.status == 403 ? { + "result": "valid", + "reason": "Authenticated but control-plane access is restricted" + } : r.status == 401 ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# pinterest-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "pinterest-access-token" +description = "Pinterest access token." +regex = '''\b(pina_[A-Za-z0-9_-]{20,200})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["pina_"] +validate = ''' +let r = http.get("https://api.pinterest.com/v5/user_account", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 && (r.body contains "\"username\"") ? { + "result": "valid" + } : r.status == 403 ? { + "result": "valid", + "reason": "Authenticated but user-account access is restricted" + } : r.status == 401 && (r.json?.code ?? 0) == 2 ? { + "result": "invalid", + "reason": "Authentication failed" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# pkcs12-file +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "pkcs12-file" +description = "Found a PKCS #12 file, which commonly contain bundled private keys." +path = '''(?i)(?:^|\/)[^\/]+\.p(?:12|fx)$''' +confidence = "high" + +# ────────────────────────────────────────────────────────────────────────────── +# plaid-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "plaid-api-token" +description = "Discovered a Plaid API Token, potentially compromising financial data aggregation and banking services." +regex = '''(?i)(?:plaid)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(access-(?:sandbox|development|production)-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["plaid"] + +# ────────────────────────────────────────────────────────────────────────────── +# plaid-client-id +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "plaid-client-id" +description = "Uncovered a Plaid Client ID, which could lead to unauthorized financial service integrations and data breaches." +regex = '''(?i)(?:plaid)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{24})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["plaid"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# plaid-secret-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "plaid-secret-key" +description = "Detected a Plaid Secret key, risking unauthorized access to financial accounts and sensitive transaction data." +regex = '''(?i)(?:plaid)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{30})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["plaid"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# planetscale-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "planetscale-api-token" +description = "Identified a PlanetScale API token, potentially compromising database management and operations." +regex = '''\b(pscale_tkn_(?i)[\w=\.-]{32,64})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["pscale_tkn_"] +validate = ''' +let r = http.get("https://api.planetscale.com/v1/organizations", { + "Accept": "application/json", + "Authorization": (components["planetscale-id"]?.secret ?? "") + ":" + finding["secret"] + }); r.status == 200 && (r.json?.type ?? "") == "list" ? { + "result": "valid", + "organization": r.json?.data?.[0]?.name ?? "" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' +components = [ + { id = "planetscale-id" }, +] + +# ────────────────────────────────────────────────────────────────────────────── +# planetscale-id +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "planetscale-id" +description = "Found a PlanetScale service token ID." +regex = '''(?i)(?:pscale|planetscale)(?:.|[\n\r]){0,16}?(?:USER|ID|NAME)(?:.|[\n\r]){0,16}?([a-z0-9]{12})''' +confidence = "high" +keywords = [ + "pscale", + "planetscale", +] +skipReport = true +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# planetscale-oauth-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "planetscale-oauth-token" +description = "Found a PlanetScale OAuth token, posing a risk to database access control and sensitive data integrity." +regex = '''\b(pscale_oauth_[\w=\.-]{32,64})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["pscale_oauth_"] +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# planetscale-password +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "planetscale-password" +description = "Discovered a PlanetScale password, which could lead to unauthorized database operations and data breaches." +regex = '''(?i)\b(pscale_pw_(?i)[\w=\.-]{32,64})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["pscale_pw_"] +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# plivo-auth-id +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "plivo-auth-id" +description = "Plivo Auth ID, used as a component of the Plivo Auth Token composite rule." +regex = '''(?i)(?:plivo(?:[_. -]*(?:auth|account))?[_. -]*(?:id|sid))(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(MA[A-Z0-9]{18})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["plivo"] +skipReport = true +filter = ''' +filter.entropy(finding["secret"]) < 2.8 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# plivo-auth-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "plivo-auth-token" +description = "Plivo Auth Token." +regex = '''(?i:(?:plivo(?:[_. -]*(?:auth))?[_. -]*(?:secret|token|key))(?:[ \t\w.-]{0,20})[\s'"]{0,3})(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([A-Za-z0-9_-]{40})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["plivo"] +validate = ''' +let authID = (components["plivo-auth-id"]?.secret ?? ""); +let r = http.get("https://api.plivo.com/v1/Account/" + authID + "/", { + "Authorization": "Basic " + base64.encode(bytes(authID + ":" + finding["secret"])), + "Accept": "application/json" +}); r.status == 200 ? { + "result": "valid" +} : r.status == 403 ? { + "result": "valid", + "reason": "Authenticated but account access is restricted" +} : r.status == 401 ? { + "result": "invalid", + "reason": "Unauthorized" +} : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' +components = [ + { id = "plivo-auth-id" }, +] + +# ────────────────────────────────────────────────────────────────────────────── +# polar-oauth-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "polar-oauth-access-token" +description = "Polar OAuth access token." +regex = '''\b(polar_at_[A-Za-z0-9_-]{20,100})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["polar_at_"] +validate = ''' +let r = http.get("https://api.polar.sh/v1/oauth2/userinfo", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 && (r.body contains "\"sub\"") ? { + "result": "valid" + } : r.status == 403 ? { + "result": "valid", + "reason": "Authenticated but user-info access is restricted" + } : r.status == 401 && (r.json?.error ?? "") == "invalid_token" ? { + "result": "invalid", + "reason": "Invalid token" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# polar-organization-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "polar-organization-access-token" +description = "Polar organization access token." +regex = '''\b(polar_oat_[A-Za-z0-9_-]{20,100})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["polar_oat_"] +validate = ''' +let r = http.get("https://api.polar.sh/v1/organizations/", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 && (r.body contains "\"items\"") ? { + "result": "valid" + } : r.status == 403 ? { + "result": "valid", + "reason": "Authenticated but organization access is restricted" + } : r.status == 401 && (r.json?.error ?? "") == "invalid_token" ? { + "result": "invalid", + "reason": "Invalid token" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# polar-personal-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "polar-personal-access-token" +description = "Polar personal access token." +regex = '''\b(polar_pat_[A-Za-z0-9_-]{20,100})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["polar_pat_"] +validate = ''' +let r = http.get("https://api.polar.sh/v1/oauth2/userinfo", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 && (r.body contains "\"sub\"") ? { + "result": "valid" + } : r.status == 403 ? { + "result": "valid", + "reason": "Authenticated but user-info access is restricted" + } : r.status == 401 && (r.json?.error ?? "") == "invalid_token" ? { + "result": "invalid", + "reason": "Invalid token" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# polymarket-address +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "polymarket-address" +description = "Found a Polymarket wallet address, used as a component of authenticated Polymarket API requests." +regex = '''(?i:(?:poly.{0,20}address)(?:[ \t\w.-]{0,20})[\s'"]{0,3})(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(0x[a-fA-F0-9]{40})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["poly"] +skipReport = true + +# ────────────────────────────────────────────────────────────────────────────── +# polymarket-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "polymarket-api-key" +description = "Identified a Polymarket API key, potentially compromising access to the Polymarket trading platform." +regex = '''(?i:(?:poly.{0,20}key)(?:[ \t\w.-]{0,20})[\s'"]{0,3})(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["poly"] +validate = ''' +let ts = time.nowUnix(); (let sig = crypto.hmacSha256( + base64.decode((components["polymarket-api-secret"]?.secret ?? "")), + bytes(ts + "GET" + "/data/orders") + ); (let r = http.get("https://clob.polymarket.com/data/orders", { + "POLY_BUILDER_API_KEY": finding["secret"], + "POLY_BUILDER_PASSPHRASE": (components["polymarket-passphrase"]?.secret ?? ""), + "POLY_BUILDER_TIMESTAMP": ts, + "POLY_BUILDER_SIGNATURE": replace(replace(base64.encode(sig), "+", "-"), "/", "_") + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r))) +''' +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' +components = [ + { id = "polymarket-api-secret", within = "20L" }, + { id = "polymarket-passphrase", within = "20L" }, +] + +# ────────────────────────────────────────────────────────────────────────────── +# polymarket-api-secret +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "polymarket-api-secret" +description = "Discovered a Polymarket API secret, which could be used to sign authenticated requests to the Polymarket L2 API." +regex = '''(?i:(?:poly.{0,20}secret)(?:[ \t\w.-]{0,20})[\s'"]{0,3})(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-zA-Z0-9+/]{40,}={0,2})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["poly"] +skipReport = true +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# polymarket-passphrase +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "polymarket-passphrase" +description = "Found a Polymarket API passphrase, used as a component of authenticated Polymarket API requests." +regex = '''(?i:(?:poly.{0,20}passphrase)(?:[ \t\w.-]{0,20})[\s'"]{0,3})(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-zA-Z0-9_]{8,128})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["poly"] +skipReport = true + +# ────────────────────────────────────────────────────────────────────────────── +# polymarket-private-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "polymarket-private-key" +description = "Discovered a Polymarket private key, which could allow unauthorized trading and fund transfers." +regex = '''(?i:(?:poly.{0,20}private.{0,20}key)(?:[ \t\w.-]{0,20})[\s'"]{0,3})(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(0x[a-fA-F0-9]{64})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["poly"] +filter = ''' +entropy(finding["secret"]) <= 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# posthog-personal-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "posthog-personal-api-key" +description = "Detected a PostHog Personal API Key, which may expose administrative access to PostHog analytics projects." +regex = '''(?i)\b(phx_[a-zA-Z0-9_\-]{41,49})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["phx_"] +validate = ''' +let us = http.get("https://us.posthog.com/api/users/@me/", { + "Authorization": "Bearer " + finding["secret"] + }); us.status in [200, 403] ? { + "result": "valid", + "region": "us", + "email": (us.json?.email ?? ""), + "organization": (us.json?.organization?.name ?? "") + } : (let eu = http.get("https://eu.posthog.com/api/users/@me/", { + "Authorization": "Bearer " + finding["secret"] + }); eu.status in [200, 403] ? { + "result": "valid", + "region": "eu", + "email": (eu.json?.email ?? ""), + "organization": (eu.json?.organization?.name ?? "") + } : (us.status == 401 && eu.status == 401) ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(eu)) +''' +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# posthog-project-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "posthog-project-api-key" +description = "Detected a PostHog Project API Key, a public write-only token used to send events to a PostHog project." +regex = '''(?i)\b(phc_[a-zA-Z0-9_\-]{41,44})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["phc_"] +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# postman-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "postman-api-token" +description = "Uncovered a Postman API token, potentially compromising API testing and development workflows." +regex = '''\b(PMAK-(?i)[a-f0-9]{24}\-[a-f0-9]{34})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["pmak-"] +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# prefect-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "prefect-api-token" +description = "Detected a Prefect API token, risking unauthorized access to workflow management and automation services." +regex = '''\b(pnu_[a-zA-Z0-9]{36})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["pnu_"] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# private-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "private-key" +description = "Identified a Private Key, which may compromise cryptographic security and sensitive data encryption." +regex = '''(?i)-----BEGIN[ A-Z0-9_-]{0,100}PRIVATE KEY(?: BLOCK)?-----[\s\S-]{64,}?KEY(?: BLOCK)?-----''' +confidence = "high" +keywords = ["-----begin"] + +# ────────────────────────────────────────────────────────────────────────────── +# privateai-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "privateai-api-token" +description = "Identified a PrivateAI Token, posing a risk of unauthorized access to AI services and data manipulation." +regex = '''(?i:(?:private[_-]?ai)(?:[ \t\w.-]{0,20})[\s'"]{0,3})(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = [ + "privateai", + "private_ai", + "private-ai", +] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# proof-full-access-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "proof-full-access-api-key" +description = "Proof production full-access API key." +regex = '''\b(prf_(?:cli_)?[A-Za-z0-9_-]{20,80})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["prf_"] +validate = ''' +let r = http.post("https://api.proof.com/v1/transactions", { + "ApiKey": finding["secret"], + "Content-Type": "application/json", + "Accept": "application/json" + }, "{}"); r.status == 422 && (r.body contains "signer") ? { + "result": "valid" + } : r.status == 401 ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.matchesAny(finding["secret"], ["^prf_(?:cli_)?test_"]) +|| entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# pulumi-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "pulumi-api-token" +description = "Found a Pulumi API token, posing a risk to infrastructure as code services and cloud resource management." +regex = '''\b(pul-[a-f0-9]{40})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["pul-"] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# pypi-upload-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "pypi-upload-token" +description = "Discovered a PyPI upload token, potentially compromising Python package distribution and repository integrity." +regex = '''pypi-AgEIcHlwaS5vcmc[\w-]{50,1000}''' +confidence = "high" +keywords = ["pypi-ageichlwas5vcmc"] +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# rainforest-pay-production-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "rainforest-pay-production-api-key" +description = "Rainforest Pay production API key." +regex = '''(?i:(?:rainforest(?:[_. -]*pay)?(?:[_. -]*(?:api))?[_. -]*(?:secret|key|token))(?:[ \t\w.-]{0,20})[\s'"]{0,3})(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(apikey_[a-f0-9]{64})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["rainforest"] +validate = ''' +let r = http.get("https://api.rainforestpay.com/v1/merchants?limit=1", { + "Authorization": "Bearer " + finding["secret"], + "Rainforest-Api-Version": "2024-10-16", + "Accept": "application/json" + }); r.status == 200 && (r.json?.status ?? "") == "SUCCESS" ? { + "result": "valid" + } : r.status == 403 && (r.json?.status ?? "") == "ERROR" ? { + "result": "valid", + "reason": "Authenticated but merchant access is restricted" + } : r.status == 401 && (r.json?.status ?? "") == "ERROR" ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# ramp-client-id +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "ramp-client-id" +description = "Ramp client ID, used as a component of the Ramp client-secret composite rule." +regex = '''\b(ramp_id_[A-Za-z0-9]{40})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["ramp_id_"] +skipReport = true +filter = ''' +entropy(finding["secret"]) < 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# ramp-client-secret +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "ramp-client-secret" +description = "Ramp OAuth client secret." +regex = '''\b(ramp_sec_[A-Za-z0-9]{48})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["ramp_sec_"] +validate = ''' +let r = http.post("https://api.ramp.com/developer/v1/token", { + "Authorization": "Basic " + base64.encode(bytes((components["ramp-client-id"]?.secret ?? "") + ":" + finding["secret"])), + "Content-Type": "application/x-www-form-urlencoded", + "Accept": "application/json" + }, "grant_type=client_credentials&scope=betterleaks%3Avalidate"); r.status == 200 + && (r.json?.access_token ?? "") != "" ? { + "result": "valid" + } : r.status == 400 + && (r.json?.error ?? "") in ["invalid_scope", "unauthorized_client"] ? { + "result": "valid" + } : r.status == 401 && (r.json?.error_v2?.error_code ?? "") == "5001" ? { + "result": "invalid", + "reason": "Invalid client credentials" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' +components = [ + { id = "ramp-client-id" }, +] + +# ────────────────────────────────────────────────────────────────────────────── +# rapidapi-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "rapidapi-access-token" +description = "Uncovered a RapidAPI Access Token, which could lead to unauthorized access to various APIs and data services." +regex = '''(?i)(?:rapidapi)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9_-]{50})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["rapidapi"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# readme-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "readme-api-token" +description = "Detected a Readme API token, risking unauthorized documentation management and content exposure." +regex = '''\b(rdme_[a-z0-9]{70})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["rdme_"] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# redirect-pizza-api-token.1 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "redirect-pizza-api-token.1" +description = "redirect.pizza API token." +regex = '''\b(rpa_[A-Za-z0-9]{30})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["rpa_"] +validate = ''' +let r = http.get("https://redirect.pizza/api/v1/domains", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status == 401 && (r.json?.message ?? "") == "Unauthenticated." ? { + "result": "invalid", + "reason": "Unauthenticated" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# render-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "render-api-key" +description = "Detected a Render API key, which may expose hosted services and account resources to unauthorized access." +regex = '''\b(rnd_[A-Za-z0-9]{28})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["rnd_"] +validate = ''' +let r = http.get("https://api.render.com/v1/services?limit=1", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); +r.status == 200 && (true) ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) + +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# replicate-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "replicate-api-token" +description = "Detected a Replicate API Token, which may expose AI model hosting and inference services to unauthorized access." +regex = '''(?i)\b(r8_[A-Za-z0-9]{37})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["r8_"] +validate = ''' +let r = http.get("https://api.replicate.com/v1/account", { + "Authorization": "Bearer " + finding["secret"] + }); r.status == 200 && (r.body contains '"type"') && (r.body contains '"username"') && (r.body contains '"name"') ? { + "result": "valid", + "username": (r.json?.username ?? "") + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# rootly-api-key.1 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "rootly-api-key.1" +description = "Rootly API key." +regex = '''\b(rootly_[a-f0-9]{64})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["rootly_"] +validate = ''' +let r = http.get("https://api.rootly.com/v1/incidents", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status in [200, 404] ? { + "result": "valid" + } : r.status == 401 ? { + "result": "invalid", + "reason": "Invalid token" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# rubygems-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "rubygems-api-token" +description = "Identified a Rubygem API token, potentially compromising Ruby library distribution and package management." +regex = '''\b(rubygems_[a-f0-9]{48})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["rubygems_"] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# runpod-api-key.1 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "runpod-api-key.1" +description = "RunPod API key." +regex = '''\b(rpa_[A-Z0-9]{40}[A-Za-z0-9]{6})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["rpa_"] +validate = ''' +let r = http.post("https://api.runpod.io/graphql", { + "Authorization": "Bearer " + finding["secret"], + "Content-Type": "application/json", + "Accept": "application/json" + }, "{\"query\":\"{ myself { id } }\"}"); r.status == 200 + && (r.json?.data?.myself?.id ?? "") != "" ? { + "result": "valid" + } : r.status == 401 ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# salesforce-access-token.1 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "salesforce-access-token.1" +description = "Salesforce access token." +regex = '''\b(00[A-Za-z0-9]{13}![A-Za-z0-9._-]{80,260})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["salesforce.com"] +validate = ''' +let r = http.get("https://" + (components["salesforce-instance-url.1"]?.secret ?? "") + "/services/data/v67.0/limits", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 && (r.body contains "\"DailyApiRequests\"") ? { + "result": "valid" + } : r.status == 403 && (r.body contains "\"REQUEST_LIMIT_EXCEEDED\"") ? { + "result": "valid", + "reason": "Authenticated but the organization API request limit is exceeded" + } : r.status == 401 ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.3 +''' +components = [ + { id = "salesforce-instance-url.1", within = "30L" }, +] + +# ────────────────────────────────────────────────────────────────────────────── +# salesforce-instance-url.1 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "salesforce-instance-url.1" +description = "Salesforce instance host, used as a component of the Salesforce access-token rule." +regex = '''(?i)(?:^|[^a-z0-9.-])(?:https?://)?((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?){0,4}\.my\.salesforce\.com|[a-z]{2,8}[0-9]{1,4}\.salesforce\.com))(?:[^a-z0-9.-]|$)''' +confidence = "high" +keywords = ["salesforce.com"] +skipReport = true + +# ────────────────────────────────────────────────────────────────────────────── +# samsara-api-token.1 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "samsara-api-token.1" +description = "Samsara API token." +regex = '''\b(samsara_api_[A-Za-z0-9]{26,32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["samsara_api_"] +validate = ''' +let r = http.get("https://api.samsara.com/fleet/vehicles", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status == 403 ? { + "result": "valid", + "reason": "Authenticated but vehicle access is restricted" + } : r.status == 401 && (r.json?.message ?? "") == "invalid token" ? { + "result": "invalid", + "reason": "Invalid token" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# scaleway-secret-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "scaleway-secret-key" +description = "Identified a standalone Scaleway Secret Key. This can be used to authenticate API requests." +regex = '''(?i)(?:(?:scaleway|scw).{0,20}?(?:secret|token))(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = [ + "scaleway", + "scw", +] +validate = ''' +let r = http.get("https://api.scaleway.com/instance/v1/zones/fr-par-1/servers", { + "X-Auth-Token": secret, + "Accept": "application/json" + }); r.status in [200, 403] ? { + "result": "valid", + "permission_status": r.status == 200 ? "Active" : "Restricted but still valid (403)", + } : r.status == 401 ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' + +# ────────────────────────────────────────────────────────────────────────────── +# scalingo-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "scalingo-api-token" +description = "Found a Scalingo API token, posing a risk to cloud platform services and application deployment security." +regex = '''\b(tk-us-[\w-]{48})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["tk-us-"] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# scalr-api-access-token.1 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "scalr-api-access-token.1" +description = "Scalr API access token." +regex = '''(?i:(?:scalr(?:[_. -]*(?:api|access))?[_. -]*(?:secret|key|token))(?:[ \t\w.-]{0,20})[\s'"]{0,3})(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9\.eyJpc3MiOiJ1c2VyIiwianRpIjoiYXQt[A-Za-z0-9_-]{20,40}\.[A-Za-z0-9_-]{43})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["scalr"] +validate = ''' +let r = http.get("https://scalr.io/api/iacp/v3/accounts", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/vnd.api+json" + }); r.status == 200 && (r.body contains "\"data\"") ? { + "result": "valid" + } : r.status == 403 ? { + "result": "valid", + "reason": "Authenticated but account access is restricted" + } : r.status == 401 ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# segment-public-api-token.1 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "segment-public-api-token.1" +description = "Segment workspace bearer token for the Public API." +regex = '''\b(sgp_[A-Za-z0-9]{64})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["sgp_"] +validate = ''' +let r = http.get("https://api.segmentapis.com/", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status == 403 ? { + "result": "invalid", + "reason": "Not authorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.3 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# sendbird-access-id +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "sendbird-access-id" +description = "Discovered a Sendbird Access ID, which could compromise chat and messaging platform integrations." +regex = '''(?i)(?:sendbird)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["sendbird"] +filter = ''' +filter.entropy(finding["secret"]) < 3.3 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# sendbird-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "sendbird-access-token" +description = "Uncovered a Sendbird Access Token, potentially risking unauthorized access to communication services and user data." +regex = '''(?i)(?:sendbird)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-f0-9]{40})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["sendbird"] +filter = ''' +filter.entropy(finding["secret"]) < 3.3 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# sendgrid-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "sendgrid-api-token" +description = "Detected a SendGrid API token, posing a risk of unauthorized email service operations and data exposure." +regex = '''\b(SG\.(?i)[a-z0-9=_\-\.]{66})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["sg."] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# sendinblue-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "sendinblue-api-token" +description = "Identified a Brevo (formerly Sendinblue) API token, which may compromise email marketing services and subscriber data privacy." +regex = '''\b(xkeysib-[a-fA-F0-9]{64}-[a-zA-Z0-9]{16})\b''' +confidence = "high" +keywords = ["xkeysib-"] +validate = ''' +let r = http.get("https://api.brevo.com/v3/account", { + "api-key": finding["secret"], + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.2 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# sentry-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "sentry-access-token" +description = "Found a Sentry.io Access Token (old format), risking unauthorized access to error tracking services and sensitive application data." +regex = '''(?i)(?:sentry)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-f0-9]{64})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["sentry"] +filter = ''' +filter.entropy(finding["secret"]) < 3.0 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# sentry-org-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "sentry-org-token" +description = "Found a Sentry.io Organization Token, risking unauthorized access to error tracking services and sensitive application data." +regex = '''\bsntrys_eyJpYXQiO[a-zA-Z0-9+/]{10,200}(?:LCJyZWdpb25fdXJs|InJlZ2lvbl91cmwi|cmVnaW9uX3VybCI6)[a-zA-Z0-9+/]{10,200}={0,2}_[a-zA-Z0-9+/]{43}(?:[^a-zA-Z0-9+/]|\z)''' +confidence = "high" +keywords = ["sntrys_eyjpyxqio"] +filter = ''' +filter.entropy(finding["secret"]) < 4.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# sentry-user-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "sentry-user-token" +description = "Found a Sentry.io User Token, risking unauthorized access to error tracking services and sensitive application data." +regex = '''\b(sntryu_[a-f0-9]{64})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["sntryu_"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# settlemint-application-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "settlemint-application-access-token" +description = "Found a Settlemint Application Access Token." +regex = '''\b(sm_aat_[a-zA-Z0-9]{16})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["sm_aat"] +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# settlemint-personal-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "settlemint-personal-access-token" +description = "Found a Settlemint Personal Access Token." +regex = '''\b(sm_pat_[a-zA-Z0-9]{16})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["sm_pat"] +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# settlemint-service-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "settlemint-service-access-token" +description = "Found a Settlemint Service Access Token." +regex = '''\b(sm_sat_[a-zA-Z0-9]{16})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["sm_sat"] +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# shippo-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "shippo-api-token" +description = "Discovered a Shippo API token, potentially compromising shipping services and customer order data." +regex = '''\b(shippo_(?:live|test)_[a-fA-F0-9]{40})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["shippo_"] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# shopify-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "shopify-access-token" +description = "Uncovered a Shopify access token, which could lead to unauthorized e-commerce platform access and data breaches." +regex = '''shpat_[a-fA-F0-9]{32}''' +confidence = "high" +keywords = ["shpat_"] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# shopify-custom-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "shopify-custom-access-token" +description = "Detected a Shopify custom access token, potentially compromising custom app integrations and e-commerce data security." +regex = '''shpca_[a-fA-F0-9]{32}''' +confidence = "high" +keywords = ["shpca_"] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# shopify-private-app-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "shopify-private-app-access-token" +description = "Identified a Shopify private app access token, risking unauthorized access to private app data and store operations." +regex = '''shppa_[a-fA-F0-9]{32}''' +confidence = "high" +keywords = ["shppa_"] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# shopify-shared-secret +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "shopify-shared-secret" +description = "Found a Shopify shared secret, posing a risk to application authentication and e-commerce platform security." +regex = '''shpss_[a-fA-F0-9]{32}''' +confidence = "high" +keywords = ["shpss_"] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# sidekiq-secret +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "sidekiq-secret" +description = "Discovered a Sidekiq Secret, which could lead to compromised background job processing and application data breaches." +regex = '''(?i)(?:BUNDLE_ENTERPRISE__CONTRIBSYS__COM|BUNDLE_GEMS__CONTRIBSYS__COM)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-f0-9]{8}:[a-f0-9]{8})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = [ + "bundle_enterprise__contribsys__com", + "bundle_gems__contribsys__com", +] + +# ────────────────────────────────────────────────────────────────────────────── +# sidekiq-sensitive-url +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "sidekiq-sensitive-url" +description = "Uncovered a Sidekiq Sensitive URL, potentially exposing internal job queues and sensitive operation details." +regex = '''(?i)\bhttps?://([a-f0-9]{8}:[a-f0-9]{8})@(?:gems.contribsys.com|enterprise.contribsys.com)(?:[\/|\#|\?|:]|$)''' +confidence = "high" +keywords = [ + "gems.contribsys.com", + "enterprise.contribsys.com", +] + +# ────────────────────────────────────────────────────────────────────────────── +# slack-app-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "slack-app-token" +description = "Detected a Slack App-level token, risking unauthorized access to Slack applications and workspace data." +regex = '''(?i)xapp-\d-[A-Z0-9]+-\d+-[a-z0-9]+''' +confidence = "high" +keywords = ["xapp"] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# slack-bot-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "slack-bot-token" +description = "Identified a Slack Bot token, which may compromise bot integrations and communication channel security." +regex = '''xoxb-[0-9]{10,13}-[0-9]{10,13}[a-zA-Z0-9-]*''' +confidence = "high" +keywords = ["xoxb"] +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# slack-config-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "slack-config-access-token" +description = "Found a Slack Configuration access token, posing a risk to workspace configuration and sensitive data access." +regex = '''(?i)xoxe.xox[bp]-\d-[A-Z0-9]{163,166}''' +confidence = "high" +keywords = [ + "xoxe.xoxb-", + "xoxe.xoxp-", +] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# slack-config-refresh-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "slack-config-refresh-token" +description = "Discovered a Slack Configuration refresh token, potentially allowing prolonged unauthorized access to configuration settings." +regex = '''(?i)xoxe-\d-[A-Z0-9]{146}''' +confidence = "high" +keywords = ["xoxe-"] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# slack-legacy-bot-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "slack-legacy-bot-token" +description = "Uncovered a Slack Legacy bot token, which could lead to compromised legacy bot operations and data exposure." +regex = '''xoxb-[0-9]{8,14}-[a-zA-Z0-9]{18,26}''' +confidence = "high" +keywords = ["xoxb"] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# slack-legacy-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "slack-legacy-token" +description = "Detected a Slack Legacy token, risking unauthorized access to older Slack integrations and user data." +regex = '''xox[os]-\d+-\d+-\d+-[a-fA-F\d]+''' +confidence = "high" +keywords = [ + "xoxo", + "xoxs", +] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# slack-legacy-workspace-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "slack-legacy-workspace-token" +description = "Identified a Slack Legacy Workspace token, potentially compromising access to workspace data and legacy features." +regex = '''xox[ar]-(?:\d-)?[0-9a-zA-Z]{8,48}''' +confidence = "high" +keywords = [ + "xoxa", + "xoxr", +] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# slack-session-cookie +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "slack-session-cookie" +description = "Detected a Slack session cookie (xoxd-), which authenticates browser and desktop sessions across all of a user's workspaces." +regex = '''(xoxd-[\w\/\\+-]{100,}={0,2})(?:[^\w\/+=-]|\z)''' +confidence = "high" +keywords = ["xoxd-"] +filter = ''' +entropy(finding["secret"]) <= 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# slack-session-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "slack-session-token" +description = "Detected a Slack client session token (xoxc-), which provides full user-level API access when paired with a session cookie." +regex = '''xoxc-\d{9,15}-\d{9,15}-\d{9,15}-[a-f0-9]{64}\b''' +confidence = "high" +keywords = ["xoxc-"] +filter = ''' +entropy(finding["secret"]) <= 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# slack-user-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "slack-user-token" +description = "Found a Slack User token, posing a risk of unauthorized user impersonation and data access within Slack workspaces." +regex = '''xox[pe](?:-[0-9]{10,13}){3}-[a-zA-Z0-9-]{28,34}''' +confidence = "high" +keywords = [ + "xoxp-", + "xoxe-", +] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# slack-webhook-url +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "slack-webhook-url" +description = "Discovered a Slack Webhook, which could lead to unauthorized message posting and data leakage in Slack channels." +regex = '''(?:https?://)?hooks.slack.com/(?:services|workflows|triggers)/[A-Za-z0-9+/]{43,56}''' +confidence = "high" +keywords = ["hooks.slack.com"] + +# ────────────────────────────────────────────────────────────────────────────── +# snowflake-account-host.1 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "snowflake-account-host.1" +description = "Snowflake account host, used as a component of the programmatic access-token rule." +regex = '''(?i)\b([a-z0-9_-]+(?:\.[a-z0-9_-]+)*\.snowflakecomputing\.com)\b''' +confidence = "high" +keywords = ["snowflakecomputing.com"] +skipReport = true + +# ────────────────────────────────────────────────────────────────────────────── +# snowflake-programmatic-access-token.1 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "snowflake-programmatic-access-token.1" +description = "Snowflake programmatic access token." +regex = '''(?i:(?:(?:snowflake[_. -]*(?:programmatic[_. -]*)?(?:access[_. -]*)?token|sf[_. -]*token))(?:[ \t\w.-]{0,20})[\s'"]{0,3})(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([A-Za-z0-9_-]{100,500})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = [ + "snowflake", + "sf_token", +] +validate = ''' +let r = http.post("https://" + (components["snowflake-account-host.1"]?.secret ?? "") + "/api/v2/statements", { + "Authorization": "Bearer " + finding["secret"], + "X-Snowflake-Authorization-Token-Type": "PROGRAMMATIC_ACCESS_TOKEN", + "Content-Type": "application/json", + "Accept": "application/json" + }, "{\"statement\":\"select 1\",\"timeout\":5}"); r.status in [200, 202] + && ((r.body contains "\"statementHandle\"") || (r.body contains "\"resultSetMetaData\"")) ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' +components = [ + { id = "snowflake-account-host.1", within = "30L" }, +] + +# ────────────────────────────────────────────────────────────────────────────── +# snyk-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "snyk-api-token" +description = "Uncovered a Snyk API token, potentially compromising software vulnerability scanning and code security." +regex = '''(?i)(?:snyk[_.-]?(?:(?:api|oauth)[_.-]?)?(?:key|token))(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["snyk"] + +# ────────────────────────────────────────────────────────────────────────────── +# sonar-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "sonar-api-token" +description = "Uncovered a Sonar API token, potentially compromising software vulnerability scanning and code security." +regex = '''(?i)(?:sonar[_.-]?(login|token))(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}((?:squ_|sqp_|sqa_)?[a-z0-9=_\-]{40})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +secretGroup = 2 +confidence = "high" +keywords = ["sonar"] + +# ────────────────────────────────────────────────────────────────────────────── +# sourcegraph-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "sourcegraph-access-token" +description = "Sourcegraph is a code search and navigation engine." +regex = '''(?i)\b(sgp_(?:[a-fA-F0-9]{16}|local)_[a-fA-F0-9]{40}|sgp_[a-fA-F0-9]{40})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["sgp_"] +validate = ''' +let r = http.post("https://sourcegraph.com/.api/graphql", { + "Authorization": "token " + finding["secret"], + "Content-Type": "application/json" + }, "{\"query\":\"query ValidateToken { site { id } }\"}"); r.status == 200 && (r.json?.data?.site?.id ?? "") != "" ? { + "result": "valid", + "site_id": (r.json?.data?.site?.id ?? "") + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# square-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "square-access-token" +description = "Detected a Square Access Token, risking unauthorized payment processing and financial transaction exposure." +regex = '''\b((?:EAAA|sq0atp-)[\w-]{22,60})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = [ + "sq0atp-", + "eaaa", +] +filter = ''' +entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# squarespace-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "squarespace-access-token" +description = "Identified a Squarespace Access Token, which may compromise website management and content control on Squarespace." +regex = '''(?i)(?:squarespace)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["squarespace"] + +# ────────────────────────────────────────────────────────────────────────────── +# sslmate-api-key.1 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "sslmate-api-key.1" +description = "SSLMate API key." +regex = '''(?i:(?:sslmate(?:[_. -]*(?:api))?[_. -]*(?:secret|key|token))(?:[ \t\w.-]{0,20})[\s'"]{0,3})(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([A-Za-z0-9]{36})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["sslmate"] +validate = ''' +let r = http.get("https://sslmate.com/api/v2/certs/example.com", { + "Authorization": "Basic " + base64.encode(bytes(finding["secret"] + ":")), + "Accept": "application/json" + }); r.status == 200 && (r.body contains "\"cn\"") + && (r.body contains "\"exists\"") ? { + "result": "valid" + } : r.status == 401 && (r.json?.reason ?? "") == "bad_credentials" ? { + "result": "invalid", + "reason": "Bad credentials" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# stability-ai-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "stability-ai-api-key" +description = "Detected a Stability AI API Key, which may expose AI image generation services to unauthorized access." +regex = '''(?i)(?:stability)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(sk-[A-Za-z0-9]{48})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["stability"] +filter = ''' +entropy(finding["secret"]) <= 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# stripe-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "stripe-access-token" +description = "Found a Stripe Access Token, posing a risk to payment processing services and sensitive financial data." +regex = '''\b((?:sk|rk)_(?:test|live|prod)_[a-zA-Z0-9]{10,99})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = [ + "sk_test", + "sk_live", + "sk_prod", + "rk_test", + "rk_live", + "rk_prod", +] +validate = ''' +let r = http.get("https://api.stripe.com/v1/account", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 && (r.json?.object ?? "") == "account" ? { + "result": "valid" + } : r.status == 401 ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.matchesAny(finding["secret"], ["^sk_live_a2V5Xz"]) +|| entropy(finding["secret"]) <= 2.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# sumologic-access-id +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "sumologic-access-id" +description = "Discovered a SumoLogic Access ID, potentially compromising log management services and data analytics integrity." +regex = '''(?i:(?:(?-i:[Ss]umo|SUMO))(?:[ \t\w.-]{0,20})[\s'"]{0,3})(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(su[a-zA-Z0-9]{12})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["sumo"] +filter = ''' +filter.entropy(finding["secret"]) < 3.0 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# sumologic-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "sumologic-access-token" +description = "Uncovered a SumoLogic Access Token, which could lead to unauthorized access to log data and analytics insights." +regex = '''(?i)(?:(?-i:[Ss]umo|SUMO))(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{64})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["sumo"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# supabase-management-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "supabase-management-token" +description = "Detected a Supabase Management Token, which may allow unauthorized access to Supabase organizations and projects." +regex = '''\b(sbp_[a-z0-9_-]{40})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["sbp_"] +validate = ''' +let r = http.get("https://api.supabase.com/v1/organizations", { + "Authorization": "Bearer " + finding["secret"] + }); r.status == 200 ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 3.5 +|| !matchesAny(finding["secret"], [`^sbp_[a-z0-9_-]*[0-9][a-z0-9_-]*[0-9][a-z0-9_-]*$`]) +''' + +# ────────────────────────────────────────────────────────────────────────────── +# supabase-project-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "supabase-project-api-key" +description = "Detected a Supabase Project API Key, which may expose project data through Supabase APIs when paired with a project URL." +regex = '''\b(sb_secret_[A-Za-z0-9_-]{31})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["sb_secret_"] +validate = ''' +let r = http.get((components["supabase-project-url"]?.secret ?? "") + "/rest/v1/?select=*", { + "Apikey": finding["secret"], + "User-Agent": "" + }); r.status == 200 && (r.body contains "\"host\":") ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 4.0 +''' +components = [ + { id = "supabase-project-url" }, +] + +# ────────────────────────────────────────────────────────────────────────────── +# supabase-project-url +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "supabase-project-url" +description = "Detected a Supabase project URL, used as a component of the supabase-project-api-key composite rule." +regex = '''\b(https://[a-z0-9]{16,32}\.supabase\.co)\b''' +confidence = "high" +keywords = ["supabase.co"] +skipReport = true +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# tableau-personal-access-token-name.1 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "tableau-personal-access-token-name.1" +description = "Tableau personal access-token name, used as a component of the token rule." +regex = '''(?i:(?:tableau(?:[_. -]*(?:personal[_. -]*access|pat))?[_. -]*(?:token[_. -]*)?name)(?:[ \t\w.-]{0,20})[\s'"]{0,3})(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([A-Za-z][A-Za-z0-9_-]{2,50})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["tableau"] +skipReport = true + +# ────────────────────────────────────────────────────────────────────────────── +# tableau-personal-access-token.1 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "tableau-personal-access-token.1" +description = "Tableau personal access token." +regex = '''\b([A-Za-z0-9+/]{22}==:[A-Za-z0-9]{32})\b''' +confidence = "high" +keywords = ["tableau"] +validate = ''' +let r = http.post("https://" + (components["tableau-server-host.1"]?.secret ?? "") + "/api/3.26/auth/signin", { + "Content-Type": "application/json", + "Accept": "application/json" + }, "{\"credentials\":{\"personalAccessTokenName\":\"" + (components["tableau-personal-access-token-name.1"]?.secret ?? "") + + "\",\"personalAccessTokenSecret\":\"" + finding["secret"] + "\",\"site\":{}}}"); + r.status == 200 && (r.json?.credentials?.token ?? "") != "" ? { + "result": "valid" + } : r.status in [400, 401, 403] ? { + "result": "invalid", + "reason": "Invalid Tableau credentials" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' +components = [ + { id = "tableau-personal-access-token-name.1", within = "20L" }, + { id = "tableau-server-host.1", within = "20L" }, +] + +# ────────────────────────────────────────────────────────────────────────────── +# tableau-server-host.1 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "tableau-server-host.1" +description = "Tableau Online server host, used as a component of the personal access-token rule." +regex = '''(?i)\b([a-z0-9-]+\.online\.tableau\.com)\b''' +confidence = "high" +keywords = ["online.tableau.com"] +skipReport = true + +# ────────────────────────────────────────────────────────────────────────────── +# tailscale-api-key.1 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "tailscale-api-key.1" +description = "Tailscale API access token." +regex = '''\b(tskey-api-[A-Za-z0-9_-]{20,36})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["tskey-api-"] +validate = ''' +let r = http.post("https://api.tailscale.com/api/v2/secret-scanning/verify", { + "Content-Type": "application/x-www-form-urlencoded", + "Accept": "application/json" + }, "key=" + finding["secret"]); r.status == 204 ? { + "result": "valid" + } : r.status == 401 ? { + "result": "invalid", + "reason": "Invalid API token" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# telegram-bot-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "telegram-bot-api-token" +description = "Detected a Telegram Bot API Token, risking unauthorized bot operations and message interception on Telegram." +regex = '''(?i)(?:telegr)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([0-9]{5,16}:(?-i:A)[a-z0-9_\-]{34})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["telegr"] + +# ────────────────────────────────────────────────────────────────────────────── +# telnyx-api-v2-key.1 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "telnyx-api-v2-key.1" +description = "Telnyx API v2 key." +regex = '''(?i:(?:telnyx(?:[_. -]*(?:api))?[_. -]*(?:secret|key|token))(?:[ \t\w.-]{0,20})[\s'"]{0,3})(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(KEY[0-9A-Za-z_-]{55})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["telnyx"] +validate = ''' +let r = http.get("https://api.telnyx.com/v2/balance", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 && (r.body contains "\"balance\"") ? { + "result": "valid" + } : r.status == 403 ? { + "result": "valid", + "reason": "Authenticated but balance access is restricted" + } : r.status == 401 ? { + "result": "invalid", + "reason": "Authentication failed" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# temporal-cloud-api-key.1 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "temporal-cloud-api-key.1" +description = "Temporal Cloud API key." +regex = '''\b(eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]*Y2NvdW50X2lk[A-Za-z0-9_-]*InRlbXBvcmFsLmlv[A-Za-z0-9_-]*(?:ICJrZXlfaWQiOi|a2V5X2lk|rZXlfaWQi)[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["inrlbxbvcmfslmlv"] +validate = ''' +let r = http.get("https://saas-api.tmprl.cloud/cloud/current-identity", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 && ((r.body contains "\"user\"") || (r.body contains "\"serviceAccount\"")) ? { + "result": "valid" + } : r.status == 401 ? { + "result": "invalid", + "reason": "Request not authenticated" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.2 +|| !filter.matchesAny(finding["secret"], ["^(?:[^0-9]*[0-9]){3}"]) +''' + +# ────────────────────────────────────────────────────────────────────────────── +# thunderstore-api-token.1 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "thunderstore-api-token.1" +description = "Thunderstore API token." +regex = '''\b(tss_[A-Za-z0-9_-]{20,80})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["tss_"] +validate = ''' +let r = http.get("https://thunderstore.io/api/experimental/current-user/", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 && (r.body contains "\"username\"") ? { + "result": "valid" + } : r.status == 401 ? { + "result": "invalid", + "reason": "Invalid Service Account token" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 +|| !filter.matchesAny(finding["secret"], ["^(?:[^0-9]*[0-9]){2}"]) +''' + +# ────────────────────────────────────────────────────────────────────────────── +# togetherai-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "togetherai-api-key" +description = "Detected a Together.ai API Key, which may expose access to open-source AI models and inference services." +regex = '''(?i)\b(tgp_v1_[A-Za-z0-9_-]{43})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["tgp_v1_"] +validate = ''' +let r = http.get("https://api.together.xyz/v1/models", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 && (r.body contains '"id"') && (r.body contains '"object"') ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# travisci-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "travisci-access-token" +description = "Identified a Travis CI Access Token, potentially compromising continuous integration services and codebase security." +regex = '''(?i)(?:travis)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{22})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["travis"] +filter = ''' +filter.entropy(finding["secret"]) < 3.0 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# twilio-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "twilio-api-key" +description = "Found a Twilio API Key, posing a risk to communication services and sensitive customer interaction data." +regex = '''SK[0-9a-fA-F]{32}''' +confidence = "high" +keywords = ["twilio"] +filter = ''' +entropy(finding["secret"]) <= 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# twitch-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "twitch-api-token" +description = "Discovered a Twitch API token, which could compromise streaming services and account integrations." +regex = '''(?i)(?:twitch)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{30})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["twitch"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# twitter-access-secret +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "twitter-access-secret" +description = "Uncovered a Twitter Access Secret, potentially risking unauthorized Twitter integrations and data breaches." +regex = '''(?i)(?:twitter)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{45})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["twitter"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# twitter-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "twitter-access-token" +description = "Detected a Twitter Access Token, posing a risk of unauthorized account operations and social media data exposure." +regex = '''(?i)(?:twitter)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([0-9]{15,25}-[a-zA-Z0-9]{20,40})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["twitter"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# twitter-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "twitter-api-key" +description = "Identified a Twitter API Key, which may compromise Twitter application integrations and user data security." +regex = '''(?i)(?:twitter)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{25})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["twitter"] +filter = ''' +filter.entropy(finding["secret"]) < 3.0 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# twitter-api-secret +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "twitter-api-secret" +description = "Found a Twitter API Secret, risking the security of Twitter app integrations and sensitive data access." +regex = '''(?i)(?:twitter)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{50})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["twitter"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# twitter-bearer-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "twitter-bearer-token" +description = "Discovered a Twitter Bearer Token, potentially compromising API access and data retrieval from Twitter." +regex = '''(?i)(?:twitter)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(A{22}[a-zA-Z0-9%]{80,100})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["twitter"] +filter = ''' +filter.entropy(finding["secret"]) < 3.0 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# typeform-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "typeform-api-token" +description = "Uncovered a Typeform API token, which could lead to unauthorized survey management and data collection." +regex = '''(?i)(?:typeform)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(tfp_[a-z0-9\-_\.=]{59})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["tfp_"] + +# ────────────────────────────────────────────────────────────────────────────── +# unkey-root-key.1 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "unkey-root-key.1" +description = "Unkey administrative root key." +regex = '''\b(unkey_[A-Za-z0-9]{20,32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["unkey_"] +validate = ''' +let r = http.post("https://api.unkey.com/v2/keys.verifyKey", { + "Authorization": "Bearer " + finding["secret"], + "Content-Type": "application/json", + "Accept": "application/json" + }, "{\"key\":\"betterleaks_validation_key\"}"); r.status == 200 && (r.body contains "\"data\"") ? { + "result": "valid" + } : r.status == 401 ? { + "result": "invalid", + "reason": "Invalid root key" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 +|| !filter.matchesAny(finding["secret"], ["[0-9]"]) +|| !filter.matchesAny(finding["secret"], ["[A-Z]"]) +|| !filter.matchesAny(finding["secret"], ["[a-z]"]) +''' + +# ────────────────────────────────────────────────────────────────────────────── +# upcloud-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "upcloud-api-token" +description = "Identified an UpCloud API token, which may expose cloud infrastructure resources to unauthorized access." +regex = '''\b(ucat_[0-9A-Za-z]{24,32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["ucat_"] +validate = ''' +let r = http.get("https://api.upcloud.com/1.3/account", { + "Authorization": "Bearer " + finding["secret"] + }); r.status == 200 && (r.body contains '"account"') ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' + +# ────────────────────────────────────────────────────────────────────────────── +# upstage-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "upstage-api-key" +description = "Detected an Upstage AI API key, which may expose Solar language models and document AI services to unauthorized access." +regex = '''(?i)(?:upstage)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([A-Za-z0-9]{40,50})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["upstage"] +validate = ''' +let r = http.get("https://api.upstage.ai/v1/models", { + "Authorization": "Bearer " + finding["secret"] + }); r.status == 200 && (r.body contains '"data"') ? { + "result": "valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# val-town-api-token.1 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "val-town-api-token.1" +description = "Val Town API token." +regex = '''\b(vtwn_[A-Za-z0-9_-]{20,80})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["vtwn_"] +validate = ''' +let r = http.get("https://api.val.town/v1/me", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 && (r.body contains "\"id\"") ? { + "result": "valid" + } : r.status == 401 ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 +|| !filter.matchesAny(finding["secret"], ["^(?:[^0-9]*[0-9]){2}"]) +''' + +# ────────────────────────────────────────────────────────────────────────────── +# vault-batch-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "vault-batch-token" +description = "Detected a Vault Batch Token, risking unauthorized access to secret management services and sensitive data." +regex = '''\b(hvb\.[\w-]{138,300})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["hvb."] +filter = ''' +entropy(finding["secret"]) <= 4.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# vault-service-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "vault-service-token" +description = "Identified a Vault Service Token, potentially compromising infrastructure security and access to sensitive credentials." +regex = '''\b((?:hvs\.[\w-]{90,120}|s\.(?i:[a-z0-9]{24})))(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = [ + "hvs.", + "vault", +] +filter = ''' +entropy(finding["secret"]) <= 3.5 +|| matchesAny(finding["secret"], [`s\.[A-Za-z]{24}`]) +''' + +# ────────────────────────────────────────────────────────────────────────────── +# vercel-ai-gateway-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "vercel-ai-gateway-key" +description = "Detected a Vercel AI Gateway API Key (vck_), which may expose AI model routing and gateway access to unauthorized parties." +regex = '''(?i)\b(vck_[A-Za-z0-9_-]{56})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["vck_"] +validate = ''' +let r = http.post("https://ai-gateway.vercel.sh/v1/chat/completions", { + "Authorization": "Bearer " + finding["secret"], + "Content-Type": "application/json" + }, "{\"model\":\"openai/gpt-3.5-turbo\",\"messages\":[{\"role\":\"user\",\"content\":\"x\"}],\"max_tokens\":1}"); r.status in [200, 403] ? { + "result": "valid" + } : r.status in [401] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# vercel-api-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "vercel-api-token" +description = "Detected a Vercel API Token, which may expose deployment and serverless infrastructure to unauthorized access." +regex = '''(?i)(?:vercel)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([A-Z0-9]{24})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["vercel"] +validate = ''' +let r = http.get("https://api.vercel.com/v2/user", { + "Authorization": "Bearer " + finding["secret"] + }); r.status == 200 && (r.body contains "\"user\"") && (r.body contains "\"email\"") ? { + "result": "valid", + "email": (r.json?.user?.email ?? ""), + "username": (r.json?.user?.username ?? ""), + "user_id": (r.json?.user?.id ?? "") + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# vercel-app-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "vercel-app-access-token" +description = "Detected a Vercel App Access Token (vca_), which may allow Sign in with Vercel apps to access user resources." +regex = '''(?i)\b(vca_[A-Za-z0-9_-]{56})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["vca_"] +validate = ''' +let r = http.post("https://api.vercel.com/login/oauth/userinfo", { + "Authorization": "Bearer " + finding["secret"] + }, ""); r.status == 200 && (r.body contains "\"sub\"") ? { + "result": "valid", + "email": (r.json?.email ?? ""), + "user_id": (r.json?.sub ?? "") + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# vercel-app-refresh-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "vercel-app-refresh-token" +description = "Detected a Vercel App Refresh Token (vcr_), which may allow persistent unauthorized access through token refresh flows." +regex = '''(?i)\b(vcr_[A-Za-z0-9_-]{56})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["vcr_"] +validate = ''' +let r = http.post("https://api.vercel.com/login/oauth/token/introspect", { + "Content-Type": "application/x-www-form-urlencoded" + }, "token=" + finding["secret"]); r.status == 200 && (r.body contains "\"active\":true") ? { + "result": "valid" + } : r.status == 200 && (r.body contains "\"active\":false") ? { + "result": "invalid", + "reason": "Token inactive" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# vercel-integration-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "vercel-integration-token" +description = "Detected a Vercel Integration Token (vci_), which may allow third-party service integrations to act on behalf of users." +regex = '''(?i)\b(vci_[A-Za-z0-9_-]{56})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["vci_"] +validate = ''' +let r = http.get("https://api.vercel.com/v2/user", { + "Authorization": "Bearer " + finding["secret"] + }); r.status == 200 && (r.body contains "\"user\"") ? { + "result": "valid", + "email": (r.json?.user?.email ?? ""), + "username": (r.json?.user?.username ?? ""), + "user_id": (r.json?.user?.id ?? "") + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# vercel-personal-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "vercel-personal-access-token" +description = "Detected a Vercel Personal Access Token (vcp_), which may expose full account and deployment management capabilities." +regex = '''(?i)\b(vcp_[A-Za-z0-9_-]{56})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["vcp_"] +validate = ''' +let r = http.get("https://api.vercel.com/v2/user", { + "Authorization": "Bearer " + finding["secret"] + }); r.status == 200 && (r.body contains "\"user\"") && (r.body contains "\"email\"") ? { + "result": "valid", + "email": (r.json?.user?.email ?? ""), + "username": (r.json?.user?.username ?? ""), + "user_id": (r.json?.user?.id ?? "") + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# wakatime-api-key.1 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "wakatime-api-key.1" +description = "WakaTime API key version 1 (UUID format)." +regex = '''(?i:(?:waka[_. -]?time(?:[_. -]*(?:api))?[_. -]*(?:secret|key|token))(?:[ \t\w.-]{0,20})[\s'"]{0,3})(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([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})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = [ + "wakatime", + "waka_time", + "waka-time", + "waka time", + "waka.time", +] +validate = ''' +let r = http.get("https://api.wakatime.com/api/v1/users/current?api_key=" + finding["secret"], { + "Accept": "application/json" + }); r.status == 200 && (r.body contains "\"data\"") ? { + "result": "valid" + } : r.status == 401 ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# wakatime-api-key.2 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "wakatime-api-key.2" +description = "WakaTime API key version 2 (waka_ format)." +regex = '''(?i)\b(waka_[a-z0-9]{36,64})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["waka_"] +validate = ''' +let r = http.get("https://api.wakatime.com/api/v1/users/current?api_key=" + finding["secret"], { + "Accept": "application/json" + }); r.status == 200 && (r.body contains "\"data\"") ? { + "result": "valid" + } : r.status == 401 ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# weatherstack-api-key.1 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "weatherstack-api-key.1" +description = "Weatherstack API key." +regex = '''(?i:(?:weatherstack(?:[_. -]*(?:api))?[_. -]*(?:secret|key|token))(?:[ \t\w.-]{0,20})[\s'"]{0,3})(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([0-9a-z]{32})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = ["weatherstack"] +validate = ''' +let r = http.get("https://api.weatherstack.com/current?access_key=" + finding["secret"] + "&query=Los%20Angeles", { + "Accept": "application/json" + }); r.status == 200 && ((r.body contains "\"location\"") || (r.body contains "Access Restricted - Your current Subscription Plan does not support HTTPS Encryption")) ? { + "result": "valid" + } : r.status == 401 && (r.body contains "\"invalid_access_key\"") ? { + "result": "invalid", + "reason": "Invalid access key" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.3 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# weights-and-biases-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "weights-and-biases-api-key" +description = "Detected a Weights & Biases API Key, which may expose ML experiment tracking and model registry access to unauthorized parties." +regex = '''(?i)(?:wandb|weightsandbiases)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-f0-9]{40})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = [ + "wandb", + "weightsandbiases", +] +validate = ''' +let r = http.post("https://api.wandb.ai/graphql", { + "Authorization": "Basic " + base64.encode(bytes("api:" + finding["secret"])), + "Content-Type": "application/json" + }, "{\"query\":\"query { viewer { email username } }\"}"); r.status == 200 && (r.body contains "\"username\"") ? { + "result": "valid", + "email": (r.json?.data?.viewer?.email ?? ""), + "username": (r.json?.data?.viewer?.username ?? "") + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# weights-and-biases-api-key-v1 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "weights-and-biases-api-key-v1" +description = "Detected a Weights & Biases v1 API Key (wandb_v1_), which may expose ML experiment tracking and artifact storage to unauthorized access." +regex = '''(?i)\b(wandb_v1_[A-Za-z0-9_]{77})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["wandb_v1_"] +validate = ''' +let r = http.post("https://api.wandb.ai/graphql", { + "Authorization": "Basic " + base64.encode(bytes("api:" + finding["secret"])), + "Content-Type": "application/json" + }, "{\"query\":\"query { viewer { email username } }\"}"); r.status == 200 && (r.body contains "\"username\"") ? { + "result": "valid", + "email": (r.json?.data?.viewer?.email ?? ""), + "username": (r.json?.data?.viewer?.username ?? "") + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# workato-developer-api-token.1 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "workato-developer-api-token.1" +description = "Workato Developer API token." +regex = '''\b(wrka(?:[a-z]{2})?-eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{64,})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["wrka"] +validate = ''' +let token = finding["secret"]; +let host = filter.matchesAny(token, ["^wrkaeu-"]) ? "https://app.eu.workato.com" : + filter.matchesAny(token, ["^wrkajp-"]) ? "https://app.jp.workato.com" : + filter.matchesAny(token, ["^wrkasg-"]) ? "https://app.sg.workato.com" : + filter.matchesAny(token, ["^wrkaau-"]) ? "https://app.au.workato.com" : + filter.matchesAny(token, ["^wrkail-"]) ? "https://app.il.workato.com" : + filter.matchesAny(token, ["^wrkacn-"]) ? "https://app.workatoapp.cn" : + filter.matchesAny(token, ["^wrkakr-"]) ? "https://app.kr.workato.com" : + "https://www.workato.com"; +let r = http.get(host + "/api/users/me", { + "Authorization": "Bearer " + token, + "Accept": "application/json" + }); r.status == 200 && (r.body contains "\"id\"") ? { + "result": "valid" + } : r.status == 403 ? { + "result": "valid", + "reason": "Authenticated but workspace-details access is restricted" + } : r.status == 401 ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 4.0 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# workos-production-api-key.1 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "workos-production-api-key.1" +description = "WorkOS production API key." +regex = '''(?i:(?:workos(?:[_. -]*(?:api))?[_. -]*(?:secret|key|token))(?:[ \t\w.-]{0,20})[\s'"]{0,3})(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(sk_live_a2V5Xz[A-Za-z0-9+/]{69}={0,2})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["workos"] +validate = ''' +let r = http.get("https://api.workos.com/organizations", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json" + }); r.status == 200 && (r.body contains "\"data\"") ? { + "result": "valid" + } : r.status == 403 ? { + "result": "valid", + "reason": "Authenticated but organization access is restricted" + } : r.status == 401 ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +filter.entropy(finding["secret"]) < 3.5 +|| filter.matchesAny(finding["secret"], ["(?i)example"]) +''' + +# ────────────────────────────────────────────────────────────────────────────── +# xai-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "xai-api-key" +description = "Detected an xAI (Grok) API Key, which may expose Grok AI model access to unauthorized parties." +regex = '''(?i)\b(xai-[A-Za-z0-9_-]{70,120})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["xai-"] +filter = ''' +entropy(finding["secret"]) <= 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# yandex-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "yandex-access-token" +description = "Found a Yandex Access Token, posing a risk to Yandex service integrations and user data privacy." +regex = '''(?i)(?:yandex)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(t1\.[A-Z0-9a-z_-]+[=]{0,2}\.[A-Z0-9a-z_-]{86}[=]{0,2})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["yandex"] + +# ────────────────────────────────────────────────────────────────────────────── +# yandex-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "yandex-api-key" +description = "Discovered a Yandex API Key, which could lead to unauthorized access to Yandex services and data manipulation." +regex = '''(?i)(?:yandex)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(AQVN[A-Za-z0-9_\-]{35,38})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["yandex"] + +# ────────────────────────────────────────────────────────────────────────────── +# yandex-aws-access-token +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "yandex-aws-access-token" +description = "Uncovered a Yandex AWS Access Token, potentially compromising cloud resource access and data security on Yandex Cloud." +regex = '''(?i)(?:yandex)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}(YC[a-zA-Z0-9_\-]{38})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["yandex"] + +# ────────────────────────────────────────────────────────────────────────────── +# zai-api-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "zai-api-key" +description = "Detected a Z.ai API key, which may expose GLM model access and usage to unauthorized parties." +regex = '''(?i)(?:zai|z_ai|z\.ai|glm|zlm)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-f0-9]{32}\.[a-z0-9]{16})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "medium" +keywords = [ + "zai", + "z_ai", + "z.ai", + "glm", + "zlm", +] +validate = ''' +let r = http.post("https://api.z.ai/api/paas/v4/tokenizer", { + "Authorization": "Bearer " + finding["secret"], + "Accept": "application/json", + "Content-Type": "application/json" + }, + "{" + + "\"model\":\"glm-4.6\"," + + "\"messages\":[{\"role\":\"user\",\"content\":\"hello\"}]" + + "}"); r.status == 200 && (r.body contains '"usage"') ? { + "result": "valid" + } : r.status == 429 && (r.body contains "Insufficient balance") ? { + "result": "valid", + "reason": "Insufficient balance but still valid" + } : r.status in [401, 403] ? { + "result": "invalid", + "reason": "Unauthorized" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) <= 3.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# zendesk-secret-key +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "zendesk-secret-key" +description = "Detected a Zendesk Secret Key, risking unauthorized access to customer support services and sensitive ticketing data." +regex = '''(?i)(?:zendesk)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([a-z0-9]{40})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["zendesk"] +filter = ''' +filter.entropy(finding["secret"]) < 3.5 || filter.tokenRatio(finding["secret"]) >= 2.5 +''' + +# ────────────────────────────────────────────────────────────────────────────── +# zuplo-consumer-api-key.1 +# ────────────────────────────────────────────────────────────────────────────── +[[rules]] +id = "zuplo-consumer-api-key.1" +description = "Zuplo consumer API key." +regex = '''\b(zpka_[a-z0-9]{32}_[0-9a-f]{8})(?:\\?['"\x60]|[\s;]|\\[nr]|$)''' +confidence = "high" +keywords = ["zpka_"] +validate = ''' +let r = http.get("https://dev.zuplo.com/v1/who-am-i", { + "Authorization": "Bearer " + finding["secret"], + "x-api-key": finding["secret"], + "Accept": "application/json" + }); r.status == 200 ? { + "result": "valid" + } : r.status == 401 ? { + "result": "invalid", + "reason": "Authorization failed" + } : validate.unknown(r) +''' +filter = ''' +entropy(finding["secret"]) < 3.3 +''' +