Merge branch 'main' into bored-engineer-patch-2

Signed-off-by: Luke Young <bored-engineer@users.noreply.github.com>
This commit is contained in:
Luke Young 2026-01-31 13:27:24 -08:00 committed by GitHub
commit f3b049ba84
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
459 changed files with 44945 additions and 5013 deletions

View file

@ -1,42 +1,148 @@
name: CI Pull Request
on:
pull_request:
branches:
- main
pull_request:
branches:
- main
env:
VCPKG_ROOT: C:\vcpkg
VCPKG_DOWNLOADS: C:\vcpkg\downloads
VCPKG_FEATURE_FLAGS: binarycaching
VCPKG_BINARY_SOURCES: clear;x-gha,readwrite
RUST_TOOLCHAIN: "1.90"
# This workflow runs on pull requests to the main branch
# It builds the project for 2 platforms, Linux arm64 and macOS arm64,
# and runs tests for each platform. All platforms tested on merge to main
jobs:
linux-arm64:
name: Linux arm64
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v4
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.85.0
profile: minimal
override: true
- uses: swatinem/rust-cache@v2
- name: Build (Makefile linux-arm64)
run: make ubuntu-arm64
- name: Run tests
run: make tests
linux-arm64:
name: Linux arm64
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v4
- uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.RUST_TOOLCHAIN }}
profile: minimal
override: true
- name: Build (Makefile linux-arm64)
run: make ubuntu-arm64
- name: Run tests
run: make tests
env:
CARGO_BUILD_JOBS: 1
macos-arm64:
name: macOS arm64
runs-on: macos-14
steps:
- uses: actions/checkout@v4
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.85.0
profile: minimal
override: true
- uses: swatinem/rust-cache@v2
- name: Build (Makefile darwin-arm64)
run: make darwin-arm64
- name: Run tests
run: make tests
macos-arm64:
name: macOS arm64
runs-on: macos-14
steps:
- uses: actions/checkout@v4
- uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.RUST_TOOLCHAIN }}
profile: minimal
override: true
- uses: swatinem/rust-cache@v2
- name: Build (Makefile darwin-arm64)
run: make darwin-arm64
- name: Run tests
run: make tests
windows:
name: Windows x64
runs-on: windows-latest
# Windows-only env to keep vcpkg consistent and enable caching
env:
VCPKG_ROOT: C:\vcpkg
VCPKG_DOWNLOADS: C:\vcpkg\downloads
VCPKG_FEATURE_FLAGS: binarycaching
VCPKG_BINARY_SOURCES: clear;x-gha,readwrite
steps:
- uses: actions/checkout@v4
- uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.RUST_TOOLCHAIN }}
profile: minimal
override: true
# Cache vcpkg artifacts & downloads (so we only fetch PCRE once)
- name: Cache vcpkg artifacts
uses: actions/cache@v4
with:
path: |
C:\vcpkg\buildtrees
C:\vcpkg\packages
C:\vcpkg\installed
C:\vcpkg\downloads
C:\vcpkg\archives
C:\Users\runneradmin\AppData\Local\vcpkg\archives
key: vcpkg-${{ runner.os }}-hs-542
restore-keys: |
vcpkg-${{ runner.os }}-
vcpkg-
# Ensure downloads dir exists and seed PCRE 8.45 zip from a working mirror
- name: Pre-seed PCRE 8.45 for vcpkg
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path "$env:VCPKG_DOWNLOADS" | Out-Null
$dst = Join-Path $env:VCPKG_DOWNLOADS "pcre-8.45.zip"
if (-not (Test-Path $dst)) {
$sf = "https://sourceforge.net/projects/pcre/files/pcre/8.45/pcre-8.45.zip/download"
# Resolve to the final mirror URL (follow redirects without downloading the whole file)
$handler = New-Object System.Net.Http.HttpClientHandler
$handler.AllowAutoRedirect = $true
$client = New-Object System.Net.Http.HttpClient($handler)
try {
$req = New-Object System.Net.Http.HttpRequestMessage([System.Net.Http.HttpMethod]::Head, $sf)
$resp = $client.SendAsync($req).GetAwaiter().GetResult()
# Some mirrors dont like HEAD; fall back to GET headers only.
if (-not $resp.IsSuccessStatusCode) {
$req.Dispose()
$req = New-Object System.Net.Http.HttpRequestMessage([System.Net.Http.HttpMethod]::Get, $sf)
$resp = $client.SendAsync($req, [System.Net.Http.HttpCompletionOption]::ResponseHeadersRead).GetAwaiter().GetResult()
}
$finalUrl = $resp.RequestMessage.RequestUri.AbsoluteUri
Write-Host "Resolved SourceForge URL to: $finalUrl"
# Download the actual file
Invoke-WebRequest -Uri $finalUrl -OutFile $dst
}
finally {
$client.Dispose()
$handler.Dispose()
}
}
Get-ChildItem $env:VCPKG_DOWNLOADS
- uses: swatinem/rust-cache@v2
- name: Build
run: .\buildwin.bat
shell: cmd
- name: Run tests
shell: pwsh
run: |
if (-not (Get-Command cargo-nextest -ErrorAction SilentlyContinue)) {
cargo install --locked cargo-nextest
}
Write-Host "▶ cargo nextest run --release --workspace --all-targets"
cargo nextest run --release --workspace --all-targets
- name: Move artifact to dist
shell: bash
run: |
mkdir -p dist
cp target/release/kingfisher-windows-x64.zip dist/
- uses: actions/upload-artifact@v4
with:
name: kingfisher-windows-x64
path: dist/kingfisher-*windows-x64*.*

101
.github/workflows/release-docker.yml vendored Normal file
View file

@ -0,0 +1,101 @@
# .github/workflows/release-docker.yml
name: Publish Docker image
###############################################################################
# Triggers
###############################################################################
on:
# 1⃣ Traditional: run automatically when a GitHub Release is published
release:
types: [published]
# 2⃣ Option 2: run every time the build-and-release workflow
# completes successfully on the main branch
workflow_run:
workflows: ["build-and-release"]
types: [completed]
branches: [main]
# 3⃣ Manual: “Run workflow” button or `gh workflow run`
workflow_dispatch:
inputs:
tag:
description: "Tag to push (leave blank → latest release)"
required: false
type: string
###############################################################################
permissions:
contents: read # needed for checkout + GH API
packages: write # push to ghcr.io
###############################################################################
jobs:
build-and-push:
# Run if:
# - event is NOT workflow_run (release, workflow_dispatch)
# - OR workflow_run completed successfully
# - OR this is a re-run (run_attempt > 1) so we force it to run
if: >
github.event_name != 'workflow_run' ||
github.event.workflow_run.conclusion == 'success' ||
github.run_attempt > 1
runs-on: ubuntu-latest
steps:
# -----------------------------------------------------------------------
# Check out the exact commit that produced the artifacts (workflow_run),
# otherwise just use the SHA tied to the release / manual dispatch.
# -----------------------------------------------------------------------
- uses: actions/checkout@v4
with:
ref: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_sha || github.sha }}
# -----------------------------------------------------------------------
# Decide which tag were going to publish
# -----------------------------------------------------------------------
- name: Determine tag
id: tag
shell: bash
env:
# populated only for workflow_dispatch
MANUAL_TAG: ${{ github.event.inputs.tag }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
if [[ "${GITHUB_EVENT_NAME}" == "release" ]]; then
RAW_TAG="${{ github.event.release.tag_name }}"
elif [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" && -n "${MANUAL_TAG}" ]]; then
RAW_TAG="${MANUAL_TAG}"
else
# workflow_run (or manual w/o tag) → ask GitHub API for latest release tag
RAW_TAG=$(curl -sSL -H "Authorization: Bearer ${GH_TOKEN}" \
"https://api.github.com/repos/${{ github.repository }}/releases/latest" \
| jq -r .tag_name)
fi
# Strip a leading "v" so v1.2.3 → 1.2.3
TAG=${RAW_TAG#v}
echo "Selected tag: ${TAG}"
echo "tag=${TAG}" >> "${GITHUB_OUTPUT}"
# -----------------------------------------------------------------------
# Build & push
# -----------------------------------------------------------------------
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v5
with:
context: .
file: docker/Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: |
ghcr.io/mongodb/kingfisher:latest
ghcr.io/mongodb/kingfisher:${{ steps.tag.outputs.tag }}

View file

@ -4,6 +4,20 @@ on:
push:
branches:
- main
release:
types: [published]
workflow_dispatch:
inputs:
tag:
description: "Tag to publish (leave blank to use Cargo.toml version)"
required: false
type: string
env:
VCPKG_ROOT: C:\vcpkg
VCPKG_DOWNLOADS: C:\vcpkg\downloads
VCPKG_FEATURE_FLAGS: binarycaching
VCPKG_BINARY_SOURCES: clear;x-gha,readwrite
RUST_TOOLCHAIN: "1.90"
jobs:
# ──────────────── Linux (via Makefile) ────────────────
@ -15,25 +29,51 @@ jobs:
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.85.0
toolchain: ${{ env.RUST_TOOLCHAIN }}
profile: minimal
override: true
- uses: swatinem/rust-cache@v2
- name: Install packaging tools
run: cargo install cargo-deb cargo-generate-rpm
- name: Build (Makefile linux-x64)
run: make linux-x64
- name: Fix permissions
run: sudo chown -R $(id -u):$(id -g) target
- name: Build Debian package
run: |
cargo deb --no-build --target x86_64-unknown-linux-musl \
--output target/release/kingfisher-linux-x64.deb
- name: Build RPM package
run: |
cargo generate-rpm --target x86_64-unknown-linux-musl \
--output target/release/kingfisher-linux-x64.rpm
- name: Move artifact to dist
shell: bash
run: |
mkdir -p dist
cp target/release/kingfisher-linux-x64.tgz dist/
cp target/release/kingfisher-linux-x64.deb dist/
cp target/release/kingfisher-linux-x64.rpm dist/
- uses: actions/upload-artifact@v4
with:
name: kingfisher-linux-x64
path: dist/kingfisher-*linux-x64*.*
name: kingfisher-linux-x64.tgz
path: dist/kingfisher-linux-x64.tgz
- uses: actions/upload-artifact@v4
with:
name: kingfisher-linux-x64.deb
path: dist/kingfisher-linux-x64.deb
- uses: actions/upload-artifact@v4
with:
name: kingfisher-linux-x64.rpm
path: dist/kingfisher-linux-x64.rpm
linux-arm64:
name: Linux arm64
@ -43,36 +83,59 @@ jobs:
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.85.0
toolchain: ${{ env.RUST_TOOLCHAIN }}
profile: minimal
override: true
- uses: swatinem/rust-cache@v2
- name: Install packaging tools
run: cargo install cargo-deb cargo-generate-rpm
- name: Build (Makefile linux-arm64)
run: make linux-arm64
- name: Fix permissions
run: sudo chown -R $(id -u):$(id -g) target
- name: Build Debian package
run: |
cargo deb --no-build --target aarch64-unknown-linux-musl \
--output target/release/kingfisher-linux-arm64.deb
- name: Build RPM package
run: |
cargo generate-rpm --target aarch64-unknown-linux-musl \
--output target/release/kingfisher-linux-arm64.rpm
- name: Move artifact to dist
shell: bash
run: |
mkdir -p dist
cp target/release/kingfisher-linux-arm64.tgz dist/
cp target/release/kingfisher-linux-arm64.deb dist/
cp target/release/kingfisher-linux-arm64.rpm dist/
- uses: actions/upload-artifact@v4
with:
name: kingfisher-linux-arm64
path: dist/kingfisher-*linux-arm64*.*
name: kingfisher-linux-arm64.tgz
path: dist/kingfisher-linux-arm64.tgz
- uses: actions/upload-artifact@v4
with:
name: kingfisher-linux-arm64.deb
path: dist/kingfisher-linux-arm64.deb
- uses: actions/upload-artifact@v4
with:
name: kingfisher-linux-arm64.rpm
path: dist/kingfisher-linux-arm64.rpm
macos-x64:
name: macOS x64
runs-on: macos-13
runs-on: macos-15-intel
steps:
- uses: actions/checkout@v4
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.85.0
toolchain: ${{ env.RUST_TOOLCHAIN }}
profile: minimal
override: true
@ -80,8 +143,6 @@ jobs:
- name: Build Darwin x64
run: make darwin-x64
- name: Run tests
run: make tests
- name: Move artifacts to dist
shell: bash
@ -94,7 +155,6 @@ jobs:
name: kingfisher-darwin-x64.tgz
path: dist/kingfisher-darwin-x64.tgz
macos-arm64:
name: macOS arm64
runs-on: macos-14
@ -103,7 +163,7 @@ jobs:
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.85.0
toolchain: ${{ env.RUST_TOOLCHAIN }}
profile: minimal
override: true
@ -125,34 +185,87 @@ jobs:
name: kingfisher-darwin-arm64.tgz
path: dist/kingfisher-darwin-arm64.tgz
# ──────────────── Windows ────────────────
windows:
name: Windows x64
runs-on: windows-latest
# Windows-only env to keep vcpkg consistent and enable caching
env:
VCPKG_ROOT: C:\vcpkg
VCPKG_DOWNLOADS: C:\vcpkg\downloads
VCPKG_FEATURE_FLAGS: binarycaching
VCPKG_BINARY_SOURCES: clear;x-gha,readwrite
steps:
- uses: actions/checkout@v4
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.85.0
toolchain: ${{ env.RUST_TOOLCHAIN }}
profile: minimal
override: true
# Cache vcpkg artifacts & downloads (so we only fetch PCRE once)
- name: Cache vcpkg artifacts
uses: actions/cache@v3
uses: actions/cache@v4
with:
# Adjust these paths if your vcpkg root is somewhere else
path: |
C:\vcpkg\buildtrees
C:\vcpkg\packages
C:\vcpkg\installed
key: ${{ runner.os }}-vcpkg-${{ hashFiles('vcpkg.json', 'vcpkg-configuration.cmake') }}
C:\vcpkg\downloads
C:\vcpkg\archives
C:\Users\runneradmin\AppData\Local\vcpkg\archives
key: vcpkg-${{ runner.os }}-hs-542
restore-keys: |
${{ runner.os }}-vcpkg-
vcpkg-${{ runner.os }}-
vcpkg-
# Ensure downloads dir exists and seed PCRE 8.45 zip from a working mirror
- name: Pre-seed PCRE 8.45 for vcpkg
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path "$env:VCPKG_DOWNLOADS" | Out-Null
$dst = Join-Path $env:VCPKG_DOWNLOADS "pcre-8.45.zip"
if (-not (Test-Path $dst)) {
$sf = "https://sourceforge.net/projects/pcre/files/pcre/8.45/pcre-8.45.zip/download"
# Resolve to the final mirror URL (follow redirects without downloading the whole file)
$handler = New-Object System.Net.Http.HttpClientHandler
$handler.AllowAutoRedirect = $true
$client = New-Object System.Net.Http.HttpClient($handler)
try {
$req = New-Object System.Net.Http.HttpRequestMessage([System.Net.Http.HttpMethod]::Head, $sf)
$resp = $client.SendAsync($req).GetAwaiter().GetResult()
# Some mirrors dont like HEAD; fall back to GET headers only.
if (-not $resp.IsSuccessStatusCode) {
$req.Dispose()
$req = New-Object System.Net.Http.HttpRequestMessage([System.Net.Http.HttpMethod]::Get, $sf)
$resp = $client.SendAsync($req, [System.Net.Http.HttpCompletionOption]::ResponseHeadersRead).GetAwaiter().GetResult()
}
$finalUrl = $resp.RequestMessage.RequestUri.AbsoluteUri
Write-Host "Resolved SourceForge URL to: $finalUrl"
# Download the actual file
Invoke-WebRequest -Uri $finalUrl -OutFile $dst
}
finally {
$client.Dispose()
$handler.Dispose()
}
}
Get-ChildItem $env:VCPKG_DOWNLOADS
- uses: swatinem/rust-cache@v2
- uses: Swatinem/rust-cache@v2
- name: Build
run: .\buildwin.bat -force
run: .\buildwin.bat
shell: cmd
- name: Run tests
@ -183,11 +296,20 @@ jobs:
contents: write
steps:
- uses: actions/checkout@v4
- name: Read version from Cargo.toml
- name: Determine tag
id: version
shell: bash
run: |
VERSION=$(grep -m1 '^version\s*=' Cargo.toml | cut -d '"' -f2)
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
set -euo pipefail
if [[ "${GITHUB_EVENT_NAME}" == "release" ]]; then
TAG="${{ github.event.release.tag_name }}"
elif [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" && -n "${{ github.event.inputs.tag }}" ]]; then
TAG="${{ github.event.inputs.tag }}"
else
VERSION=$(grep -m1 '^version\s*=' Cargo.toml | cut -d '"' -f2)
TAG="v${VERSION}"
fi
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
- uses: actions/download-artifact@v4
with:
path: target/release/kingfisher-*
@ -207,8 +329,9 @@ jobs:
- name: Create release & upload assets
uses: ncipollo/release-action@v1
with:
tag: v${{ steps.version.outputs.version }}
name: "Kingfisher v${{ steps.version.outputs.version }}"
bodyFile: .latest_changelog.md # ← only the most-recent entry
tag: ${{ steps.version.outputs.tag }}
name: "Kingfisher ${{ steps.version.outputs.tag }}"
bodyFile: .latest_changelog.md # ← only the most-recent entry
allowUpdates: true
generateReleaseNotes: false
artifacts: target/release/**
artifacts: target/release/**

10
.gitignore vendored
View file

@ -5,11 +5,19 @@
*.sarif
*.profile.json
*.json
!webserver/static/sample-report.json
!docs/access-map-viewer/sample-report.json
*.jsonl
*.bson
.prettierrc
custom.py
logs/*
*.patch
*.orig
*.rej
*.html
!docs/access-map-viewer/index.html
*.dot
### macOS ###
# General
@ -20,6 +28,7 @@ logs/*
# Icon must end with two \r
Icon
node_modules/
# Thumbnails
._*
@ -68,6 +77,7 @@ Cargo.lock
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
.vscode/launch.json
# Local History for Visual Studio Code
.history/

18
.pre-commit-hooks.yaml Normal file
View file

@ -0,0 +1,18 @@
- id: kingfisher-docker
name: kingfisher (docker)
description: Run Kingfisher in Docker against staged changes at the repository root. No local install required.
entry: ghcr.io/mongodb/kingfisher:latest
language: docker
args: ["scan", ".", "--staged", "--quiet", "--no-update-check"]
pass_filenames: false
stages: [commit]
- id: kingfisher
name: kingfisher
description: Scan staged changes with the locally installed Kingfisher binary.
entry: kingfisher
language: system
args: ["scan", ".", "--staged", "--quiet", "--no-update-check"]
pass_filenames: false
types: [file]
stages: [commit]

View file

@ -2,6 +2,309 @@
All notable changes to this project will be documented in this file.
## [v1.76.0]
- Fixed validation deduplication for rules with nested unnamed captures (e.g. `(?<REGEX>...(ABC|DEF)...)`) to use the primary capture for grouping, ensuring each unique match triggers a separate validation request.
- Added trace-level (`-vv`) logging for internal validation dedup keys and grouping to aid debugging.
- Switched compression dependencies to pure-Rust bzip2/lzma implementations and pared zip features to avoid C-based codecs for bz2/xz handling.
## [v1.75.0]
- Enhanced Access Map View: added fingerprint display, enabled searching by fingerprint, and implemented bidirectional navigation between Findings and Access Map nodes.
- Added Slack Access Map support with granular permissions in the tree view.
- Improved HTML report
- Improved several rules
- Added new rules for Apollo, Clay, CodeRabbit, Customer.io, Instantly, Vast.ai
- Skipped per-repository report writes when an output file is specified and emit a single aggregated report after multi-repository scans to preserve full output content in files.
## [v1.74.0]
- Added new rules: cursor, definednetworking, filezilla, harness, intra42, klingai, lark, mergify, naver, plaid, resend, retellai
## [v1.73.0]
- Will now prefer git history findings when identical secrets appear in both current files and git history (dedup only).
- Fixed report viewer to add support for opening JSONL.
- Add opt-in contributor repository enumeration for GitHub/GitLab `--git-url` scans with `--include-contributors`, plus `--repo-clone-limit` to cap repo cloning.
- Add `--git-clone-dir` to set the parent clone directory and `--keep-clones` to preserve cloned repos after scans.
- Added several new rules.
- Added configurable validation timeout and retry settings for `kingfisher scan`.
## [v1.72.0]
- Fixed deduplication for dependency-provider rules so dependent validations run per blob
- Updated Artifactory rule entropy and added new artifactory rule
- Aliased "kingfisher self-update" as "kingfisher update"
- Map SARIF result levels from rule confidence
- Added tag selection support to the bash and PowerShell install scripts.
## [v1.71.0]
- Improved Report Viewer layout
- Improved Salesforce rule
## [v1.70.0]
- Added `--staged` argument to support new `pre-commit` behavior and added integration coverage to ensure validated secrets block commits when used as pre-commit hook
- Added new rules for AWS Bedrock, Voyage.ai, Posthog, Atlassian
- Added an embedded web-based report and access-map viewer via `kingfisher view` subcommand that can load JSON or JSONL reports passed on the CLI (or upload them in the browser)
- Updated Jira create to gouqi, which supports Jira api v2 and v3
## [v1.69.0]
- Reduced per-match memory usage by compacting stored source locations and interning repeated capture names.
- Stored optional validation response bodies as boxed strings to avoid allocating empty payloads and to streamline validator caches.
- Parallelized git cloning based on the configured job count and begin scanning repositories as soon as each clone finishes to reduce end-to-end scan times.
- Combined per-repository results into a single aggregate summary after scans complete.
- Added initial access-map support and report viewer html file. Currently beta features.
## [v1.68.0]
- Fixed Bitbucket authenticated cloning bug
## [v1.67.0]
- Added checksum to GitLab rule
- Fixed deduplication to consider rule identifiers so overlapping patterns are not merged before validation
- After scan summaries, emit the styled outdated-version notice to stderr when a newer release is available
- Reduced false positives across a number of rules
- Updated Summary to include scan date, kingfisher version ran, and latest kingfisher version available
## [v1.66.0]
- Updating to support Bitbucket App Passwords
- Improved boundaries for several rules
- Added more rules
## [v1.65.0]
- Skip reporting MongoDB and Postgres findings when their connection strings cannot be parsed, even when validation is disabled.
- Improve MySQL detection by broadening URI coverage and adding live validation that skips clearly invalid connection strings.
- Added a helper to truncate validation response bodies only at UTF-8 character boundaries to prevent panics during validation.
## [v1.64.0]
- Fixed a bug when using --redact, that broke validation
- Added JDBC rule with validator
- Filter out empty 'KF_BITBUCKET_*' environment values when constructing the Bitbucket authentication configuration so blank variables no longer override valid credentials
## [v1.63.1]
- Updated allocator
## [v1.63.0]
- Fixed bug when retrieving some finding values and injecting them as TOKENS in the rule templates
- Improved Datadog rule
- Improved AWS rule
## [v1.62.0]
- Added `pattern_requirements` checks to rules, providing lightweight post-regex character-class validation without lookarounds. See docs/RULES.md for detail
- Added an `ignore_if_contains` option to `pattern_requirements` to drop matches containing case-insensitive placeholder words, with tests covering the new behavior.
- Updated rules to adopt the new `pattern_requirements` support.
- Added checksum comparisons to `pattern_requirements`, new `suffix`, `crc32`, and `base62` Liquid filters, and verbose logging so mismatched checksums are skipped with context rather than reported as findings.
- Split GitHub token detections into fine-grained/fixed-format variants and enforce checksum validation for modern GitHub token families (PAT, OAuth, App, refresh) while preserving legacy coverage.
- Added a rule for Zuplo tokens.
- Added checksum calculation for Confluent, GitHub, and Zuplo tokens, which can drastically reduce false positive reports.
- Improved OpsGenie validation.
- Automatically enable `--no-dedup` when `--manage-baseline` is supplied so baseline management keeps every finding.
- This release is focused on further improving detection accuracy, before even attempting to validate findings.
- Updated GitHub Actions CI for Windows and buildwin.bat script
## [v1.61.0]
- Fixed local filesystem scans to keep `open_path_as_is` enabled when opening Git repositories and only disable it for diff-based scans.
- Created Linux and Windows specific installer script
- Updated diff-focused scanning so `--branch-root-commit` can be provided alongside `--branch`, letting you diff from a chosen commit while targeting a specific branch tip (still defaulting back to the `--branch` ref when the commit is omitted).
- Updated rules
## [v1.60.0]
- Removed the `--bitbucket-username`, `--bitbucket-token`, and `--bitbucket-oauth-token` flags in favour of `KF_BITBUCKET_*` environment variables when authenticating to Bitbucket.
- Added provider-specific `kingfisher scan` subcommands (for example `kingfisher scan github …`) that translate into the legacy flags under the hood. The new layout keeps backwards compatibility while removing the wall of provider options from `kingfisher scan --help`.
- Updated the README so every provider example (GitHub, GitLab, Bitbucket, Azure Repos, Gitea, Hugging Face, Slack, Jira, Confluence, S3, GCS, Docker) uses the new subcommand style.
- Legacy provider flags (for example `--github-user`, `--gitlab-group`, `--bitbucket-workspace`, `--s3-bucket`) still work but now emit a deprecation warning to encourage migration to the new `kingfisher scan <provider>` flow.
- Kept the direct `kingfisher scan /path/to/dir` flow for local filesystem / local git repo scans while adding a `--list-only` switch to each provider subcommand so repository enumeration no longer requires the standalone `github repos`, `gitlab repos`, etc. commands.
- Removed the legacy top-level provider commands (`kingfisher github`, `kingfisher gitlab`, `kingfisher gitea`, `kingfisher bitbucket`, `kingfisher azure`, `kingfisher huggingface`) now that enumeration lives under `kingfisher scan <provider> --list-only`.
## [v1.59.0]
- Fixed `kingfisher scan github …` (and other provider-specific subcommands) so they no longer demand placeholder path arguments before the CLI accepts the request.
- Fixed `kingfisher scan` so that providing `--branch` without `--since-commit` now diffs the branch against the empty tree and scans every commit reachable from that branch.
- Added rules for meraki, duffel, finnhub, frameio, freshbooks, gitter, infracost, launchdarkly, lob, maxmind, messagebird, nytimes, prefect, scalingo, sendinblue, sentry, shippo, twitch, typeform
- ## [v1.58.0]
- Added first-class Hugging Face scanning support, including CLI enumeration, token authentication, and integration with remote scans.
- Condensed GitError formatting to report the exit status and the first informative lines from stdout/stderr, producing concise git clone failure logs.
- Added support for scanning Google Cloud Storage buckets via `--gcs-bucket`, including optional prefixes and service-account authentication.
- Added `--skip-aws-account` (now accepting comma-separated values) and `--skip-aws-account-file` to bypass live AWS validation for known canary/honey-token account IDs without triggering alerts. Kingfisher now ships with several canary AWS account IDs pre-seeded in the skip list and now reports matching findings as "Not Attempted" with the "Response" containing "(skip list entry)" so it's clear that validation was intentionally skipped and why.
## [v1.57.0]
- Added inline ignore directive detection to treat suppression tokens anywhere on surrounding lines, including multi-line handling
- Added a `--no-ignore` CLI flag to disable inline directives when you need every potential secret reported
- Added: repeatable `--ignore-comment <TOKEN>` flag to reuse inline directives from other scanners (for example `NOSONAR`, `kics-scan ignore`, `gitleaks:allow`, etc)
- Respect user color settings in update messages by using the same color helper as the main reporter, ensuring consistent output and no ANSI codes on update check, when color is disabled
## [v1.56.0]
- Fixed tree-sitter scanning bug where passing --no-base64 caused errors to be printed when the file type couldnt be determined
## [v1.55.0]
- Added first-class Azure Repos support, including CLI commands, enumeration, and documentation updates
- Improved performance of tree-sitter parsing
- Updated Windows build script to ensure static binary is produced
## [v1.54.0]
- Added first-class Gitea support, including CLI commands, environment-based authentication, documentation, and integration with scans and repository enumeration.
- Populate the finding path from git blob metadata so history-derived secrets display their file location instead of an empty path
- Replaced Match::finding_ids SHA1-based hashing with a fast xxh3_64 digest that keeps IDs deterministic while eliminating a hot-path SHA1 dependency
## [v1.53.0]
- Added first-class Bitbucket support, including CLI commands, authentication helpers, documentation, and integration testing.
## [v1.52.0]
- Enabled ANSI formatting in the tracing formatter whenever stderr is attached to a terminal so colorized updater messages render correctly instead of showing escape sequences.
- Added a new CLI flag, `--user-agent-suffix` to allow developers to append additional information to the user-agent
- Removed the unused --rlimit-nofile flag
## [1.51.0]
- Added diff-only Git scanning via `--since-commit` and `--branch`, including remote-aware ref resolution so CI jobs can pair `--git-url` clones with pull request branches
## [1.50.0]
- Added `--github-exclude` and `--gitlab-exclude` options to skip specific repositories when scanning or listing GitHub and GitLab sources, including support for gitignore-style glob patterns
## [1.49.0]
- Enabled MongoDB URI validation
- AWS + GCP validators now respect HTTPS_PROXY and share a consistent user agent across AWS, GCP, and HTTP validation
- Increase max-file-size default to 256 mb (up from 64 mb)
- Improved AWS rule
## [1.48.0]
- Improved error message when self-update cannot find the current binary
- Optimized memory usage via string interning and extensive data sharing
- Replaced quadratic match filtering with a per-rule span map, fixing missed secrets in extremely large files and improving scan performance
- Support scanning extremely large files by chunking input into 1 GiB segments with small overlaps, avoiding vectorscan buffer limits while preserving match offsets
- Always use chunked vectorscan, eliminating the slow regex fallback for blobs over 4 GiB
- Skip Base64 scanning for blobs over 64 MB to avoid a second pass over massive files
- Increased max-file-size default to 64 MB (up from 25 MB)
## [1.47.0]
- MongoDB validator now validates `mongodb+srv://` URIs with a fast timeout instead of skipping them
- Improved rules: github oauth2, diffbot, mailchimp, aws
- Added validation to SauceLabs rule
- Added rules: shodan, bitly, flickr
- Decode Base64 blobs and scan their contents for secrets while skipping short strings for performance. This has a small performance impact and can be disabled with `--no-base64`
## [1.46.0]
- Improved rules: AWS, pem
- Added rule for Ollama, Weights and Biases, Cerebras, Friendli, Fireworks.ai, NVIDIA NIM, together.ai, zhipu
- Added `self-update` command to update the binary independently. Now supports updating over homebrew managed binary
- MongoDB validator now checks `mongodb+srv://` URIs with fast-fail timeouts
## [1.45.0]
- Added `--repo-artifacts` flag to scan repository issues, gists/snippets, and wikis when cloning via `--git-url`
- Added rules for sendbird, mattermost, langchain, notion
- JWT validation hardened to reject alg:none by default (only allowed if explicitly configured), require iss for OIDC/JWKS verification, ensuring "Active Credential" means cryptographically verified and time-valid, not just unexpired
- Updated the Git cloning logic to include all refs and minimize clone output, allowing Kingfisher to analyze pull request and deleted branch history
## [1.44.0]
- Fixed issue with self-update on Linux
- Reverted the change to json and jsonl outputs by rule
- Added `--skip-regex` and `--skip-word` flags to ignore secrets matching custom patterns or skipwords
## [1.43.0]
- Added rules for clearbit, kickbox, azure container registry, improved Azure Storage key
- Grouped JSON and JSONL outputs by rule, restoring `matches` arrays in reports
## [1.42.0]
- Fixed pagination issue when calling gitlab api
- Expanded directory exclusion handling to interpret plain patterns as prefixes, ensuring options like --exclude .git also skip all nested paths
- Updated baseline management to track encountered findings and remove entries that are no longer present, saving the baseline file whenever entries are pruned or new matches are added
- Added rules for authress, clickhouse, codecov, contentful, curl, dropbox, fly.io, hubspot, firecrawl
- Internal refactoring of rule loader, git enumerator, and filetype guesser
- Improved language detection
## [1.41.0]
- Added support for scanning gitlab subgroups, with `kingfisher scan --gitlab-group my-group --gitlab-include-subgroups`
- Added rule for Vercel
## [1.40.0]
- Dropped the “prevalidated” flag from rule definitions and validation logic so every finding now flows through the standard active/inactive/unknown pipeline, simplifying rule configuration and preventing specialcase bypasses
- Improved Tailscale api key detectors
## [1.39.0]
- Added support for scanning Confluence pages via `--confluence-url` and `--cql`
## [1.38.0]
- `--quiet` now suppresses scan summaries and rule statistics unless `--rule-stats` is explicitly provided
- Added X Consumer key detection and validation
## [1.37.0]
- GitLab: Matched GitLab group repository listings to glab by only enumerating projects that belong directly to each group, without automatically traversing subgroups
## [1.36.0]
- Fixed GitHub organization and GitLab group scans when using `--git-history=none`
- JWT tokens without both `iss` and `aud` are no longer reported as active credentials
## [1.35.0]
- Remote scans with `--git-history=none` now clone repositories with a working tree and scan the current files instead of erroring with "No inputs to scan".
- Fixed issue where `--redact` did not function properly
- Fixed validation logic for clarifai rule
## [1.34.0]
- Use system TLS root certificates to support self-hosted GitLab instances with internal CAs
- Added new rule: Coze personal access token
- Updated Supabase rule to detect project url's and validate their corresponding tokens
## [1.33.0]
- Fixed header precedence so custom HTTP validation headers like `Accept` are preserved
- Added new Heroku rule
## [1.32.0]
- Added support for scanning AWS S3 buckets via `--s3-bucket` and optional `--s3-prefix`
- Added `--role-arn` and `--aws-local-profile` flags for S3 authentication alongside `KF_AWS_KEY`/`KF_AWS_SECRET`
- Added progress bar for scanning s3 buckets
- Refactored output reporting and formatting logic
## [1.31.0]
- New rules: Telegram bot token, OpenWeatherMap, Apify, Groq
- New OpenAI detectors added (@joshlarsen)
- Fixed bug that broke validation when using unnamed group captures
## [1.30.0]
- Fixed validation caching for HTTP validators to include rendered headers so inactive secrets no longer appear active.
- Removed pre-commit installation hook, due to bugs
## [1.29.0]
- Fixed issue when more than 1 named capture group is used in a rule variable
- Added a new liquid template filters: `b64dec`
- Added custom validator for Coinbase, and a Coinbase rule that uses it
## [1.28.0]
- Added support for scanning Slack
## [1.27.0]
- Added Buildkite rule
- Added support for scanning Docker images via `--docker-image`
## [1.26.0]
- Added rule for ElevenLabs
- Added support for scanning Jira issues via a given JQL (Jira Query Language)
## [1.25.0]
- Fixed GitLab authentication bug
- Added pre-commit and pre-receive installation hooks
- MongoDB validator now skips `mongodb+srv://` URIs and returns a message that validation was skipped
- Fixed noisy Baseten rule
## [1.24.0]
- Now generating DEB and RPM packages
- Now releasing Docker images, and updated README
- Added rule for Scale, Deepgram, AssemblyAI
## [1.23.0]
- Updating GitHub Action to generate Docker image
- Added rules for Diffbot, ai21, baseten
- Fixed supabase rule
- Added 'alg' to JWT validation output
## [1.22.0]
- Added rules for Google Gemini AI, Cohere, Stability.ai, Replicate, Runway, Clarifai
- Upgraded dependencies
## [1.21.0]
- Improved Azure Storage rule
- Added rule to detect TravisCI encrypted values
- Added baseline feature with `--baseline-file` and `--manage-baseline` flags
- Introduced `--exclude` option for skipping paths
- Added tests covering baseline and exclude workflow
- Added validation for JWT tokens that checks `exp` and `nbf` claims
- JWT validation performs OpenID Connect discovery using the `iss` claim and verifies signatures via JWKS
- Removed `--ignore-tests` argument, because the `--exclude` flag provides more granular functionality
- DigitalOcean rule update
- Adafruit rule update
## [1.20.0]
- Removed confirmation prompt when user provides --self-update flag

View file

@ -1,6 +1,6 @@
[workspace.package]
edition = "2021"
rust-version = "1.83"
rust-version = "1.90"
license = "Apache-2.0"
authors = ["Mick Grove <mick.grove@mongodb.com>"]
homepage = "https://github.com/mongodb/kingfisher"
@ -10,7 +10,8 @@ publish = false
[package]
name = "kingfisher"
version = "1.20.0"
version = "1.76.0"
description = "MongoDB's blazingly fast and accurate secret scanning and validation tool"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
@ -19,18 +20,38 @@ homepage.workspace = true
repository.workspace = true
publish.workspace = true
[package.metadata.deb]
name = "kingfisher"
maintainer = "Mick Grove <mick.grove@mongodb.com>"
depends = "$auto"
section = "utils"
priority = "optional"
assets = [
["target/release/kingfisher", "/usr/bin/kingfisher", "755"]
]
[package.metadata.generate-rpm]
package = "kingfisher"
summary = "MongoDB's blazingly fast and accurate secret scanning and validation tool"
license = "Apache-2.0"
url = "https://github.com/mongodb/kingfisher"
assets = [
{ source = "target/release/kingfisher", dest = "/usr/bin/kingfisher", mode = "755" }
]
[dependencies]
clap = { version = "4.3", features = [
clap = { version = "4.5", features = [
"cargo",
"derive",
"env",
"unicode",
"wrap_help",
] }
anyhow = "1.0"
bstr = { version = "1.0", features = ["serde"] }
bstr = { version = "1.12", features = ["serde"] }
fixedbitset = "0.5"
gix = { version = "0.72", features = ["max-performance", "serde", "blocking-network-client"] }
gix = { version = "0.73", features = ["max-performance", "serde", "blocking-network-client"] }
ignore = "0.4"
petgraph = "0.6"
roaring = "0.10"
@ -41,132 +62,162 @@ smallvec = { version = "1", features = [
"const_new",
"union",
] }
tracing = "0.1.41"
tracing = "0.1.43"
indicatif = { version = "0.17", features = ["improved_unicode"] }
rayon = "1.10"
sha1 = "0.10.6"
rayon = "1.11"
hex = "0.4.3"
vectorscan-rs = "0.0.5"
regex = "1.10.6"
serde_json = "1.0.128"
regex = "1.12.2"
serde_json = "1.0.145"
lazy_static = "1.5.0"
url = "2.5.2"
url = "2.5.7"
include_dir = { version = "0.7", features = ["glob"] }
strum = { version = "0.26", features = ["derive"] }
sysinfo = "0.31.2"
sysinfo = "0.31.4"
webbrowser = "1.0.5"
reqwest = { version = "0.12", default-features = false, features = [
"json",
"gzip",
"brotli",
"json",
"gzip",
"brotli",
"deflate",
"stream",
"rustls-tls",
"rustls-tls-native-roots",
"blocking",
"multipart",
"rustls-tls",
] }
axum = { version = "0.7", default-features = false, features = ["tokio", "http1"] }
chrono = "0.4.38"
thiserror = "1.0.63"
tokio = { version = "1.39.2", features = ["full"] }
chrono = "0.4.42"
thiserror = "1.0.69"
tokio = { version = "1.48.0", features = ["full"] }
base64 = "0.22.1"
crossbeam-channel = "0.5.13"
indenter = "0.3.3"
crossbeam-channel = "0.5.15"
indenter = "0.3.4"
serde-sarif = "0.4"
console = "0.15.8"
time = "0.3.36"
tempfile = "3.12.0"
num_cpus = "1.16.0"
once_cell = "1.19.0"
http = "1.1.0"
liquid = "0.26.4"
liquid-core = "0.26.4"
flate2 = "1.0.33"
brotli = "6.0.0"
console = "0.15.11"
time = "0.3.44"
tempfile = "3.23.0"
num_cpus = "1.17.0"
once_cell = "1.21.3"
http = "1.4.0"
liquid = "0.26.11"
liquid-core = "0.26.11"
flate2 = "1.1"
thousands = "0.2.0"
base32 = "0.5.1"
crossbeam-skiplist = "0.1.3"
tokio-postgres = { version = "0.7", default-features = false, features = ["runtime"] }
mongodb = { version = "3.2", default-features = false, features = ["rustls-tls", "aws-auth", "compat-3-0-0", "dns-resolver"] }
bson = "2.13.0"
ring = "0.17.8"
pem = "3.0.4"
aws-config = "1.5.10"
aws-credential-types = "1.2.1"
aws-sdk-sts = "1.21.0"
aws-types = "1.3.3"
mongodb = { version = "3.4", default-features = false, features = ["rustls-tls", "aws-auth", "compat-3-0-0", "dns-resolver"] }
mysql_async = { version = "0.34.2", default-features = false, features = ["default-rustls"] }
bson = "2.15.0"
ring = "0.17.14"
pem = "3.0.6"
aws-config = "1.8.12"
aws-credential-types = "1.2.11"
aws-sdk-sts = "1.95.0"
aws-types = "1.3.11"
byteorder = "1.5.0"
parking_lot = "0.12.3"
parking_lot = "0.12.5"
octorust = "0.9.0"
reqwest-middleware = "0.4.1"
tracing-subscriber = {version = "0.3.19", features = ["env-filter"] }
tracing-core = "0.1.33"
tree-sitter = "0.24.4"
tree-sitter-bash = "0.23.3"
tree-sitter-c = "0.23.2"
reqwest-middleware = "0.4.2"
tracing-subscriber = {version = "0.3.22", features = ["env-filter"] }
tracing-core = "0.1.35"
tree-sitter = "0.25.10"
aws-smithy-http-client = "1.1.5"
aws-smithy-runtime-api = "1.9.3"
aws-smithy-types = "1.3.5"
tree-sitter-bash = "0.25.1"
tree-sitter-c = "0.24.1"
tree-sitter-c-sharp = "0.23.1"
tree-sitter-cpp = "0.23.4"
tree-sitter-css = "0.23.1"
tree-sitter-css = "0.23.2"
tree-sitter-go = "0.23.4"
tree-sitter-html = "0.23.2"
tree-sitter-java = "0.23.4"
tree-sitter-java = "0.23.5"
tree-sitter-javascript = "0.23.1"
tree-sitter-php = "0.23.11"
tree-sitter-python = "0.23.4"
tree-sitter-python = "0.23.6"
tree-sitter-ruby = "0.23.1"
tree-sitter-rust = "0.23.2"
tree-sitter-rust = "0.24.0"
tree-sitter-toml-ng = "0.7.0"
tree-sitter-typescript = "0.23.2"
tree-sitter-yaml = "0.6.1"
tree-sitter-yaml = "0.7.2"
streaming-iterator = "0.1.9"
tree-sitter-regex = "0.24.3"
tree_magic_mini = "3.2"
content_inspector = "0.2.4"
rustc-hash = "2.1.0"
rustc-hash = "2.1.1"
term_size = "0.3.2"
bzip2 = "0.5.0"
zip = "2.2.2"
tar = "0.4.43"
xz2 = "0.1.7"
bzip2-rs = "0.1.2"
zip = { version = "2.4.2", default-features = false, features = ["deflate", "deflate64", "time"] }
tar = "0.4.44"
lzma-rs = "0.3.0"
asar = "0.3.0"
blake3 = "1.5.5"
memmap2 = "0.9.5"
blake3 = "1.8.2"
memchr = "2.7"
memmap2 = "0.9.9"
futures = "0.3.31"
dashmap = "6.1.0"
xxhash-rust = { version = "0.8.15", features = ["xxh3", "const_xxh3"] }
serde_yaml = "0.9.34"
hmac = "0.12.1"
sha2 = "0.10.8"
strum_macros = "0.27.1"
humantime = "2.2.0"
sha2 = "0.10.9"
strum_macros = "0.27.2"
humantime = "2.3.0"
path-dedot = "3.1.1"
quick-xml = {version = "0.37.5", features = ["serde","serialize"] }
rustls = "0.23.26"
quick-xml = {version = "0.38.4", features = ["serde","serialize"] }
rustls = "0.23.35"
tokio-postgres-rustls = "0.13.0"
rustls-native-certs = "0.8.1"
rustls-native-certs = "0.8.2"
predicates = "3.1.3"
assert_cmd = "2.0.17"
proptest = "1.6.0"
color-backtrace = "0.7.0"
gitlab = "0.1711.0"
mimalloc = {version = "0.1.46", features = ["override"]}
thread_local = "1.1.8"
crc32fast = "1.4.2"
assert_cmd = "2.1.1"
proptest = "1.9.0"
color-backtrace = "0.7.2"
gitlab = "0.1801.0"
mimalloc = {version = "0.1.48", features = ["override"]}
thread_local = "1.1.9"
bloomfilter = "3.0.1"
uuid = "1.17.0"
urlencoding = "2.1.3"
rand = "0.9.1"
percent-encoding = "2.3.1"
trust-dns-resolver = { version = "0.23.2", default-features = false, features = ["tokio-runtime"] }
uuid = "1.19.0"
rand = "0.9.2"
percent-encoding = "2.3.2"
atty = "0.2.14"
self_update = { version = "0.42.0", default-features = false, features = ["rustls", "archive-tar", "archive-zip", "compression-flate2"] }
semver = "1.0.26"
semver = "1.0.27"
globset = "0.4.18"
jsonwebtoken = { version = "10.2.0", features = ["aws-lc-rs"] }
ipnet = "2.11.0"
gouqi = { version = "0.20.0", features = ["async"] }
oci-client = { version = "0.15", default-features = false, features = ["rustls-tls"] }
walkdir = "2.5.0"
p256 = "0.13.2"
ed25519-dalek = { version = "2.2", features = ["pkcs8"] }
aws-sdk-s3 = "1.117.0"
aws-sdk-iam = "1.101.0"
aws-sdk-ec2 = "1.196.0"
aws-sdk-dynamodb = "1.101.0"
aws-sdk-lambda = "1.111.0"
aws-sdk-kms = "1.97.0"
aws-sdk-secretsmanager = "1.96.0"
gcloud-storage = { version = "1.1.1", default-features = false, features = [
"rustls-tls",
"auth",
"jwt-aws-lc-rs",
] }
tokei = "12.1.2"
crc32fast = "1.5.0"
[target.'cfg(not(windows))'.dependencies]
sha1 = { version = "0.10.6", features = ["asm"] }
[target.'cfg(windows)'.dependencies]
sha1 = "0.10.6"
[dependencies.tikv-jemallocator]
version = "0.6"
optional = true
[features]
default = ["use-mimalloc"]
use-mimalloc = ["mimalloc/override"]
@ -174,15 +225,16 @@ use-jemalloc = ["tikv-jemallocator"]
system-alloc = [] # forces System allocator
[dev-dependencies]
pretty_assertions = "1.3"
pretty_assertions = "1.4"
temp-env = "0.3.6"
wiremock = "0.6.2"
git2 = "0.20.2"
wiremock = "0.6.5"
git2 = "0.20.3"
rand_chacha = "0.9.0"
testcontainers = "0.15.0"
[profile.release]
debug = false
strip = "debuginfo"
strip = true #"debuginfo"
opt-level = 3 # Maximum optimization for performance
lto = true # Enable Link Time Optimization
codegen-units = 1 # Optimize for size but slower compilation

View file

@ -1,8 +1,7 @@
SHELL := /usr/bin/env bash
.SHELLFLAGS := -eu -o pipefail -c
# Detect project name from Cargo.toml
PROJECT_NAME := $(shell grep '^name' Cargo.toml | cut -d '"' -f 2)
PROJECT_NAME := kingfisher
# Determine OS and whether to use gtar on darwin
OS := $(shell uname)
@ -25,6 +24,7 @@ endif
ifeq ($(OS),darwin)
export HOMEBREW_NO_INSTALL_CLEANUP=1
export HOMEBREW_NO_ENV_HINTS=1
export HOMEBREW_NO_AUTO_UPDATE=1
endif
# detect host architecture and map to our target suffixes
@ -110,11 +110,11 @@ setup-zig:
ubuntu-x64: setup-zig # ensures Zig & cargo-zigbuild exist
@echo "Checking Rust toolchain…"
@$(MAKE) check-rust || { \
echo "🦀 Installing Rust 1.85.0 …"; \
echo "🦀 Installing Rust 1.90.0 …"; \
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y; \
. $$HOME/.cargo/env; \
rustup toolchain install 1.85.0; \
rustup default 1.85.0; \
rustup toolchain install 1.90.0; \
rustup default 1.90.0; \
}
@echo "📦 Installing build dependencies (musl, cmake, etc.)…"
@ -150,11 +150,11 @@ ubuntu-x64: setup-zig # ensures Zig & cargo-zigbuild exist
ubuntu-arm64: setup-zig # ensures Zig & cargo-zigbuild exist
@echo "Checking Rust toolchain…"
@$(MAKE) check-rust || { \
echo "🦀 Installing Rust 1.85.0 …"; \
echo "🦀 Installing Rust 1.90.0 …"; \
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y; \
. $$HOME/.cargo/env; \
rustup toolchain install 1.85.0; \
rustup default 1.85.0; \
rustup toolchain install 1.90.0; \
rustup default 1.90.0; \
}
@echo "📦 Installing build dependencies (musl, cmake, etc.)…"
@ -183,14 +183,15 @@ ubuntu-arm64: setup-zig # ensures Zig & cargo-zigbuild exist
$(MAKE) list-archives
darwin-arm64:
@echo "Checking Rust for darwin-arm64..."
@$(MAKE) check-rust || ( \
echo "Rust not found or out-of-date. Installing via Homebrew..." && \
brew install rust \
)
@brew install boost cmake gcc libpcap pkg-config ragel sqlite coreutils gnu-tar || true
@brew list cmake >/dev/null 2>&1 || brew install cmake
@brew list boost >/dev/null 2>&1 || brew install boost
@brew install gcc libpcap pkg-config ragel sqlite coreutils gnu-tar
@rustup target add aarch64-apple-darwin
cargo build --release --target aarch64-apple-darwin --features system-alloc
@cd target/aarch64-apple-darwin/release && \
@ -206,13 +207,18 @@ darwin-arm64:
fi
$(MAKE) list-archives
darwin-dev:
cargo build --profile=dev --target aarch64-apple-darwin --features system-alloc
darwin-x64:
@echo "Checking Rust for darwin-x64..."
@$(MAKE) check-rust || ( \
echo "Rust not found or out-of-date. Installing via Homebrew..." && \
brew install rust \
)
@brew install boost cmake gcc libpcap pkg-config ragel sqlite coreutils gnu-tar || true
@brew list cmake >/dev/null 2>&1 || brew install cmake
@brew list boost >/dev/null 2>&1 || brew install boost
@brew install gcc libpcap pkg-config ragel sqlite coreutils gnu-tar
@rustup target add x86_64-apple-darwin
source $$HOME/.cargo/env && cargo build --release --target x86_64-apple-darwin --features system-alloc
@cd target/x86_64-apple-darwin/release && \
@ -242,7 +248,7 @@ endif
linux-x64: check-docker create-dockerignore
@mkdir -p target/release
docker run --platform linux/amd64 --rm \
-v "$$(pwd):/src" -w /src rust:1.85-alpine sh -eu -c '\
-v "$$(pwd):/src" -w /src rust:1.90-alpine sh -eu -c '\
apk add --no-cache \
musl-dev \
gcc g++ make cmake pkgconfig \
@ -253,7 +259,7 @@ linux-x64: check-docker create-dockerignore
patch perl ragel && \
git openssl-dev curl && \
\
cargo test --workspace --all-targets --release ; \
cargo test --workspace --all-targets ; \
\
rustup target add x86_64-unknown-linux-musl && \
\
@ -262,24 +268,16 @@ linux-x64: check-docker create-dockerignore
\
cargo build --release --target x86_64-unknown-linux-musl && \
cd target/x86_64-unknown-linux-musl/release && \
find "./$(PROJECT_NAME)" -type f -executable \
-not -name "*.d" -not -name "*.rlib" \
-exec sha256sum {} \; > CHECKSUM.txt \
sha256sum kingfisher > CHECKSUM.txt && \
tar -czf /src/target/release/kingfisher-linux-x64.tgz \
kingfisher CHECKSUM.txt \
'
@cd target/release && \
rm -rf $(PROJECT_NAME)-linux-x64.tgz && \
cp ../x86_64-unknown-linux-musl/release/$(PROJECT_NAME) . && \
cp ../x86_64-unknown-linux-musl/release/CHECKSUM.txt CHECKSUM-linux-x64.txt && \
tar --no-xattrs -czf $(PROJECT_NAME)-linux-x64.tgz \
$(PROJECT_NAME) CHECKSUM-linux-x64.txt && \
rm $(PROJECT_NAME) && \
sha256sum $(PROJECT_NAME)-linux-x64.tgz >> CHECKSUM-linux-x64.txt
$(MAKE) list-archives
linux-arm64: check-docker create-dockerignore
@mkdir -p target/release
docker run --platform linux/arm64 --rm \
-v "$$(pwd):/src" -w /src rust:1.85-alpine sh -eu -c '\
-v "$$(pwd):/src" -w /src rust:1.90-alpine sh -eu -c '\
apk add --no-cache \
musl-dev \
gcc g++ make cmake pkgconfig \
@ -292,7 +290,7 @@ linux-arm64: check-docker create-dockerignore
\
rustup target add aarch64-unknown-linux-musl && \
\
cargo test --workspace --all-targets --release ; \
cargo test --workspace --all-targets ; \
\
export PKG_CONFIG_ALLOW_CROSS=1 ; \
export RUSTFLAGS="-C target-feature=+crt-static" ; \
@ -300,18 +298,10 @@ linux-arm64: check-docker create-dockerignore
cargo build --release --target aarch64-unknown-linux-musl && \
\
cd target/aarch64-unknown-linux-musl/release && \
find "./$(PROJECT_NAME)" -type f -executable \
-not -name "*.d" -not -name "*.rlib" \
-exec sha256sum {} \; > CHECKSUM.txt \
sha256sum kingfisher > CHECKSUM.txt && \
tar -czf /src/target/release/kingfisher-linux-arm64.tgz \
kingfisher CHECKSUM.txt \
'
@cd target/release && \
rm -rf $(PROJECT_NAME)-linux-arm64.tgz && \
cp ../aarch64-unknown-linux-musl/release/$(PROJECT_NAME) . && \
cp ../aarch64-unknown-linux-musl/release/CHECKSUM.txt CHECKSUM-linux-arm64.txt && \
tar --no-xattrs -czf $(PROJECT_NAME)-linux-arm64.tgz \
$(PROJECT_NAME) CHECKSUM-linux-arm64.txt && \
rm $(PROJECT_NAME) && \
sha256sum $(PROJECT_NAME)-linux-arm64.tgz >> CHECKSUM-linux-arm64.txt
$(MAKE) list-archives
@ -366,6 +356,13 @@ all: linux darwin
@echo -e "\nCombined Checksums:"
@cat target/release/CHECKSUMS.txt
dockerfile:
# Build for the host architecture (default)
docker build -f docker/Dockerfile -t kingfisher:latest .
# Crossbuild for arm64 from an x64 machine
docker buildx build -f docker/Dockerfile --platform linux/arm64 -t kingfisher:arm64 .
list-archives:
@echo -e "\n=== Built archives ==="
@found=0; \
@ -391,7 +388,7 @@ check-rust:
echo "Rust not found."; \
exit 1; \
fi; \
required=1.85.0; \
required=1.90.0; \
if [ $$(printf '%s\n' "$$required" "$$version" | sort -V | head -n1) != "$$required" ]; then \
echo "Rust version $$version is older than required $$required."; \
exit 1; \
@ -424,6 +421,3 @@ notices:
@echo "Generating third-party notices..."
@cargo install cargo-bundle-licenses
@cargo bundle-licenses --format yaml --output THIRD_PARTY_NOTICES
evergreen-patch:
@evergreen patch --project kingfisher --variants all --tasks build

17
NOTICE
View file

@ -1,5 +1,14 @@
NOTICE file corresponding to Section 4 (d) of the Apache License, Version 2.0
--------------------------------------------------------------------
Notices for Kingfisher
--------------------------------------------------------------------
Copyright 2025 MongoDB, Inc.
https://www.mongodb.com
Source repository: https://github.com/mongodb/kingfisher
--------------------------------------------------------------------
Upstream notices
--------------------------------------------------------------------
@ -21,11 +30,3 @@ distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--------------------------------------------------------------------
Additional notices for Kingfisher
--------------------------------------------------------------------
Copyright 2025 MongoDB, Inc.
https://www.mongodb.com
Source repository: https://github.com/mongodb/kingfisher

1460
README.md

File diff suppressed because it is too large Load diff

View file

@ -1,120 +1,133 @@
@echo off
REM This script builds a Windows x64 release binary and creates a tarball with checksum.
REM It requires vcpkg to be installed at root of C: drive (https://github.com/microsoft/vcpkg).
REM This script will install Rust (using chocolatey) if it is not already installed.
REM
REM Call with -force to clone and bootstrap vcpkg if it is not found
REM
REM ============================================================================
REM buildwin.bat — Windows x64 release build + archive for Kingfisher
REM - Forces a single vcpkg root (C:\vcpkg) and avoids VS-integrated vcpkg
REM - Installs Hyperscan for x64-windows-static into that root
REM - Verifies hs.lib is present before building, then builds & packages
REM ============================================================================
setlocal
REM Set your Cargo project name manually here if desired:
set "PROJECT_NAME=kingfisher"
set "FORCE_VCPKG=0"
if /I "%~1"=="-force" set "FORCE_VCPKG=1"
if "%VCPKG_TRIPLET%"=="" set "VCPKG_TRIPLET=x64-windows-static"
REM Optional check for OS:
REM --- Ensure Windows ---
if NOT "%OS%"=="Windows_NT" (
echo This script must be run on Windows.
exit /b 1
echo This script must be run on Windows.
exit /b 1
)
REM --- Find MSVC / init toolchain ---
if "%VCINSTALLDIR%"=="" (
echo VCINSTALLDIR not set - attempting auto-detection…
for %%P in (
"C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC"
"C:\Program Files\Microsoft Visual Studio\2022\Professional\VC"
"C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC"
"C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC"
) do (
if exist "%%~P\Auxiliary\Build\vcvars64.bat" (
set "VCINSTALLDIR=%%~P"
echo Found Visual C++ Build Tools at: %%~P
goto :vc_found
)
echo VCINSTALLDIR not set - attempting auto-detection…
for %%P in (
"C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC"
"C:\Program Files\Microsoft Visual Studio\2022\Professional\VC"
"C:\Program Files\Microsoft Visual Studio\2022\Community\VC"
"C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC"
"C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC"
) do (
if exist "%%~P\Auxiliary\Build\vcvars64.bat" (
set "VCINSTALLDIR=%%~P"
echo Found Visual C++ Build Tools at: %%~P
goto :vc_found
)
echo ERROR: Could not find a suitable Visual Studio installation.
echo Install “Desktop development with C++” or set VCINSTALLDIR.
exit /b 1
)
echo ERROR: Could not find a suitable Visual Studio installation.
echo Install "Desktop development with C++" or set VCINSTALLDIR.
exit /b 1
)
:vc_found
REM Strip trailing backslash if present
if "%VCINSTALLDIR:~-1%"=="\" set "VCINSTALLDIR=%VCINSTALLDIR:~0,-1%"
echo Initialising MSVC environment…
call "%VCINSTALLDIR%\Auxiliary\Build\vcvars64.bat" || (
echo ERROR: Failed to initialise MSVC toolchain.
exit /b 1
echo ERROR: Failed to initialise MSVC toolchain.
exit /b 1
)
REM Locate vcpkg.exe
where vcpkg.exe >nul 2>nul
if %ERRORLEVEL% NEQ 0 (
if exist "%HOMEDRIVE%\vcpkg\vcpkg.exe" (
set "VCPKG_EXE=%HOMEDRIVE%\vcpkg\vcpkg.exe"
echo Found vcpkg at: %VCPKG_EXE%
) else (
if "%~1"=="-force" (
echo Cloning and bootstrapping vcpkg...
if exist "%HOMEDRIVE%\vcpkg" (
rmdir /s /q "%HOMEDRIVE%\vcpkg"
)
git clone https://github.com/microsoft/vcpkg.git "%HOMEDRIVE%\vcpkg"
pushd "%HOMEDRIVE%\vcpkg"
dir
call .\bootstrap-vcpkg.bat
set "VCPKG_EXE=%CD%\vcpkg.exe"
popd
echo Installed vcpkg at: %VCPKG_EXE%
) else (
echo ERROR: vcpkg not found. Please install it or re-run script with -force.
exit /b 1
)
)
) else (
for /f "tokens=*" %%i in ('where vcpkg.exe') do (
set "VCPKG_EXE=%%i"
goto :found_vcpkg
)
:found_vcpkg
echo Found vcpkg at: %VCPKG_EXE%
)
REM --- CRITICAL: Force our own vcpkg root (ignore VS-integrated vcpkg) ----
set "VCPKG_ROOT=C:\vcpkg"
set "VCPKG_DISABLE_METRICS=1"
REM Check if LOCALAPPDATA starts with a drive letter, if not set it to APPDATA
REM --- Ensure LOCALAPPDATA sane for tools that use it ---
if /I not "%LOCALAPPDATA:~1,1%"==":" (
echo LOCALAPPDATA does not start with a drive letter. Setting it to APPDATA.
set "LOCALAPPDATA=%APPDATA%"
echo LOCALAPPDATA not drive-qualified; using APPDATA instead.
set "LOCALAPPDATA=%APPDATA%"
)
echo Installing hyperscan via vcpkg...
set
"%HOMEDRIVE%\vcpkg\vcpkg.exe" install hyperscan:x64-windows
set "LIBHS_NO_PKG_CONFIG=1"
REM --- Find/Install vcpkg into C:\vcpkg ---
call :ensure_vcpkg || exit /b 1
echo Using vcpkg root: "%VCPKG_ROOT%"
echo vcpkg executable: "%VCPKG_EXE%"
REM Point vectorscan-rs-sys at the Hyperscan install from vcpkg
set "HYPERSCAN_ROOT=%HOMEDRIVE%\vcpkg\installed\x64-windows"
set "LIB=%HYPERSCAN_ROOT%\lib;%LIB%"
REM --- Install Hyperscan into THIS root ---
echo Installing Hyperscan (%VCPKG_TRIPLET%) via vcpkg...
pushd "%VCPKG_ROOT%" || (
echo ERROR: Cannot cd into "%VCPKG_ROOT%".
exit /b 1
)
"%VCPKG_EXE%" --vcpkg-root "%VCPKG_ROOT%" install hyperscan:%VCPKG_TRIPLET% || (
echo ERROR: vcpkg install failed.
popd
exit /b 1
)
popd
REM --- Point build to installed Hyperscan ---
set "LIBHS_NO_PKG_CONFIG=1"
set "HYPERSCAN_ROOT=%VCPKG_ROOT%\installed\%VCPKG_TRIPLET%"
set "HS_LIB_DIR=%HYPERSCAN_ROOT%\lib"
set "LIB=%HS_LIB_DIR%;%LIB%"
set "INCLUDE=%HYPERSCAN_ROOT%\include;%INCLUDE%"
REM Check for Rust, install if missing
REM Verify hs.lib (or libhs.lib)
set "HS_LIB_FILE=%HS_LIB_DIR%\hs.lib"
if not exist "%HS_LIB_FILE%" if exist "%HS_LIB_DIR%\libhs.lib" set "HS_LIB_FILE=%HS_LIB_DIR%\libhs.lib"
echo.
echo [DIAG] HYPERSCAN_ROOT = %HYPERSCAN_ROOT%
echo [DIAG] HS_LIB_DIR = %HS_LIB_DIR%
dir /b "%HS_LIB_DIR%\hs.lib" 2>nul
dir /b "%HS_LIB_DIR%\libhs.lib" 2>nul
if not exist "%HS_LIB_FILE%" (
echo ERROR: Hyperscan library not found under "%HS_LIB_DIR%".
echo Check that hyperscan:%VCPKG_TRIPLET% installed correctly.
exit /b 1
)
REM --- Ensure Rust/CMake present (fallback for local runs) ---
where rustc.exe >nul 2>nul
if %ERRORLEVEL% NEQ 0 (
echo Installing Rust...
choco install rust-ms -y
choco install cmake -y --installargs "ADD_CMAKE_TO_PATH=System"
call refreshenv
echo Installing Rust via Chocolatey...
choco install rust-ms -y
choco install cmake -y --installargs "ADD_CMAKE_TO_PATH=System"
call refreshenv
) else (
echo Rust is already installed.
echo Rust is already installed.
)
echo Building for Windows x64...
REM --- Build (static CRT) ---
if "%RUSTFLAGS%"=="" (
set "RUSTFLAGS=-C target-feature=+crt-static"
) else (
echo Using existing RUSTFLAGS: %RUSTFLAGS%
)
echo.
echo Building static Windows x64 binary...
cargo build --release --target x86_64-pc-windows-msvc || (
echo Cargo build failed.
exit /b 1
echo Cargo build failed.
exit /b 1
)
REM --- Package & checksums ---
echo Generating CHECKSUM.txt...
powershell -Command ^
"Get-FileHash .\target\x86_64-pc-windows-msvc\release\%PROJECT_NAME%.exe -Algorithm SHA256 | Out-File .\target\x86_64-pc-windows-msvc\release\CHECKSUM.txt"
"$h=Get-FileHash '.\target\x86_64-pc-windows-msvc\release\%PROJECT_NAME%.exe' -Algorithm SHA256;" ^
"$l='{0} {1}' -f $h.Hash,(Split-Path -Leaf $h.Path);" ^
"Set-Content '.\target\x86_64-pc-windows-msvc\release\CHECKSUM.txt' $l"
if not exist "target\release" mkdir "target\release"
copy /Y "target\x86_64-pc-windows-msvc\release\%PROJECT_NAME%.exe" "target\release\" >nul
@ -126,15 +139,60 @@ if exist "%PROJECT_NAME%-windows-x64.zip" del /f /q "%PROJECT_NAME%-windows-x64.
powershell -Command "Compress-Archive -Path '%PROJECT_NAME%.exe','CHECKSUM-windows-x64.txt' -DestinationPath '%PROJECT_NAME%-windows-x64.zip' -Force"
if exist "%PROJECT_NAME%-windows-x64.zip" (
REM -- append the ZIPs SHA-256 to the existing checksum file ----
certutil -hashfile "%PROJECT_NAME%-windows-x64.zip" SHA256 >> "CHECKSUM-windows-x64.txt"
echo Created: %PROJECT_NAME%-windows-x64.zip
powershell -Command ^
"$h=Get-FileHash '.\%PROJECT_NAME%-windows-x64.zip' -Algorithm SHA256;" ^
"$l='{0} {1}' -f $h.Hash,(Split-Path -Leaf $h.Path);" ^
"Add-Content '.\CHECKSUM-windows-x64.txt' $l"
echo Created: %PROJECT_NAME%-windows-x64.zip
) else (
echo ERROR: Archive not created.
echo ERROR: Archive not created.
exit /b 1
)
echo Archives in target\release:
dir /b *.zip 2>nul || echo None found.
endlocal
goto :eof
REM ====================== helpers ============================================
:ensure_vcpkg
REM If vcpkg.exe already exists under our chosen root, use it
if exist "%VCPKG_ROOT%\vcpkg.exe" (
set "VCPKG_EXE=%VCPKG_ROOT%\vcpkg.exe"
echo Found vcpkg at: %VCPKG_EXE%
exit /b 0
)
REM If on PATH (and not the VS one), still force install into C:\vcpkg
where vcpkg.exe >nul 2>nul
if %ERRORLEVEL%==0 (
for /f "tokens=*" %%i in ('where vcpkg.exe') do (
set "VCPKG_EXE=%%i"
)
echo Found vcpkg on PATH: %VCPKG_EXE%
)
REM Clone/bootstrap into our root if missing
if not exist "%VCPKG_ROOT%" mkdir "%VCPKG_ROOT%"
if "%FORCE_VCPKG%"=="1" if exist "%VCPKG_ROOT%" rmdir /s /q "%VCPKG_ROOT%" & mkdir "%VCPKG_ROOT%"
if not exist "%VCPKG_ROOT%\vcpkg.exe" (
echo Cloning and bootstrapping vcpkg into "%VCPKG_ROOT%"...
git clone https://github.com/microsoft/vcpkg.git "%VCPKG_ROOT%" || (
echo ERROR: Failed to clone vcpkg repository.
exit /b 1
)
pushd "%VCPKG_ROOT%"
call .\bootstrap-vcpkg.bat || (
popd
echo ERROR: Failed to bootstrap vcpkg.
exit /b 1
)
set "VCPKG_EXE=%VCPKG_ROOT%\vcpkg.exe"
popd
echo Installed vcpkg at: %VCPKG_EXE%
) else (
set "VCPKG_EXE=%VCPKG_ROOT%\vcpkg.exe"
)
exit /b 0

View file

@ -2,11 +2,13 @@ rules:
- name: Adafruit IO Key
id: kingfisher.adafruitio.1
pattern: |
(?xi)
(?x)
\b
(
aio_
[A-Z0-9]{28}
[a-zA-Z]{4}
[0-9]{2}
[a-zA-Z0-9]{22}
)
\b
min_entropy: 3.5
@ -28,4 +30,4 @@ rules:
type: StatusMatch
- type: WordMatch
words:
- '"username"'
- '"username"'

View file

@ -6,11 +6,13 @@ rules:
\b
adobe
(?:.|[\n\r]){0,32}?
\b
\b
(
[A-F0-9]{32}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.5
examples:
- adobeKey = 1a2b3c4d5e6f7890abcdef1234567890
@ -44,6 +46,7 @@ rules:
\b
adobe
(?:.|[\n\r]){0,64}?
\b
(
[a-z0-9]{12}
)
@ -60,7 +63,7 @@ rules:
(
p8e-[A-Z0-9-]{32}
)
(?:[^A-Z0-9-]|$)
(?:[^A-Z0-9-])
min_entropy: 3.5
examples:
- |

View file

@ -2,12 +2,14 @@ rules:
- name: Age Recipient (X25519 public key)
id: kingfisher.age.1
pattern: |
(?xi)
\b
(?x)
(
age1[0-9a-z]{58}
age1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{58}
)
\b
pattern_requirements:
min_digits: 2
min_lowercase: 1
min_entropy: 3.3
confidence: medium
examples:
@ -20,12 +22,10 @@ rules:
- name: Age Identity (X22519 secret key)
id: kingfisher.age.2
pattern: |
(?xi)
\b
(?x)
(
AGE-SECRET-KEY-1[0-9A-Z]{58}
AGE-SECRET-KEY-1[QPZRY9X8GF2TVDW0S3JN54KHCE6MUA7L]{58}
)
\b
min_entropy: 3.3
confidence: medium
examples:

48
data/rules/ai21.yml Normal file
View file

@ -0,0 +1,48 @@
rules:
- name: AI21 Studio API Key
id: kingfisher.ai21studio.1
pattern: |
(?xi)
\b
ai21
(?:.|[\n\r]){0,32}?
\b
(
[0-9a-f]{8}
-
[0-9a-f]{4}
-
[0-9a-f]{4}
-
[0-9a-f]{4}
-
[0-9a-f]{12}
)
\b
pattern_requirements:
min_digits: 2
min_uppercase: 1
min_lowercase: 1
min_entropy: 3.2
confidence: medium
examples:
- ai21 = 90cd6930-a9ae-4f15-8da0-dc1bbcd814b9
- 'ai21_key: befa7ec1-1129-4713-8e92-bb53d1a4f632'
- ai21_token = ec2e14e9-0309-459b-ba76-1e59e1f42b87
references:
- https://docs.ai21.com/reference/authentication
- https://docs.ai21.com/reference/manage-library-ref/list-library-files
validation:
type: Http
content:
request:
method: GET
url: https://api.ai21.com/studio/v1/library/files
headers:
Authorization: Bearer {{ TOKEN }}
Accept: application/json
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]

View file

@ -5,14 +5,16 @@ rules:
(?xi)
\b
airbrake
(?:.|[\n\r]){0,16}?
(?:SECRET|PRIVATE|ACCESS|KEY|TOKEN)
(?:.|[\n\r]){0,16}?
(?:.|[\n\r]){0,32}?
(
[A-Z0-9-]{40}
)
\b
min_entropy: 4.5
\b
pattern_requirements:
min_digits: 2
min_uppercase: 1
min_lowercase: 1
min_entropy: 4.0
confidence: medium
examples:
- airbrake secretKey= a1B2c3D4e5F6g7H8i9J0k1L2m3N4o5P6q7R8s9T0

View file

@ -2,15 +2,19 @@ rules:
- name: Airtable Personal Access Token
id: kingfisher.airtable.1
pattern: |
(?xi)
(?x)
\b
(
pat
[a-z0-9]{14}
[A-Za-z0-9]{14}
\.
[a-z0-9]{62,66}
[a-f0-9]{64}
)
\b
\b
pattern_requirements:
min_digits: 2
min_uppercase: 1
min_lowercase: 1
min_entropy: 3.3
confidence: medium
examples:
@ -37,7 +41,6 @@ rules:
id: kingfisher.airtable.2
pattern: |
(?xi)
\b
(
[A-Z0-9]+\.v1\.[A-Z0-9_-]+\.[a-f0-9]+
)

View file

@ -2,15 +2,18 @@ rules:
- name: Aiven API Key
id: kingfisher.aiven.1
pattern: |
(?xi)
(?xi)
aiven
(?:.|[\n\r]){0,32}?
(?:SECRET|PRIVATE|ACCESS|KEY|TOKEN)
(?:.|[\n\r]){0,32}?
\b
(
[a-z0-9/+=]{372}
)
(?:[^A-Za-z0-9/+=])
pattern_requirements:
min_digits: 2
min_uppercase: 1
min_lowercase: 1
min_entropy: 3.3
confidence: medium
examples:

46
data/rules/alchemy.yml Normal file
View file

@ -0,0 +1,46 @@
rules:
- name: Alchemy API Key
id: kingfisher.alchemy.1
pattern: |
(?xi)
\balchemy
(?:.|[\n\r]){0,96}?
(?:
/v2/
|
api[_-]?key|key|token|secret|url|endpoint|rpc
)
(?:.|[\n\r]){0,96}?
\b
(
[A-Za-z0-9_-]{24,64}
)
\b
pattern_requirements:
min_digits: 4
min_entropy: 3.5
confidence: medium
examples:
- alchemy_key="PajdHzB75s1V_7aldcQ6XbodqDCWMC7m"
- https://eth-mainnet.alchemyapi.io/v2/PajdHzB75s1V_7aldcQ6XbodqDCWMC7m
- https://eth-goerli.alchemyapi.io/v2/AGtF3w2AsccY_bfsdDleaVRehW2xGS7W
references:
- https://www.alchemy.com/rpc/ethereum
- https://www.alchemy.com/docs/reference/nft-api-endpoints/nft-api-endpoints/nft-ownership-endpoints/get-nf-ts-for-owner-v-3
validation:
type: Http
content:
request:
method: GET
url: "https://eth-mainnet.g.alchemy.com/nft/v3/{{ TOKEN }}/getNFTsForOwner?owner=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
headers:
Accept: application/json
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]
- type: WordMatch
words: ['"ownedNfts"']
- type: WordMatch
negative: true
words: ['"error"']

View file

@ -5,11 +5,13 @@ rules:
(?xi)
algolia
(?:.|[\n\r]){0,32}?
\b
(
[a-z0-9]{32}
)
\b
pattern_requirements:
min_digits: 2
min_lowercase: 1
min_entropy: 3.5
confidence: medium
examples:
@ -38,11 +40,12 @@ rules:
(?xi)
algolia
(?:.|[\n\r]){0,16}?
\b
(
[A-Z0-9]{10}
)
\b
\b
pattern_requirements:
min_digits: 2
min_entropy: 2.0
visible: false
confidence: medium

View file

@ -3,11 +3,14 @@ rules:
id: kingfisher.alibabacloud.1
pattern: |
(?xi)
\b
(
LTAI[a-z0-9]{17,21}
)
\b
pattern_requirements:
min_digits: 2
min_uppercase: 1
min_lowercase: 1
min_entropy: 4.0
confidence: medium
visible: false
@ -21,11 +24,9 @@ rules:
\b
alibaba
(?:.|[\n\r]){0,32}?
\b
(
[a-z0-9]{30}
)
\b
min_entropy: 4.2
confidence: medium
examples:

View file

@ -2,23 +2,22 @@ rules:
- name: Anthropic API Key
id: kingfisher.anthropic.1
pattern: |
(?xi)
\b
(
(?xi)
(
sk-ant-api
\d{2,4}
-
[\w\-]{93}
AA
)
\b
)
pattern_requirements:
min_digits: 2
min_uppercase: 1
min_lowercase: 1
min_entropy: 3.3
confidence: medium
examples:
- sk-ant-api668-Clm512odot9WDD7itfUU9R880nefA1EtYZDbpE-C9b0XQEWpqFKf9DQUo03vOfXl16oSmyar1CLF1SzV3YzpZJ6bahcpLAA
categories:
- api
- secret
references:
- https://docs.anthropic.com/claude/reference/authentication
validation:
@ -46,5 +45,5 @@ rules:
- report_response: true
- type: WordMatch
words:
- '"type":"invalid_request_error"'
- '"type":"message"'
url: https://api.anthropic.com/v1/messages

View file

@ -18,8 +18,12 @@ rules:
[0-9a-z]{4}
-
[0-9a-z]{12}
)
\b
)
\b
pattern_requirements:
min_digits: 2
min_uppercase: 1
min_lowercase: 1
min_entropy: 3.5
confidence: medium
examples:

38
data/rules/apify.yml Normal file
View file

@ -0,0 +1,38 @@
rules:
- name: Apify API Token
id: kingfisher.apify.1
pattern: |
(?xi)
(
apify_api_[A-Z0-9]{34,38}
)
\b
pattern_requirements:
min_digits: 2
min_uppercase: 1
min_lowercase: 1
confidence: medium
min_entropy: 3.5
validation:
type: Http
content:
request:
method: GET
url: "https://api.apify.com/v2/users/me"
headers:
Authorization: "Bearer {{ TOKEN }}"
response_matcher:
- type: StatusMatch
status: [200]
- type: WordMatch
words:
- '"data"'
- '"username"'
match_all_words: true
references:
- https://docs.gitguardian.com/secrets-detection/secrets-detection-engine/detectors/specifics/apify_token
- https://docs.apify.com/api/v2#/reference/users/user-object/get-user-public-profile-or-me
- https://docs.apify.com/api/v2/users-me-get
examples:
- "apify_api_NcjXcxEz2XL1irjppyWSHvjghalQOd1LXOHv"
- "apify_api_9uyewBxQUF1EXWdKVc4lNaTSM461Ls4oQouz"

52
data/rules/apollo.yml Normal file
View file

@ -0,0 +1,52 @@
rules:
- name: Apollo API Key
id: kingfisher.apollo.1
pattern: |
(?xi)
\b
apollo
(?:.|[\n\r]){0,16}?
(?:SECRET|PRIVATE|ACCESS|KEY|TOKEN)
(?:.|[\n\r]){0,32}?
\b
(
[A-Z0-9_-]{22}
)
\b
pattern_requirements:
min_digits: 2
min_uppercase: 1
min_lowercase: 1
min_entropy: 3.0
confidence: medium
examples:
- 'APOLLO_API_KEY="ZNh-14foqIiscbz24oKwww"'
- apollo_key=8ku3EoDJxz8fOSCdxYozdA
- apollo.io api_key oD8GCL8MNZIyg0tzeSDuhw
references:
- https://docs.apollo.io/reference/people-api-search
validation:
type: Http
content:
request:
method: POST
url: "https://api.apollo.io/api/v1/mixed_people/api_search"
headers:
accept: "application/json"
content-type: "application/json"
x-api-key: "{{ TOKEN }}"
body: |
{"page":1,"per_page":1}
response_matcher:
- report_response: true
- type: StatusMatch
status: [200, 403]
- type: WordMatch
words:
- '"total_entries"'
- '"API_INACCESSIBLE"'
match_all_words: false
- type: WordMatch
negative: true
words:
- '"Invalid access credentials"'

View file

@ -8,6 +8,10 @@ rules:
AKC[A-Z0-9]{64,74}
)
\b
pattern_requirements:
min_digits: 2
min_uppercase: 1
min_lowercase: 1
min_entropy: 3.5
confidence: medium
examples:
@ -36,21 +40,55 @@ rules:
- name: Artifactory JFrog URL
id: kingfisher.artifactory.2
pattern: |
(?xi)
\b
(
(?xi)
\b
(
[a-z0-9]
(?:
[a-z0-9\-]{0,61}
[a-z0-9]
)?
\.jfrog\.io
)
\b
min_entropy: 3.5
)
\b
min_entropy: 2.5
visible: false
confidence: medium
examples:
- mycompany.jfrog.io
- my-company-name.jfrog.io
- a.jfrog.io
- a.jfrog.io
- name: Artifactory Identity Reference Token
id: kingfisher.artifactory.3
pattern: |
(?xi)
\b
(
cmVmd[A-Z0-9]{59}
)
\b
pattern_requirements:
min_digits: 2
min_uppercase: 1
min_lowercase: 1
min_entropy: 3.5
confidence: medium
examples:
- export HOMEBREW_ARTIFACTORY_API_REFERENCE_TOKEN=cmVmdawqkxT1EE4bMepW0zmTVmBYYdv264WVufgipR9CQAW2xwSnY4CTKap8H5u0
validation:
type: Http
content:
request:
headers:
Authorization: 'Bearer {{ TOKEN }}'
method: GET
response_matcher:
- report_response: true
- status:
- 200
type: StatusMatch
url: https://{{ JFROGURL }}/artifactory/api/repositories
depends_on_rule:
- rule_id: "kingfisher.artifactory.2"
variable: JFROGURL

View file

@ -6,13 +6,13 @@ rules:
\b
asana
(?:.|[\n\r]){0,32}?
(?:SECRET|PRIVATE|ACCESS|KEY|TOKEN)
(?:.|[\n\r]){0,32}?
\b
(
[0-9]{16}
)
\b
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.5
confidence: medium
examples:
@ -32,35 +32,35 @@ rules:
(
[a-z0-9]{30,40}
)
\b
\b
pattern_requirements:
min_digits: 2
min_uppercase: 1
min_lowercase: 1
min_entropy: 3.5
confidence: medium
examples:
- "asana :'20c2F0d03201af478ca1aBE9515A1A4FEfb'"
- ASANA_PAT = 1234567890abcdef1234567890abcdef12
- name: Asana OAuth / Personal Access Token
- name: Asana OAuth / Personal Access Token (Legacy)
id: kingfisher.asana.3
pattern: |
(?xi)
\b
(?xi)
\b
asana
(?:.|[\n\r]){0,64}?
\b
(
[01]{1,}
\/
[0-9a-f]{16,32}
(?:
:
[a-z0-9]{32,64}
)?
)
\b
\b
(
0/
[a-f0-9]{32}
)
\b
pattern_requirements:
min_digits: 4
min_entropy: 3.5
confidence: medium
examples:
- asana_pat = 1/1248440223456784:d3d7e52e5c4a5d4c9bc424d2d882324d
- asana token = 0/d6f1e29e5b4b4d8c9bb419b2d882154d
categories:
- api
@ -83,4 +83,94 @@ rules:
- 'data:'
- email
- name
url: https://app.asana.com/api/1.0/users/me
url: https://app.asana.com/api/1.0/users/me
- name: Asana OAuth / Personal Access Token (V1)
id: kingfisher.asana.4
pattern: |
(?xi)
\b
asana
(?:.|[\n\r]){0,64}?
\b
(
1/
[0-9]{14,16}
:
[a-f0-9]{32}
)
\b
pattern_requirements:
min_digits: 4
min_entropy: 3.5
confidence: medium
examples:
- asana_pat = 1/1248440223456784:d3d7e52e5c4a5d4c9bc424d2d882324d
categories:
- api
- key
- asana
references:
- https://developers.asana.com/docs/personal-access-token#example
validation:
type: Http
content:
request:
headers:
Authorization: Bearer {{ TOKEN }}
method: GET
response_matcher:
- report_response: true
- match_all_words: true
type: WordMatch
words:
- 'data:'
- email
- name
url: https://app.asana.com/api/1.0/users/me
- name: Asana OAuth / Personal Access Token (V2)
id: kingfisher.asana.5
pattern: |
(?xi)
\b
asana
(?:.|[\n\r]){0,64}?
\b
(
2/
[0-9]{16}
/
[0-9]{16}
:
[a-f0-9]{32}
)
\b
pattern_requirements:
min_digits: 4
min_entropy: 3.5
confidence: medium
examples:
- ASANA_TOKEN = "2/1208779539612523/1208824174176866:99d6decca6ce6ef503bf0c5bca554e1a"
categories:
- api
- key
- asana
references:
- https://developers.asana.com/docs/personal-access-token#example
validation:
type: Http
content:
request:
headers:
Authorization: Bearer {{ TOKEN }}
method: GET
response_matcher:
- report_response: true
- match_all_words: true
type: WordMatch
words:
- 'data:'
- email
- name
url: https://app.asana.com/api/1.0/users/me

41
data/rules/assemblyai.yml Normal file
View file

@ -0,0 +1,41 @@
rules:
- name: AssemblyAI API Key
id: kingfisher.assemblyai.1
pattern: |
(?xi)
\b
assemblyai
(?:.|[\n\r]){0,32}?
\b
(
[0-9a-z]{32}
)
\b
pattern_requirements:
min_digits: 2
min_lowercase: 1
min_entropy: 3.0
confidence: medium
examples:
- assemblyai = fa0ed91518b345468f9df7570f31f18a
- assemblyai_token = a741b921ae1f4446826a784726b6a71a
references:
- https://www.assemblyai.com/docs/api-reference/overview
- https://www.assemblyai.com/docs/api-reference/transcripts/list
validation:
type: Http
content:
request:
method: GET
url: https://api.assemblyai.com/v2/transcript?limit=1
headers:
Authorization: '{{ TOKEN }}'
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]
- type: JsonValid
- type: WordMatch
match_all_words: true
words: ['"page_details"', '"transcripts"']

View file

@ -6,13 +6,14 @@ rules:
\b
atlassian
(?:.|[\n\r]){0,32}?
(?:SECRET|PRIVATE|ACCESS|KEY|TOKEN)
(?:.|[\n\r]){0,32}?
\b
(
[a-z0-9]{24}
)
\b
\b
pattern_requirements:
min_digits: 2
min_lowercase: 1
min_entropy: 3.5
confidence: medium
examples:
@ -37,4 +38,65 @@ rules:
- type: WordMatch
words:
- "Unauthorized"
negative: true
negative: true
# - name: Atlassian Organization ID
# id: kingfisher.atlassian.2
# pattern: |
# (?xi)
# admin\.atlassian\.com
# /o/
# (
# [0-9a-f]{8}
# -
# [0-9a-f]{4}
# -
# [0-9a-f]{4}
# -
# [0-9a-f]{4}
# -
# [0-9a-f]{12}
# )
# min_entropy: 2.0
# confidence: medium
# visible: false
# examples:
# - https://admin.atlassian.com/o/12345678-9abc-def0-1234-56789abcdef0/api-keys
- name: Atlassian Admin API Key
id: kingfisher.atlassian.3
pattern: |
(?x)
(?:atlassian|api\.atlassian\.com)
(?:.|[\n\r]){0,128}?
\b
(
AT
[A-Za-z0-9_\-=]{60,260}
)
\b
min_entropy: 3.8
confidence: medium
examples:
- |
# Example usage calling the Atlassian admin APIs
curl --request GET \
'https://api.atlassian.com/admin/v1/orgs' \
--header 'Authorization: Bearer ATEXAMPLE1234567890abcdefghijklmnopqrstuvwxyz_-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789foobarAA11BB22'
references:
- https://developer.atlassian.com/cloud/admin/organization/rest/
- https://developer.atlassian.com/cloud/admin/api-access/rest/
- https://support.atlassian.com/organization-administration/docs/manage-an-organization-with-the-admin-apis/
- https://community.atlassian.com/learning/lesson/what-are-admin-apis
validation:
type: Http
content:
request:
method: GET
url: https://api.atlassian.com/admin/v1/orgs
headers:
Authorization: "Bearer {{ TOKEN }}"
Accept: application/json
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]
- type: JsonValid

View file

@ -10,7 +10,10 @@ rules:
(
[a-z0-9_-]{32,60}
)
\b
\b
pattern_requirements:
min_digits: 2
min_lowercase: 1
min_entropy: 3.5
confidence: medium
visible: false

34
data/rules/authress.yml Normal file
View file

@ -0,0 +1,34 @@
rules:
- name: Authress Service Client Access Key
id: kingfisher.authress.1
pattern: |
(?xi)
(
(?: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
pattern_requirements:
min_digits: 2
min_lowercase: 1
confidence: medium
min_entropy: 4.0
validation:
type: Http
content:
request:
method: GET
url: "https://api.authress.io/v1/users/me"
headers:
Authorization: "Bearer {{TOKEN}}"
response_matcher:
- report_response: true
- type: JsonValid
- type: WordMatch
words:
- '"Unauthorized"'
negative: true
references:
- https://authress.io/knowledge-base/docs/authorization/service-clients/access-keys/
- https://authress.io/knowledge-base/docs/usage-guides/api-keys-as-a-service-setup/
examples:
- "sc_a6DTktFwMEvh87xstYV1BXl.ihwj.acc-0xd1a47h1rr0f.MC4CAQAwBQYDKAVwBCIEIB1wYB62EK24FKxEPHbW0ishcstwp2qs30uLXdWgu4V0"

View file

@ -3,12 +3,17 @@ rules:
id: kingfisher.aws.1
pattern: |
(?xi)
\b
\b
(
(?:AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)
[0-9A-Z]{16}
(?:A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)
[2-7A-Z]{16}
)
\b
\b
pattern_requirements:
min_digits: 2
ignore_if_contains:
- "EXAMPLE"
- "TEST"
min_entropy: 3.2
visible: false
confidence: medium
@ -21,27 +26,28 @@ rules:
(?xi)
(?:
\b
(?:AWS|AMAZON|AMZN|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)
(?:.|[\n\r]){0,32}?
\b
(
[A-Z0-9/+=]{40}
)
\b
(?:AWS|AMAZON|AMZN|A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)
(?:.|[\n\r]){0,64}?
[^A-Za-z0-9_+!@\#$%^&*()\]./]
([A-Za-z0-9/+]{40})
[^A-Za-z0-9_+!@\#$%^&*()\]./]
|
\b(?:AWS|AMAZON|AMZN|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)
\b(?:AWS|AMAZON|AMZN|A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)
(?:.|[\n\r]){0,96}?
(?:SECRET|PRIVATE|ACCESS)
(?:.|[\n\r]){0,16}?
(?:KEY|TOKEN)
(?:.|[\n\r]){0,32}?
(?:.|[\n\r]){0,64}?
\b
(
[A-Z0-9/+=]{40}
)
([A-Za-z0-9/+]{40})
\b
)
min_entropy: 4.5
pattern_requirements:
min_digits: 3
ignore_if_contains:
- "EXAMPLE"
- "TEST"
min_entropy: 4.0
confidence: medium
examples:
- foo.backup.archive.aws.secretkey=sBmHlDFrNcsz35N+LRjwlUxF8/wypT4tiJCQ0wP4
@ -64,10 +70,62 @@ rules:
- name: AWS Session Token
id: kingfisher.aws.4
pattern: '(?i)(?:aws.?session|aws.?session.?token|aws.?token)["''`]?\s{0,30}(?::|=>|=)\s{0,30}["''`]?([a-z0-9/+=]{16,200})[^a-z0-9/+=]'
pattern_requirements:
min_digits: 2
min_entropy: 3.3
confidence: medium
examples:
- |
export AWS_ACCESS_KEY_ID="I08BCX2ACV45ED1DOC9J"
export AWS_SECRET_ACCESS_KEY="0qk+o7XctJMmG6ydO8537c9+TofLJU1K0PiVBXSg"
export AWS_SESSION_TOKEN="eyJhbGciOiJIUzUxMi53InR5cCI6IkpXVCJ9.eyJhY2Nlc3NLZXkiOiJJMDhCQ1gySkpWNDVFRDFET0M5SiIsImFjciI6Ij53LCJhdWQiOiJhY2NvdW50IiwiYXV0aF90aW1lIjowLCJhenAiOiJtaW5pbyIsImVtYWlsIjoiYWlkYW4uY29wZUBnbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsImV4cCI6MTU4MDUwMDIzOCwiZmFtaWx5X25hbWUiOiJDb3BlIiwiZ2l2ZW5fbmFtZSI6IkFpZGFuIENvcGUiLCJpYXQiOjE1ODA0OTk5MzgsImlzcyI6Imh0dHBzOi8vYXV0aHN0Zy5wb3BkYXRhLmJjLmNhL2F1dGgvcmVhbG1zL3NhbXBsZSIsImp0aSI6IjU5ZTM5ODAxLWQxMmUtNDVhYS04NmQzLWVhMmNmZDU0NmE2MiIsIm1pbmlvX3BvbGljeSI6ImRhdGFzZXRfMV9ybyIsIm5hbWUiOiJBaWRhbiBDb3BlIENvcGUiLCJuYmYiOjAsInByZWZlcnJlZF91c2VybmFtZSI6ImFjb3BlLTk5LXQwNSIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJwcm9maWxlIGVtYWlsIiwic2Vzc2lvbl9zdGF0ZSI6IjcxYjczZWJjLThlMzMtNGMyMi04NmE2LWI0MzhhNDM4ZmI2MiIsInN1YiI6IjVkOTBlOTgzLTA1NDItNDYyYS1hZWIwLWYxZWVmNjcwYzdlNSIsInR5cCI6IkJlYXJlciJ9.J-a9PORJToz7MUrnPQlOywcqtVMNkXy53Gedp_V4PW-Gbf1_BAMjwuw_X7fKRd6hkNfEn43CKKju7muzi_d1Ig"
export AWS_SESSION_TOKEN="eyJhbGciOiJIUzUxMi53InR5cCI6IkpXVCJ9.eyJhY2Nlc3NLZXkiOiJJMDhCQ1gySkpWNDVFRDFET0M5SiIsImFjciI6Ij53LCJhdWQiOiJhY2NvdW50IiwiYXV0aF90aW1lIjowLCJhenAiOiJtaW5pbyIsImVtYWlsIjoiYWlkYW4uY29wZUBnbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsImV4cCI6MTU4MDUwMDIzOCwiZmFtaWx5X25hbWUiOiJDb3BlIiwiZ2l2ZW5fbmFtZSI6IkFpZGFuIENvcGUiLCJpYXQiOjE1ODA0OTk5MzgsImlzcyI6Imh0dHBzOi8vYXV0aHN0Zy5wb3BkYXRhLmJjLmNhL2F1dGgvcmVhbG1zL3NhbXBsZSIsImp0aSI6IjU5ZTM5ODAxLWQxMmUtNDVhYS04NmQzLWVhMmNmZDU0NmE2MiIsIm1pbmlvX3BvbGljeSI6ImRhdGFzZXRfMV9ybyIsIm5hbWUiOiJBaWRhbiBDb3BlIENvcGUiLCJuYmYiOjAsInByZWZlcnJlZF91c2VybmFtZSI6ImFjb3BlLTk5LXQwNSIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJwcm9maWxlIGVtYWlsIiwic2Vzc2lvbl9zdGF0ZSI6IjcxYjczZWJjLThlMzMtNGMyMi04NmE2LWI0MzhhNDM4ZmI2MiIsInN1YiI6IjVkOTBlOTgzLTA1NDItNDYyYS1hZWIwLWYxZWVmNjcwYzdlNSIsInR5cCI6IkJlYXJlciJ9.J-a9PORJToz7MUrnPQlOywcqtVMNkXy53Gedp_V4PW-Gbf1_BAMjwuw_X7fKRd6hkNfEn43CKKju7muzi_d1Ig"
- name: AWS Bedrock API Key (Long-lived)
id: kingfisher.aws.bedrock.long_lived
pattern: |
(?x)
(
ABSKQmVkcm9ja0FQSUtleS[A-Za-z0-9+/=]{110}
)
min_entropy: 3.0
confidence: medium
examples:
- "ABSKQmVkcm9ja0FQSUtleS1GU9MjAyNTEyMDVUMjE1MTUxWiZYLUFtei1FeHBpcmVzPTQzMjAwJlgtQW16LVNlY3VyaXR5LVRva2VuPUlRb0piM0pwWjJsdVgyVmpFSjclMk"
references:
- https://aws.amazon.com/blogs/security/securing-amazon-bedrock-api-keys-best-practices-for-implementation-and-management/
- https://docs.aws.amazon.com/bedrock/latest/userguide/api-keys-how.html
validation:
type: Http
content:
request:
method: GET
url: https://bedrock.us-east-1.amazonaws.com/foundation-models
headers:
Authorization: "Bearer {{ TOKEN }}"
response_matcher:
- type: StatusMatch
status: [200]
- name: AWS Bedrock API Key (Short-lived)
id: kingfisher.aws.6
pattern: |
(?x)
(
bedrock-api-key-YmVkcm9jay5hbWF6b25hd3MuY29t[A-Za-z0-9+/]+={0,2}
)
min_entropy: 3.0
confidence: medium
examples:
- "AWS_BEARER_TOKEN_BEDROCK=bedrock-api-key-YmVkcm9jay5hbWF6b25hd3MuY29tLz9BY3Rpb249Q2FsbFdpdGhCZWFyZXJUb2tlbiZYLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFTSUFWRzRBNFpCSk5YUzRJSEZTJTJGMjAyNTEyMDUlMkZ1cy1lYXN0LTElMkZiZWRyb2NrJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTEyMDVUMjE1MTUxWiZYLUFtei1FeHBpcmVzPTQzMjAwJlgtQW16LVNlY3VyaXR5LVRva2VuPUlRb0piM0pwWjJsdVgyVmpFSjclMkYlMkYlMkYlMkYlMkYlMkYlMkYlMkYlMkYlMkZ3RWFDWFZ6TFdWaGMzUXRNU0pITUVVQ0lRQ1Z1dkhPTmZLMHVxY3lPeUhibkJ5SUlRQnl3Sm9RV2VTRko4RlclMkIyNkxGQUlnUXJXSU9SbWd1bUozd3ZxTElMZVJ4SXczYzglMkIxaUJ2U1E0R1d6T21rY2VNcTN3UUlaeEFBR2d3ek5UZ3pOak15TWpBd05UQWlEQ05ZYkhtZVVTOE01Rjl6MGlxOEJOOWg4TEZLd0tqTHJDdzZ1eUVDYTd3YjFDbnpGQndyVlFkSXFPU0ZrNWJGbHg5Sjc0cnJ2TjNCYUZQOHR2S3lQcnJCeUJ3bGU3dTIwRjBXVDJoWHlQVTM4cUtpRDclMkZzaTNydnFkT2ptR3pNdERuazRHbEpEN3ZnM01SMWd3cFZJM2Z5ZjU0WU5aZ0lWcm9RZ1g4UVZ4aGNZeHNuSEx6Y3llelh1aGZWbElRMk1LVXUyOTh0c2NqcnF3aEs3WmMlMkZ0Mjc5TWRvengzVkFveUgzdFpocE9oVHhud1VkMHRtQ3REOU5QNHdIN1pOQjRIR2xaZWtidjBoUGIxV012azlhVGF2QkRUZlFCcERueEFHVG5KbXpicm8lMkJod2M0SDB5Skwwb1lVbGplalB3JTJCRVY4ZlJzU3hrVUliOHVRTWRBNDdhUmFzNGpPWkwzZVRlNTdvUXI1Rlo1ekJLJTJGdzBmc1p3RlY5JTJGMTE5Mzc3S2huSnFPRTMxdjBRJTJGYWV1YVk5YThIZnFVNlZ4MD14cVIyM1VxUExxaUVhUnJiTXlQSjVHRUdNSzk0RG5zMDF5cmFjNzU5UGF2Zko2QnpjaEFPSklJeFdXeXBiYmY4dUJKYTdyTldOQUF6S1R4NHFSVm9VdHljS2txciUyQlFyajZ2b1NNOHBoJTJCRnpZOXFEJTJCaCUyQkNEbkk4M0xMRDRkVnJVN0Jla05QbjNXSFpEN0twRVdVZWJ1UlpoZGVNSVU4R0hVVlpGa3FCV3Q0djk5QVdNdlFydEFJVzlHUWN3UkhZM3FaMFo2ZHI3cHpIOGNoZWRyMWdyJTJGUnBkT3lBdFIlMkZ3OE9HeU1LeklaSzRBdTZVeEhRaGdOVjJKdDh0ZnFVSlNCS281UVhiV1RmakFSNFlQSFcwbEREaEtRTTZYWWJsJTJGY0hSM3pIMG1WMGUyc92OJTJGVTJTc1Q3MVhCb1Z1Y2d3WU56RXFkM2M0ZUZzdjFaelBTQ2lMVWUyaDhPZTI5Q0F2VHF5eEZBTUFaMVpKNyUyRk5MSzVRSldNT09uemNrR09zTUNqQXhOVFdXUXdMUjd5NmR2TlMzQmh6UVlMJTJGeXpJWEdaVnhZYm9mY3IlMkJLbCUyRnVveSUyQkFlWCUyRkxLaXFwWDk5RWc2cSUyQm1tazNIZ1Q0WWNueVU4VW5Ya2FxMUNxcXVFVVBuRllyMklpbE1UYjlIOUVzanJMRDU4TnBhSTB2OENxNUVRQkIlMkZLMUtkMDdzRks5V1B6cTZaeCUyQmZEVjdYZ0NobG41UDZxQjBFJTJGem5QenRTRWNHMlViS0pHaE4yWjZ2TGtQOVU0STJQODk5WFF4enhVSUIxOTAzUWhjcGp3cGRDN2ZZWEZZVkxqS253bTFiRGlMdFIxMTVnbUpoSUVUM3NheE5zUnpSQkIlMkZjWlMwY1FiTm1wUSUyQldrbXo4ekdXUkc1ZTc1cGclMkY1dUVRMW5aN1ZGTk95UTg1M2Jrb0ZLM0lnNzR3MUpPQllPemlYTVI3ZDF6MSUyRkFNa3hQYWFrWE5YWEd2Z3BsaldBYlR1Wm5Jb1N6UFdEcWIlMkZRaFowUWNxM1JaSm1JdUhTd05oaWs2SFJiZ0NvQUlHZ2sxR21iZUZXZDRoZlhVZWNDOUxvcExzRzEzbUklM0QmWC1BbXotU2lnbmF0dXJlPTU4NTk1MjRjN2RlNGZjMWQ1ODlmZmViOTVlYWI5N2NhYjRmNTQyYWY2MmVkOGExMGYyYzlhZDYyZDQ5ZWY3ODkmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JlZlcnNpb249MQ=="
references:
- https://docs.aws.amazon.com/bedrock/latest/userguide/api-keys-how.html
validation:
type: Http
content:
request:
method: GET
url: https://bedrock.us-east-1.amazonaws.com/foundation-models
headers:
Authorization: "Bearer {{ TOKEN }}"
response_matcher:
- type: StatusMatch
status: [200]

View file

@ -8,6 +8,8 @@ rules:
(?: AccountKey | SharedAccessKey | SharedSecretValue) \s*=\s* ([^;]{1,100})
(?: ;|$ )
min_entropy: 3.3
pattern_requirements:
min_digits: 2
confidence: medium
examples:
- |
@ -27,17 +29,10 @@ rules:
"AZURE_STORAGE_CONNECTION_STRING": {
"value": "DefaultEndpointsProtocol=https;AccountName=d1biblobstor521;AccountKey=NjEwGHd9+piK+iCi2C2XURWPmeDDjif9UKN1HAszYptL4iQ+yD7/dgjLMZc3VOpURsa53aJ4HZfbVWzL429C5g==;EndpointSuffix=core.windows.net"
}
negative_examples:
- 'InstrumentationKey=00000000-0000-0000-0000-000000000000;EndpointSuffix=ai.contoso.com;'
- 'InstrumentationKey=00000000-0000-0000-0000-000000000000;IngestionEndpoint=https://custom.com:111/;LiveEndpoint=https://custom.com:222/;ProfilerEndpoint=https://custom.com:333/;SnapshotEndpoint=https://custom.com:444/;'
references:
- https://azure.microsoft.com/en-us/blog/windows-azure-web-sites-how-application-strings-and-connection-strings-work/
- https://docs.microsoft.com/en-us/azure/storage/common/storage-configure-connection-string
- https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-sas#best-practices-when-using-sas
categories:
- api
- fuzzy
- secret
- name: Azure App Configuration Connection String
id: kingfisher.azure.2
@ -53,18 +48,10 @@ rules:
- 'https://foo-nonprod-appconfig.azconfig.io;Id=ABCD-E6-s0:tl6ABcdefGHi7kLMno/p;Secret=abCD1EF+GHIJxLMnOA53ST8uVWX05zaBCdE/fg9hi4k='
- 'Endpoint=https://appconfig-test01.azconfig.io;Id=09pv-l0-s0:opFCQMC6+9485xJgN5Ws;Secret=GcoEA53t7GLRNJ910M46IrbHO/Vg0tt4HujRdsaCoTY='
- ' private static string appConfigurationConnectionString = "Endpoint=https://appcs-fg-pwc.azconfig.io;Id=pi5x-l9-s0:SZLlhHA53Nz2MpAl04cU;Secret=CQ+mlfQqkzfZv4XA53gigJ/seeXMKwNsqW/rM3wmtuE=";'
negative_examples:
- |
text:
az appconfig feature delete --connection-string Endpoint=https://contoso.azconfig.io;Id=xxx;Secret=xxx --feature color --label MyLabel
references:
- https://docs.microsoft.com/en-us/azure/azure-app-configuration/
- https://docs.microsoft.com/en-us/azure/azure-app-configuration/howto-best-practices
- https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/appconfiguration/azure-appconfiguration/azure/appconfiguration/_utils.py
categories:
- api
- fuzzy
- secret
- name: Azure Personal Access Token
id: kingfisher.azure.3
@ -84,4 +71,48 @@ rules:
$token = "58oo4mvqr2tpw7b4w3loeckwfu5o6nw3sihfckvlwoxgqimlddza"
- |
if __name__ == "__main__":
ado_pat = "iyfmob6xjrfmit67anxbot64umfx2clwx7dz5ynxi4q2z3uqegvq"
ado_pat = "iyfmob6xjrfmit67anxbot64umfx2clwx7dz5ynxi4q2z3uqegvq"
- name: Azure Container Registry URL
id: kingfisher.azure.4
pattern: |
(?xi)
(
[a-z0-9][a-z0-9-]{1,100}[a-z0-9]
)\.azurecr\.io
confidence: medium
visible: false
min_entropy: 2.0
examples:
- "myregistry.azurecr.io"
- name: Azure Container Registry Password
id: kingfisher.azure.5
pattern: |
(?xi)
\b
(
[A-Z0-9+/]{42}\+ACR[A-Z0-9]{6}
)
\b
pattern_requirements:
min_digits: 2
confidence: medium
min_entropy: 4.0
validation:
type: Http
content:
request:
method: GET
url: "https://{{ACR_USERNAME}}.azurecr.io/v2/_catalog"
headers:
Authorization: "Basic {{ ACR_USERNAME | append: ':' | append: TOKEN | b64enc }}"
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]
examples:
- "Abcdefghijklmnopqrstuvwxyz123456789012ABCD+ACRefg123"
depends_on_rule:
- rule_id: "kingfisher.azure.4"
variable: ACR_USERNAME
references:
- https://learn.microsoft.com/en-us/azure/container-registry/container-registry-authentication

View file

@ -1,15 +1,31 @@
rules:
- name: Azure DevOps Personal Access Token
- name: Azure DevOps Organization
id: kingfisher.azure.devops.1
pattern: |
(?xi)
\b
azure
(?:.|[\n\r]){0,32}?
dev\.azure\.com/
(
[a-z0-9]{75}AZDO[a-z0-9]{5}
[a-z0-9][a-z0-9-]{0,61}[a-z0-9]
)
confidence: medium
min_entropy: 2.5
visible: false
examples:
- https://dev.azure.com/contoso
- dev.azure.com/somebody123
- name: Azure DevOps Personal Access Token
id: kingfisher.azure.devops.2
pattern: |
(?xi)
\b
(
[a-z0-9]{76}AZDO[a-z0-9]{4,5}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3
confidence: medium
examples:
@ -17,16 +33,20 @@ rules:
references:
- https://learn.microsoft.com/en-us/rest/api/azure/devops/profile/profiles/get?view=azure-devops-rest-7.1&tabs=HTTP
- https://learn.microsoft.com/en-us/azure/devops/release-notes/2024/general/sprint-241-update
depends_on_rule:
- rule_id: kingfisher.azure.devops.1
variable: AZURE_DEVOPS_ORG
validation:
type: Http
content:
request:
headers:
Authorization: 'Basic {{ ":" | append: TOKEN | b64enc }}'
Accept: application/json
method: GET
url: https://app.vssps.visualstudio.com/_apis/profile/profiles/me?api-version=7.1-preview.1
url: "https://dev.azure.com/{{ AZURE_DEVOPS_ORG | split: '/' | last }}/_apis/projects?api-version=7.1-preview.1"
response_matcher:
- report_response: true
- type: StatusMatch
status:
- 200
- 200

View file

@ -14,6 +14,9 @@ rules:
[a-f0-9]{32}
)
\b
pattern_requirements:
min_digits: 2
min_lowercase: 2
min_entropy: 3.5
confidence: medium
examples:
@ -46,7 +49,7 @@ rules:
(?xi)
\b
(
[a-z0-9-]+
[a-z0-9-]{3,32}
\.openai\.azure\.com
)
\b

View file

@ -12,6 +12,10 @@ rules:
[0-9A-Z]{52}
)
\b
pattern_requirements:
min_digits: 2
min_uppercase: 1
min_lowercase: 2
min_entropy: 3.3
confidence: medium
examples:

View file

@ -1,42 +1,59 @@
rules:
- name: Azure Storage Account Name
id: kingfisher.azurestorage.name.1
id: kingfisher.azurestorage.1
pattern: |
(?xi)
(?:
(?i:
(?:Account|Storage)
(?:[._-]Account)?
[._-]?Name
)
(?:.|[\n\r]){0,20}?
([a-z0-9]{3,24})
# A) Connection string: AccountName=<name>
(?i:AccountName)\s*=\s*([a-z0-9]{3,24})(?:\b|[^a-z0-9])
|
([a-z0-9]{3,24})
(?i:\.blob\.core\.windows\.net)
)\b
min_entropy: 2.5
# B) Blob endpoint URL: <name>.blob.core.windows.net
([a-z0-9]{3,24})\.blob\.core\.windows\.net\b
|
# C) Explicit KV labels near 'azure storage/account name' with tight separators
\bazure(?:[_\s-]*)(?:storage|account)(?:[_\s-]*)(?:name)\b
[\s:=\"']{0,6}
([a-z0-9]{3,24})(?:\b|[^a-z0-9])
|
# D) Explicit KV labels near 'azure storage/account name' with tight separators
(?i:Account[_.-]?Name|Storage[_.-]?(?:Name))(?:.|\s){0,32}?\b([A-Z0-9]{3,32})\b|([A-Z0-9]{3,32})(?i:\.blob\.core\.windows\.net)
)
min_entropy: 2.0
visible: false
confidence: medium
examples:
- storage_name=mystorageaccount123
- AccountName=mystorageaccount
- mystorageaccount.blob.core.windows.net
- azure_storage_name="prodblob2024"
- name: Azure Storage Account Key
id: kingfisher.azurestorage.key.1
id: kingfisher.azurestorage.2
pattern: |
(?xi)
(?i:(?:Access|Account|Storage)[_.-]?Key)
(?:.|[\n\r]){0,25}?
azure
(?:.|[\n\r]){0,128}?
(?:SECRET|PRIVATE|ACCESS|KEY|TOKEN)
(?:.|[\n\r]){0,128}?
["':\s=}\]\)]
(
[A-Z0-9+\\/-]{86,88}={0,2}
(?:
[A-Z0-9+\\/-]{86,88}={1,2}
)
|
(?:
[A-Z0-9+\\/-]{86,88}\b
)
)
pattern_requirements:
min_digits: 2
min_uppercase: 2
min_lowercase: 2
min_entropy: 4.0
confidence: medium
examples:
- AccountKey=Xy9aB8cD7eF6gH5iJ4kL3mN2oP1qR0sT9uV8wX7yZ6aB5cD4eF3gH2iJ1kL0mN9oP8qR7sT6uV5wX4yZ3aB2cD1eF0gH9iJ8kL7mN6oP5q==\
- Azure AccountKey=Xy9aB8cD7eF6gH5iJ4kL3mN2oP1qR0sT9uV8wX7yZ6aB5cD4eF3gH2iJ1kL0mN9oP8qR7sT6uV5wX4yZ3aB2cD1q
- Azure AccountKey=Ky7aC1cD7eF6gH5iJ4kL3mN2oP1qR0sT9uV8wX7yZ6aB5cD4eF3gH2iJ1kL0mN9oP8qR7sT6uV5wX4yZ3aB2cD1g==\
validation:
type: AzureStorage
depends_on_rule:
- rule_id: kingfisher.azurestorage.name.1
variable: AZURENAME
- rule_id: kingfisher.azurestorage.1
variable: AZURENAME

View file

@ -2,17 +2,17 @@ rules:
- name: Baremetrics API Key
id: kingfisher.baremetrics.1
pattern: |
(?xi)
\b
(?xi)
\b
baremetrics
(?:.|[\n\r]){0,32}?
(?:SECRET|PRIVATE|ACCESS|KEY|TOKEN)
(?:.|[\n\r]){0,32}?
\b
(
[a-z0-9_-]{25}
)
\b
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.3
confidence: medium
references:

49
data/rules/baseten.yml Normal file
View file

@ -0,0 +1,49 @@
rules:
- name: Baseten API Key
id: kingfisher.baseten.1
pattern: |
(?x)
\b
baseten
(?:.|[\n\r]){0,32}?
\b
(
[A-Za-z0-9]{8}
\.
[A-Za-z0-9]{32}
)
\b
pattern_requirements:
min_digits: 2
min_uppercase: 1
min_lowercase: 1
min_entropy: 3.4
confidence: medium
examples:
- baseten_key = WSsDXzCD.uOcxAp7k82IvCKyY36TnpVbP4ZszP1qw
- baseten_key = crXCQC3W.CgCGGY1b9IfJan5TppW0Z07C9oMN2DmR
- baseten_key = h2wFkhFC.3WFVwVcxGFr4Qup0gyhvIuONwQxEpL0A
- baseten_key = XqbIpj04.x73j1zLUOEgGIKROqVbxsmggPdL8JvAY
references:
- https://docs.baseten.co/examples/vllm
- https://docs.baseten.co/reference/management-api/api-keys/lists-the-users-api-keys
- https://docs.baseten.co/reference/training-api/overview#authentication
- https://docs.baseten.co/reference/management-api/api-keys/creates-an-api-key
validation:
type: Http
content:
request:
method: GET
url: https://api.baseten.co/v1/api_keys
headers:
Authorization: Api-Key {{ TOKEN }}
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]
- type: JsonValid
- type: WordMatch
match_all_words: true
words:
- '"name"'
- '"type"'

View file

@ -9,7 +9,11 @@ rules:
\b
(
b_[A-Z0-9=_\\/\\\-+]{44}
)
)
pattern_requirements:
min_digits: 2
min_uppercase: 1
min_lowercase: 1
min_entropy: 3.0
confidence: medium
examples:

View file

@ -8,9 +8,10 @@ rules:
(?:.|[\n\r]){0,16}?
(?:client|id)
(?:.|[\n\r]){0,16}?
\b
([a-z0-9]{30,40})
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.5
confidence: medium
examples:
@ -43,11 +44,14 @@ rules:
(
[a-z0-9+_\-+]{44}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.5
confidence: medium
examples:
- bitbucket_key=HedmnK9h6KD_eh9KK8FlI9ahUc8WfaNZ4gulbrtN2ouV
- bitbucket_secret=kd8j2h4jf9s8mf6l4k9j2h4jf9s8mf6l4k9j2h4jf9s8mf6l
- bitbucket_secret=kd8j2h4jf9s8mf6l4k9j2h4jf9s8mf6l4k9j2h4jf9s8
validation:
type: Http
content:

38
data/rules/bitly.yml Normal file
View file

@ -0,0 +1,38 @@
rules:
- name: Bitly Access Token
id: kingfisher.bitly.1
pattern: |
(?xi)
\b
bitly
(?:.|[\n\r]){0,32}?
(?:SECRET|PRIVATE|ACCESS|KEY|TOKEN)
(?:.|[\n\r]){0,32}?
(
[a-f0-9]{40}
)
\b
pattern_requirements:
min_digits: 2
min_lowercase: 2
confidence: medium
min_entropy: 3.0
validation:
type: Http
content:
request:
method: GET
url: "https://api-ssl.bitly.com/v4/user"
headers:
Authorization: "Bearer {{ TOKEN }}"
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]
- type: WordMatch
words:
- '"login":'
references:
- https://dev.bitly.com/api-reference#Authentication
examples:
- "bitly_token = 20e9817b9c5ddde1b0cec7622bfc557dbc823791"

View file

@ -6,6 +6,10 @@ rules:
https://(?:fra1\.|lon1\.|ny3\.|sgp1\.|blr1\.)*blynk\.cloud/external/api/[A-Z0-9/]*\?token=
([A-Z0-9_\-]{32})
&
pattern_requirements:
min_digits: 2
min_uppercase: 1
min_lowercase: 1
min_entropy: 3.3
confidence: medium
examples:
@ -21,6 +25,10 @@ rules:
-H\s*"Authorization:\s*Bearer\s*
([A-Z0-9_\-]{40})
"
pattern_requirements:
min_digits: 2
min_uppercase: 1
min_lowercase: 1
min_entropy: 3.3
confidence: medium
examples:
@ -35,6 +43,10 @@ rules:
-H\s*"Authorization:\s*Bearer\s*
([A-Z0-9_\-]{40})
"[\s\\]*https://(?:fra1\.|lon1\.|ny3\.|sgp1\.|blr1\.)*blynk\.cloud/api
pattern_requirements:
min_digits: 2
min_uppercase: 1
min_lowercase: 1
min_entropy: 3.3
confidence: medium
examples:
@ -50,6 +62,10 @@ rules:
(oa2-client-id_[A-Z0-9_\-]{32})
(?: : | &client_secret= )
([A-Z0-9_\-]{40})
pattern_requirements:
min_digits: 2
min_uppercase: 1
min_lowercase: 1
min_entropy: 3.3
confidence: medium
examples:
@ -66,6 +82,10 @@ rules:
(oa2-client-id_[A-Z0-9_\-]{32})
:([A-Z0-9_\-]{40})
[\s\\]*https://(fra1\.|lon1\.|ny3\.|sgp1\.|blr1\.)*blynk\.cloud/oauth2
pattern_requirements:
min_digits: 2
min_uppercase: 1
min_lowercase: 1
min_entropy: 3.3
confidence: medium
examples:

33
data/rules/buildkite.yml Normal file
View file

@ -0,0 +1,33 @@
rules:
- name: Buildkite API Key
id: kingfisher.buildkite.1
pattern: |
(?xi)
(
bkua_[a-z0-9]{40}
)
\b
pattern_requirements:
min_digits: 2
min_lowercase: 1
min_entropy: 3.5
confidence: medium
examples:
- bkua_3c7019c2e4b6e76fe2e8bdde7c154e3c1a211743
references:
- https://buildkite.com/docs/apis/rest-api/access-token
validation:
type: Http
content:
request:
method: GET
url: https://api.buildkite.com/v2/access-token
headers:
Authorization: "Bearer {{ TOKEN }}"
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]
- type: WordMatch
words: ['"uuid"', '"user"']

38
data/rules/cerebras.yml Normal file
View file

@ -0,0 +1,38 @@
rules:
- name: Cerebras AI API Key
id: kingfisher.cerebras.1
pattern: |
(?xi)
(
csk-[a-z0-9]{48}
)
\b
pattern_requirements:
min_digits: 2
min_lowercase: 2
confidence: medium
min_entropy: 3.0
validation:
type: Http
content:
request:
method: GET
url: "https://api.cerebras.ai/v1/models"
headers:
Authorization: "Bearer {{ TOKEN }}"
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]
- type: WordMatch
words:
- '"object"'
- '"data"'
match_all_words: true
references:
- https://docs.cerebras.net/
examples:
- "csk-6nptf4w5cx36fw58t3hkx48jvm52wm693pex5tjm29kn55yt"
- "csk-e2knhj8h3h4erp6crfx6rh52tvecj4xnwmtjf3mtrvtt54et"
- "csk-rhw8npjrp6kpv9phm55n5nv5rkkm4492jepx3yh65dc9cwe9"
- "csk-w6p3nxk3dc5249mrpmv642fffert28rwdkepffrpn8rtfr9h"

View file

@ -2,31 +2,22 @@ rules:
- name: CircleCI API Personal Access Token
id: kingfisher.circleci.1
pattern: |
(?xi)
(?x)
\b
(
CCIPAT_
[a-z0-9]{4}
[a-z]{5}
[a-z0-9]{3}
[0-9]{3}
[a-z]{2}
[A-Z]{2}
[0-9]{1}
[a-z]{1}
[a-z0-9]{1}
[0-9]{1}
[a-z]{1}
[a-zA-Z0-9]{22}
_
[a-z0-9]{40}
)
\b
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.5
confidence: medium
examples:
- CircleCI_PAT = "CCIPAT_lZyPAuThWn2G908ssDT0g33e_t7qh0r5hrvsqzmuraqzduq6qco5onxgrtcn7y2z4"
- |
export CIRCLECI_TOKEN=CCIPAT_lZyPAuThWn2G908ssDT0g33e_t7qh0r5hrvsqzmuraqzduq6qco5onxgrtcn7y2z4
export CIRCLECI_TOKEN=CCIPAT_FERZRjTN451xnDCy1y9gWn_79fb6ca4d0e5f833612eee17de397a9dca0a9e9f
references:
- https://circleci.com/docs/api-developers-guide/#using-the-api-securely-wtih-curl
validation:
@ -56,7 +47,10 @@ rules:
(
[a-f0-9]{40}
)
\b
\b
pattern_requirements:
min_digits: 2
min_lowercase: 2
min_entropy: 3.3
confidence: medium
examples:
@ -80,4 +74,4 @@ rules:
- type: WordMatch
words:
- '"vcs_url"'
url: https://circleci.com/api/v1.1/projects
url: https://circleci.com/api/v1.1/projects

View file

@ -0,0 +1,37 @@
rules:
- name: Cisco Meraki API Key
id: kingfisher.ciscomeraki.1
pattern: |
(?xi)
meraki
(?:.|[\n\r]){0,32}?
(
[0-9a-f]{40}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.3
confidence: medium
examples:
- MERAKI_API_KEY=1234567890abcdef1234567890abcdef12345678
- |-
// Meraki configuration
const MERAKI_KEY = "abcdefabcdefabcdefabcdefabcdefabcdefabcd";
references:
- https://developer.cisco.com/meraki/api-v1/overview/
validation:
type: Http
content:
request:
method: GET
url: https://api.meraki.com/api/v1/organizations
headers:
X-Cisco-Meraki-API-Key: '{{ TOKEN }}'
Accept: application/json
response_matcher:
- report_response: true
- type: StatusMatch
status:
- 200
- type: JsonValid

40
data/rules/clarifai.yml Normal file
View file

@ -0,0 +1,40 @@
rules:
- name: Clarifai API Key
id: kingfisher.clarifai.1
pattern: |
(?xi)
\b
clarifai
(?:.|[\n\r]){0,32}?
\b
(
[0-9a-f]{32,36}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.0
confidence: medium
examples:
- clarifai_key = 29ee853d47364107b9edf5e5ad4374c2
- "clarifai_token: eb3cf5440b7b45f8954bb4a1fcea0ea5"
- clarifai-secret = 8e43e018f61b493c8104024ee124a57f
- clarifai_api = cf3cacafabe747988298298bffcbb459
references:
- https://docs.gitguardian.com/secrets-detection/secrets-detection-engine/detectors/specifics/clarifai_key
- https://docs.clarifai.com/control/authentication/key/
validation:
type: Http
content:
request:
method: GET
url: https://api.clarifai.com/v2/models
headers:
Authorization: Key {{ TOKEN }}
response_matcher:
- report_response: true
- type: WordMatch
match_all_words: true
words:
- '"code":10000'
- '"description":"Ok"'

25
data/rules/clay.yml Normal file
View file

@ -0,0 +1,25 @@
rules:
- name: Clay API Key
id: kingfisher.clay.1
pattern: |
(?xi)
\b
clay
(?:.|[\n\r]){0,64}?
\b
(
[a-f0-9]{20}
)
\b
pattern_requirements:
min_digits: 6
min_entropy: 3.0
confidence: medium
examples:
- clay_api_key=ce1abceaffe7d7958a41
- "CLAY_KEY: bdc55270455ca0a892e4"
- export CLAY_TOKEN=e9b711a5acbb99b8f099
- 'clay key: f6fd04ab6b4f7992adc2'
- CLAY_API_KEY=d8dfd14ec83e4e17a7d2
references:
- https://university.clay.com/docs/http-api-integration-overview

35
data/rules/clearbit.yml Normal file
View file

@ -0,0 +1,35 @@
rules:
- name: Clearbit API Key
id: kingfisher.clearbit.1
pattern: |
(?xi)
\b
clearbit
(?:.|[\n\r]){0,16}?
(?:SECRET|PRIVATE|ACCESS|KEY|TOKEN)
(?:.|[\n\r]){0,32}?
\b
(
[0-9a-z_]{35}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.5
confidence: medium
examples:
- clearbit_token = tq50141fm92fl4nid9c1c7liouhbertbvg1
validation:
type: Http
content:
request:
method: GET
url: https://discovery.clearbit.com/v1/companies/entities?name=kingfisher
headers:
Authorization: "Bearer {{ TOKEN }}"
response_matcher:
- report_response: true
- type: WordMatch
words:
- '"Invalid API key provided"'
negative: true

57
data/rules/clickhouse.yml Normal file
View file

@ -0,0 +1,57 @@
rules:
- name: ClickHouse Cloud Secret Key
id: kingfisher.clickhouse.1
pattern: |
(?xi)
\b
(
4b1d[a-z0-9]{38}
)
\b
pattern_requirements:
min_digits: 2
confidence: medium
min_entropy: 3.5
examples:
- "4b1dwEZ8aNo1U9ODBqffSci1INBrltLHM2d1bHF4dq"
validation:
type: Http
content:
request:
method: GET
url: "https://api.clickhouse.cloud/v1/organizations"
headers:
Authorization: "Basic {{ CLICKHOUSE_ID | append: ':' | append: TOKEN | b64enc }}"
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]
- type: WordMatch
words:
- '"id":'
- '"name":'
match_all_words: true
depends_on_rule:
- rule_id: "kingfisher.clickhouse.2"
variable: CLICKHOUSE_ID
references:
- https://clickhouse.com/docs/en/cloud/security/service-accounts
- name: ClickHouse Cloud Key ID
id: kingfisher.clickhouse.2
pattern: |
(?xi)
\b
clickhouse
(?:.|[\n\r]){0,16}?
(?:ID|USER)
(?:.|[\n\r]){0,16}?
(
[a-z0-9]{20}
)
pattern_requirements:
min_digits: 2
confidence: medium
visible: false
min_entropy: 3.0
examples:
- "clickhouse_id = 4ywspD2Tb0gJh4QbLnDI"

41
data/rules/clojars.yml Normal file
View file

@ -0,0 +1,41 @@
rules:
- name: Clojars Username
id: kingfisher.clojars.1
pattern: |
(?xi)
\b
clojars
(?:.|[\n\r]){0,32}?
(?:ID|USER)
(?:.|[\n\r]){0,16}?
\b
(
[a-z0-9_-]{3,}
)
\b
pattern_requirements:
min_digits: 2
confidence: medium
min_entropy: 1.5
visible: false
examples:
- "clojars_user = my-username"
- name: Clojars API Token
id: kingfisher.clojars.2
pattern: |
(?xi)
\b
(
CLOJARS_[a-z0-9]{60}
)
\b
pattern_requirements:
min_digits: 2
confidence: medium
min_entropy: 4.0
examples:
- "CLOJARS_7a0b5c647fdca75616e99a5629ba28955e53faf6391b1b4461ccd972b0e2"
references:
- https://github.com/clojars/clojars-web/wiki/API
- https://github.com/clojars/clojars-web/wiki/Tutorial-for-library-authors

View file

@ -12,7 +12,11 @@ rules:
(
[a-z0-9_-]{38,42}
)
\b
\b
pattern_requirements:
min_digits: 2
min_uppercase: 1
min_lowercase: 1
min_entropy: 3.5
confidence: medium
examples:
@ -47,9 +51,10 @@ rules:
(
v1\.0-[a-z0-9._-]{160,}
)
["'`]?
\b
min_entropy: 4.5
\b
pattern_requirements:
min_digits: 2
min_entropy: 4.0
confidence: medium
examples:
- 'X-Auth-User-Service-Key = v1.0-e26de050e02ddeaeef6de8d5ee267df5e78f68666ddd0ee76f22d26a0d20756f-eda77de60e8e76077e162727656787de2005d25e2f6e502e2d067657ed65722eade065275001a0f6f6e521e5e1fd76a6e8d7e2d6da8a2ee01e66e061e22570e2-07f2ede0aed78e82e8d2e620aaef8656d81e762266d7d226a205de7e18e2256a'
@ -58,9 +63,6 @@ rules:
references:
- https://developers.cloudflare.com/api/keys/
- https://developers.cloudflare.com/fundamentals/api/get-started/keys/
categories:
- api
- secret
validation:
type: Http
content:

View file

@ -11,8 +11,10 @@ rules:
\b
(
[a-z0-9]{20,24}
)
\b
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.5
confidence: medium
examples:

View file

@ -12,6 +12,9 @@ rules:
(
[0-9A-Z]{20,24}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.5
confidence: medium
examples:

View file

@ -5,10 +5,13 @@ rules:
(?xi)
(?: CODECLIMATE| CC_TEST_REPORTER_ID)
(?:.|[\n\r]){0,64}?
\b
(
[a-f0-9]{64}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.3
confidence: medium
examples:

39
data/rules/codecov.yml Normal file
View file

@ -0,0 +1,39 @@
rules:
- name: Codecov Access Token
id: kingfisher.codecov.1
pattern: |
(?xi)
\b
codecov
(?:.|[\n\r]){0,32}?
(?:SECRET|PRIVATE|ACCESS|KEY|TOKEN)
(?:.|[\n\r]){0,32}?
\b
(
[A-Z0-9-]{36}
)
\b
pattern_requirements:
min_digits: 2
confidence: medium
min_entropy: 3.5
validation:
type: Http
content:
request:
method: GET
url: "https://api.codecov.io/api/v2/github/"
headers:
Authorization: "Bearer {{TOKEN}}"
Accept: application/json
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]
- type: WordMatch
words:
- '"count":'
references:
- https://docs.codecov.com/reference/api-overview
examples:
- "codecov_token = 52acf265-3fc6-4ecd-304a-15940bd04653"

39
data/rules/coderabbit.yml Normal file
View file

@ -0,0 +1,39 @@
rules:
- name: CodeRabbit API Key
id: kingfisher.coderabbit.1
pattern: |
(?xi)
\b
(
cr-[a-f0-9]{58}
)
\b
pattern_requirements:
min_digits: 4
min_entropy: 3.5
confidence: medium
examples:
- "cr-33420bb12fddf6cde6fba5414df88b07f75b2258e30c956b95f2ddbb2d"
references:
- https://coderabbit.ai/
- https://api.coderabbit.ai/docs
validation:
type: Http
content:
request:
method: GET
url: "https://api.coderabbit.ai/v1/seats/"
headers:
accept: "application/json"
x-coderabbitai-api-key: "{{TOKEN}}"
response_matcher:
- report_response: true
- type: WordMatch
words:
- '"success"'
- '"errors"'
match_all_words: false
- type: WordMatch
negative: true
words:
- '"Invalid or inactive API key"'

41
data/rules/cohere.yml Normal file
View file

@ -0,0 +1,41 @@
rules:
- name: Cohere API Key
id: kingfisher.cohere.1
pattern: |
(?xi)
\b
cohere
(?:.|[\n\r]){0,16}?
\b
(
[A-Z0-9]{40}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.5
confidence: medium
examples:
- 'cohere_key = 5fNtU1ytdUcOX3jfvgjlr61EPxBqxOojOklDD6BG'
- "cohere secret key = QfsfCM0HdHH9x5ZlhsGzeignSk4pCeBwBrzYqgGV"
- 'cohere_token: x7PX0fac8a2GW2fgnNqdtqIwMQvFbrL6E7lKrKOv'
references:
- https://docs.cohere.com/reference/list-connectors
validation:
type: Http
content:
request:
method: GET
url: https://api.cohere.com/v1/connectors
headers:
Authorization: Bearer {{ TOKEN }}
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]
- type: JsonValid
- type: WordMatch
match_all_words: true
words:
- '"connectors"'
- '"total_count"'

82
data/rules/coinbase.yml Normal file
View file

@ -0,0 +1,82 @@
rules:
- name: Coinbase Access Token
id: kingfisher.coinbase.1
pattern: |
(?xi)
\b
coinbase
(?:.|[\n\r]){0,16}?
(?:SECRET|PRIVATE|ACCESS|KEY|TOKEN)
(?:.|[\n\r]){0,16}?
\b
(
[a-z-0-9]{32}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.5
examples:
- coinbase_token = 32iAkQCcHHYxXGx20VogBZoj27PC1ouI
references:
- https://docs.cloud.coinbase.com/wallet-sdk/docs/api-keys
validation:
type: Http
content:
request:
method: GET
url: https://api.coinbase.com/v2/user
headers:
Authorization: "Bearer {{ TOKEN }}"
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]
- name: Coinbase CDP API Key (ECDSA)
id: kingfisher.coinbase.2
pattern: |
(?xims)
"name"\s*:\s*"
(?P<CRED_NAME>organizations/[0-9a-f-]{36}/apiKeys/[0-9a-f-]{36})"
.*"privateKey"\s*:\s*"
(?P<PRIVATE_KEY>
-----BEGIN\sEC\s{0,1}
PRIVATE\sKEY
(\sBLOCK)?
-----
[a-z0-9 /+=\r\n\\n]{32,}?
-----END\s
(?:
RSA |
PGP |
DSA |
OPENSSH |
ENCRYPTED |
EC
)?
\s{0,1}
PRIVATE\sKEY
(\sBLOCK)?
-----
)
validation:
type: Coinbase
examples:
- |
{
"name": "organizations/243873d8-c14e-436d-9cea-10d530cbe201/apiKeys/d29bb143-ad4c-234f-9bd7-c705c16b6d19",
"privateKey": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIDs+vr9F40Mer+qYksK3QhkSMfUXOZsbRVSrelWGnMh3oAoGCCqGSM49\nAwEHoUQDQgAEOXj2qKzLYx21D3plbOa81ilURS/4K1jzLXBvgwfUe4hWDgBdKQvq\nIiet5qqZEwVlR/LqKQEUlP8YLrjLFU8Unw==\n-----END EC PRIVATE KEY-----\n"
}
- name: Coinbase CDP API Key (Ed25519)
id: kingfisher.coinbase.3
pattern: |
(?xis)
"id"\s*:\s*"(?P<CRED_NAME>[0-9a-f-]{36})"[^{]*?"privateKey"\s*:\s*"(?P<PRIVATE_KEY>[A-Za-z0-9+/=]{88})"
validation:
type: Coinbase
examples:
- |
{
"id": "413b23bf-4582-4e57-b33a-85d9527d9972",
"privateKey": "ygWq07YCO8UkmC9BE0PDBJNGhiu80yslsMUF9WnjPaIF5DBxb/wljjRuHhfuR/AMPC+kdgtL+mWKq/HOnq/YcQ=="
}

View file

@ -10,6 +10,8 @@ rules:
[A-Z0-9]{16}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3
confidence: medium
visible: false
@ -33,8 +35,45 @@ rules:
min_entropy: 3.3
confidence: medium
examples:
- confluent secret=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ab
- kafka_token=ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCD
- confluent secret=cbadefghijklmnopqrstuvwxyzcbaDEFGHIJKLMNOPQRSTUVWXYZ3214567890ab
- kafka_token=cbaDEFGHIJKLMNOPQRSTUVWXYZ3214567890cbadefghijklmnopqrstuvwxyzAB
references:
- https://docs.confluent.io/cloud/current/api.html#tag/API-Keys-(iamv2)/operation/getIamV2ApiKey
validation:
type: Http
content:
request:
headers:
Authorization: 'Basic {{ CLIENTID | append: ":" | append: TOKEN | b64enc }}'
method: GET
response_matcher:
- report_response: true
- status:
- 200
type: StatusMatch
url: https://api.confluent.cloud/iam/v2/api-keys/{{ CLIENTID }}
depends_on_rule:
- rule_id: "kingfisher.confluent.1"
variable: CLIENTID
- name: Confluent API Secret - Updated Format
id: kingfisher.confluent.3
pattern: |
(?xi)
\b
(
cflt(?P<body>[A-Za-z0-9\+/]{54})(?P<checksum>[A-Za-z0-9\+/]{6})
)
pattern_requirements:
checksum:
actual:
template: "{{ MATCH | suffix: 6 }}"
requires_capture: checksum
expected: "{{ BODY | crc32_le_b64: 6 }}"
skip_if_missing: true
min_entropy: 3.3
confidence: medium
examples:
- confluent secret=cfltqPLd2lLPAtWtHGNhN32WlZxoEj30pcg8mzaPlPJ937JlMa7n9YCRLooqgifw
references:
- https://docs.confluent.io/cloud/current/api.html#tag/API-Keys-(iamv2)/operation/getIamV2ApiKey
validation:

77
data/rules/contentful.yml Normal file
View file

@ -0,0 +1,77 @@
rules:
- name: Contentful Delivery API Token
id: kingfisher.contentful.1
pattern: |
(?xi)
\b
contentful
(?:.|[\n\r]){0,32}?
(?:SECRET|PRIVATE|ACCESS|KEY|TOKEN)
(?:.|[\n\r]){0,32}?
\b
(
[A-Z0-9_-]{43,45}
)
\b
pattern_requirements:
min_digits: 2
min_special_chars: 1
confidence: medium
min_entropy: 4.0
validation:
type: Http
content:
request:
method: GET
url: "https://cdn.contentful.com/spaces"
headers:
Authorization: "Bearer {{TOKEN}}"
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]
- type: WordMatch
words:
- '"sys":'
- '"type":"Array"'
- '"items":'
match_all_words: true
references:
- https://www.contentful.com/developers/docs/references/content-delivery-api/
examples:
- "contentful_delivery_token = wJz-g_tqZ-8n_abcdefghijklmnopqrstuvwxyz12345"
- name: Contentful Personal Access Token
id: kingfisher.contentful.2
pattern: |
(?xi)
(
CFPAT-[A-Z0-9_-]{43}
)
pattern_requirements:
min_digits: 2
confidence: medium
min_entropy: 3.5
validation:
type: Http
content:
request:
method: GET
url: "https://api.contentful.com/users/me"
headers:
Authorization: "Bearer {{TOKEN}}"
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]
- type: WordMatch
words:
- '"firstName":'
- '"lastName":'
match_all_words: true
references:
- https://www.contentful.com/developers/docs/references/content-management-api/#/reference/users/user
examples:
- "CFPAT-Cq3AarsJCDvdG9PYAJ3Y00crCG5nEPAAfVZ2LAldCsQ"
- "CFPAT-WFWEK_dWYIW0-uamOjhUBAJJ9NqQisr1x_ylb4z1vcQ"
- "CFPAT-lkITY2pqeiE0_p9TxUZrGAhfHJIiwYtbtr769y4_AYY"

81
data/rules/coveralls.yml Normal file
View file

@ -0,0 +1,81 @@
rules:
- name: Coveralls Repo Identifier
id: kingfisher.coveralls.1
visible: false
confidence: medium
min_entropy: 2.0
pattern: |
(?xi)
(?:
coveralls\.io/
(?:
(?:
github|bitbucket|gitlab
)
/
(
[A-Z0-9_.-]+
)
/
(
[A-Z0-9_.-]+
)
)
|
api/v1/repos/
(
github|bitbucket|gitlab
)
/
(
[A-Z0-9_.-]+
)
)
examples:
- https://coveralls.io/github/lemurheavy/coveralls-public
- https://coveralls.io/gitlab/group/project
- https://coveralls.io/api/v1/repos/github/octocat/hello-world
- name: Coveralls Personal API Token
id: kingfisher.coveralls.2
pattern: |
(?xi)
\b
coveralls
(?:.|[\n\r]){0,1}?
(?:SECRET|PRIVATE|ACCESS|KEY|TOKEN)
(?:.|[\n\r]){0,32}?
\b
(
[A-Z0-9-]{37}
)
\b
pattern_requirements:
min_digits: 3
min_entropy: 3.3
confidence: medium
examples:
- coveralls_SECRETTOKEN abcdefghijklmnopqrstuvwxyzab12345cdef
- coveralls-SECRET-KEY mnopqrstuvwxyzabcdefghi12345678901234
- coveralls_PRIVATEKEY-1234567890abcdefghijklmnopqrstuvwxyza
references:
- https://docs.coveralls.io/api-repos-endpoint
- https://docs.coveralls.io/api-introduction
depends_on_rule:
- rule_id: kingfisher.coveralls.1
variable: COVERALLS_REPO_ID
validation:
type: Http
content:
request:
method: GET
url: "https://coveralls.io/api/v1/repos/{{ COVERALLS_REPO_ID }}"
headers:
Authorization: "token {{ TOKEN }}"
Accept: application/json
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]
- type: WordMatch
words: ['"service"', '"name"', '"id"']

41
data/rules/coze.yml Normal file
View file

@ -0,0 +1,41 @@
rules:
- name: Coze Personal Access Token
id: kingfisher.coze.1
pattern: |
(?xi)
coze
(?:.|[\n\r]){0,32}?
\b
(
pat_[A-Z0-9]{64}
)
\b
pattern_requirements:
min_digits: 2
confidence: medium
min_entropy: 5.0
validation:
type: Http
content:
request:
method: GET
url: "https://api.coze.com/v1/workspaces?"
headers:
Authorization: "Bearer {{TOKEN}}"
Content-Type: application/json
response_matcher:
- type: StatusMatch
status: [200, 403] # API returns 403 for a valid token without permission to route
- type: JsonValid
- type: WordMatch
words:
- '"access token invalid"'
- '"does not have permission"'
negative: true
references:
- https://www.coze.com/docs/developer_guides/coze_api_overview
- https://www.coze.com/docs/developer_guides/retrieve_files
examples:
- "key_coze = pat_DlOG7fNcVfmw8cYhPWNcdfwrjjzwDr9EkV8EBjzHdgRWU2DzqHC1pPe0x590NN5f"
- "coze_token = pat_93QiTdIvZGuRCFcfGTQJJ1VIYZ9dNHanX88wKoMojwMk3tX5tKqfFtxUp0ux8CjI"
- "coze-key: pat_WvUTLYq5yZyaqegkyLSxXJMjXAJotjYEuC1sqT8daFlfwM3BiaRVJIZsER42DnhV"

View file

@ -8,6 +8,8 @@ rules:
cio[A-Z0-9]{32}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.3
confidence: medium
examples:

View file

@ -20,6 +20,6 @@ rules:
[a-z0-9\/._~-]*
)?
min_entropy: 3.0
confidence: low
confidence: medium
examples:
- https://eaRIWNkE:qyOIhJiM@j2LYY414Q5cCYD

24
data/rules/curl.yml Normal file
View file

@ -0,0 +1,24 @@
rules:
- name: Curl Basic Authentication Credentials
id: kingfisher.curl.1
pattern: '(?i)\bcurl\s.*(?:-u|--user)\s+[''"]?(?P<TOKEN>[^:''"\s]+:[^''"\s]+)[''"]?'
confidence: low
min_entropy: 3.0
references:
- https://curl.se/docs/manpage.html#-u
examples:
- 'curl --cacert ca.crt -u elastic:P@ssw0rd$1 https://localhost:9200'
- 'curl -u developer:yqDVtkqPECriaLRi'
- 'curl --user roger23@gmail.com:pQ9wTxu4Fg https://www.dropbox.com'
- name: Curl Header Authentication
id: kingfisher.curl.2
pattern: '(?i)\bcurl\s.*(?:-H|--header)\s+[''"]Authorization:\s*(?:Bearer|Basic|Token)\s+(?P<TOKEN>[a-zA-Z0-9+/=_-]{20,})[''"]'
confidence: low
min_entropy: 3.5
references:
- https://curl.se/docs/manpage.html#-H
examples:
- 'curl -H ''Authorization: Basic YnJvd3Nlcjo='''
- 'curl -H "Authorization: Bearer cfcabd11c7ed9a41b1a3e063c32d5114"'
- 'curl -H "Authorization: Token 22cb987851bc5659229114c62e60c79abd0d2c08"'

32
data/rules/cursor.yml Normal file
View file

@ -0,0 +1,32 @@
rules:
- name: Cursor Integrations (User) API Key
id: kingfisher.cursor.1
pattern: |
(?xi)
\b
(
key_
[0-9a-f]{64}
)
\b
min_entropy: 3.8
confidence: medium
examples:
- key_8c5a7657fc397e114def1b51dd520410ad50ece61e30b64261ff369ab275ef29
- key_86aed0092d14dd6aae4e8ad107d52f760c5efa4bc3753730ca6983babc2b1072
- key_d9ba91e29d81f1bf2085b55b06f5ac43885749005cff565bee7f406ca2e2f3f9
references:
- https://cursor.com/docs/cloud-agent/api/endpoints
validation:
type: Http
content:
request:
method: GET
url: https://api.cursor.com/v0/me
headers:
Accept: application/json
Authorization: 'Basic {{ TOKEN | b64enc }}'
response_matcher:
- report_response: true
- type: WordMatch
words: ['"userEmail"']

68
data/rules/customerio.yml Normal file
View file

@ -0,0 +1,68 @@
rules:
- name: Customer.io Tracking API Key
id: kingfisher.customerio.1
pattern: |
(?xi)
\b
(?:customer(?:\.?io)?|customerio|cio|tracking|track)
(?:.|[\n\r]){0,32}?
(?:SECRET|PRIVATE|ACCESS|KEY|TOKEN|API[_-]?KEY)
(?:.|[\n\r]){0,16}?
\b
(
[0-9a-f]{20}
)
\b
pattern_requirements:
min_digits: 4
min_entropy: 3.0
confidence: medium
examples:
- "tracking api key: f3b0c2b92eca01472efe"
- "customerio_key = a98eab982f4692ceb78f"
- "customer.io tracking_api_key d24d3915959b4d793a67"
references:
- https://docs.customer.io/integrations/api/#track-api
- name: Customer.io App API Key
id: kingfisher.customerio.2
pattern: |
(?xi)
\b
(?:customer(?:\.?io)?|customerio|cio)
(?:.|[\n\r]){0,32}?
(?:SECRET|PRIVATE|ACCESS|KEY|TOKEN|API)
(?:.|[\n\r]){0,16}?
\b
(
[0-9a-f]{32}
)
\b
pattern_requirements:
min_digits: 6
min_entropy: 3.0
confidence: medium
examples:
- "customerio_app_key=6e86f5734527548b7477a8b627bf4855"
- "customer.io api key 8363e3ca7e897cae7d76b8f46632e155"
- "cio_app_key: 801b93d4c8627282bbd3524362f1ea9d"
references:
- https://docs.customer.io/integrations/api/#app-api
- https://api.customer.io/v1/workspaces
validation:
type: Http
content:
request:
method: GET
url: https://api.customer.io/v1/workspaces
headers:
Authorization: "Bearer {{ TOKEN }}"
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]
- type: JsonValid
- type: WordMatch
match_all_words: true
words:
- '"workspaces"'

View file

@ -2,12 +2,17 @@ rules:
- name: Databricks API token
id: kingfisher.databricks.1
pattern: |
(?xi)
(?xi)
\b
(
dapi
[a-f0-9]{32}
)
\b
\b
pattern_requirements:
min_digits: 2
min_uppercase: 1
min_lowercase: 1
min_entropy: 3.3
confidence: medium
examples:

View file

@ -1,64 +1,117 @@
rules:
- name: Datadog API Key
# Helper: extract the Datadog site domain from common config/env/URLs.
# We capture the "site parameter" (domain), then validation uses https://api.<site>.
- name: Datadog Site Domain
id: kingfisher.datadog.1
visible: false
confidence: medium
min_entropy: 2.0
pattern: |
(?xi)
\b
(?:datadog|dd-|dd_)
(?:.|[\n\r]){0,32}?
(?:SECRET|PRIVATE|ACCESS|KEY|TOKEN)
(?:.|[\n\r]){0,32}?
\b
(?xi)
(?:
# env/config patterns
\b(?:DD_SITE|DATADOG_SITE|DATADOG_HOST)\b\s*[:=]\s*["']?
(?:https?://)?
(?:api\.|app\.)?
|
# raw URLs in code/docs
\bhttps?://(?:api\.|app\.)?
)?
(
[a-z0-9]{32}
datadoghq\.com
| us3\.datadoghq\.com
| us5\.datadoghq\.com
| datadoghq\.eu
| ap1\.datadoghq\.com
| ap2\.datadoghq\.com
| ddog-gov\.com
)
\b
examples:
- DD_SITE=datadoghq.eu
- DATADOG_HOST=https://api.us3.datadoghq.com
- https://app.datadoghq.com
- https://api.ddog-gov.com
- name: Datadog API Key
id: kingfisher.datadog.2
pattern: |
(?xi)
\b(?:datadog|dd)
(?:.|[\n\r]){0,64}?
(?:api[_-]?key|dd[_-]?api[_-]?key|secret|private|access|token)
(?:.|[\n\r]){0,32}?
\b
(
[A-Z0-9]{32}
)
\b
pattern_requirements:
min_digits: 3
min_entropy: 3.3
confidence: medium
examples:
- dd-apikey-dd52c29224affe29d163c6bf99e5c34f
- datadog-secrettoken-0024a29224affe29d173c0bf99e5a89d
- DD_API_KEY=0024a29224affe29d173c0bf99e5a89d
references:
- https://docs.datadoghq.com/account_management/api-app-keys/
validation:
type: Http
content:
request:
method: GET
url: https://api.datadoghq.com/api/v1/validate
headers:
Accept: application/json
DD-API-KEY: '{{ TOKEN }}'
DD-APPLICATION-KEY: '{{ APPKEY }}'
method: GET
DD-API-KEY: "{{ TOKEN }}"
response_matcher:
- report_response: true
- status:
- 200
type: StatusMatch
url: https://api.datadoghq.com/api/v2/current_user
depends_on_rule:
- rule_id: kingfisher.datadog.2
variable: APPKEY
- type: WordMatch
words:
- '"Forbidden"'
negative: true
- name: Datadog Application Secret
id: kingfisher.datadog.2
- name: Datadog Application Key
id: kingfisher.datadog.3
pattern: |
(?xi)
\b
(?:
dd[_-]?\w{0,8}[_-]?(?:key|secret) |
datadog |
dog
)
\b(?:datadog|dd)
(?:.|[\n\r]){0,64}?
(?:app(?:lication)?[_-]?key|dd[_-]?application[_-]?key|secret|private|access|token)
(?:.|[\n\r]){0,32}?
\b
(
[a-z0-9]{40}
[A-Za-z0-9-]{40}
)
\b
min_entropy: 3.3
\b
pattern_requirements:
min_digits: 3
min_entropy: 3.5
confidence: medium
examples:
- dd_secret_key-3c0c3965368a6b10f7640dbda46abfdca981c2d3
- datadog_token = BzHpkcs7LujMb3Q1vLRRjbpBNxxYV0ousumYoKJS
- DD_APPLICATION_KEY=abcDEF0123456789abcDEF0123456789abcDEF01
references:
- https://docs.datadoghq.com/account_management/api-app-keys/
- https://docs.datadoghq.com/account_management/api-app-keys/
- https://docs.datadoghq.com/getting_started/site/
depends_on_rule:
- rule_id: kingfisher.datadog.2
variable: DD_API_KEY
- rule_id: kingfisher.datadog.1
variable: DD_SITE_DOMAIN
validation:
type: Http
content:
request:
method: GET
# Datadog recommends /api/v2/validate_keys to verify app keys with the key pair
url: "https://api.{{ DD_SITE_DOMAIN }}/api/v2/validate_keys"
headers:
Accept: application/json
DD-API-KEY: "{{ DD_API_KEY }}"
DD-APPLICATION-KEY: "{{ TOKEN }}"
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]

40
data/rules/datagov.yml Normal file
View file

@ -0,0 +1,40 @@
rules:
- name: Data.gov API Key
id: kingfisher.datagov.1
pattern: |
(?xi)
\b
data\.gov
(?:.|[\n\r]){0,32}?
(?:SECRET|PRIVATE|ACCESS|KEY|TOKEN)
(?:.|[\n\r]){0,32}?
\b
(
[a-zA-Z0-9]{40}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.5
confidence: medium
examples:
- data.gov_api_key=pBZm2kXbuPdRfzYyarRT0bvcWAisnJg98YJzBJyJ
- data.gov_token=plZJDnKs4OrPeV8wgBr2fYO6VnXb1YPEcVaZbnYI
references:
- https://api.data.gov/docs/developer-manual/
- https://developer.nrel.gov/docs/api-key/
- https://developer.nrel.gov/docs/errors/
validation:
type: Http
content:
request:
method: GET
# NREL (developer.nrel.gov) uses api.data.gov-managed keys and accepts api_key as a query param.
url: "https://developer.nrel.gov/api/alt-fuel-stations/v1.json?limit=1&api_key={{ TOKEN }}"
headers:
Accept: application/json
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]

43
data/rules/deepgram.yml Normal file
View file

@ -0,0 +1,43 @@
rules:
- name: Deepgram API Key
id: kingfisher.deepgram.1
pattern: |
(?xi)
\b
deepgram
(?:.|[\n\r]){0,32}?
\b
(
[0-9a-f]{40}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.5
confidence: medium
examples:
- deepgram_key = 948c19ecde2818a1a357fffb14d2fc2a03d3c56e
- 'deepgram-api: 6c8ba06cb14a32d508948606d8b5d9c8f70e493b'
- deepgram = 12e217f37eb173f0c8f1b7309f4207c7dca20186
- deepgram token 1 == 1f8946087e64b14dffd069b78554e217b3ed34d4
references:
- https://developers.deepgram.com/docs/authenticating
- https://developers.deepgram.com/reference/management-api/models/list
- https://developers.deepgram.com/reference/list-keys
validation:
type: Http
content:
request:
method: GET
url: https://api.deepgram.com/v1/projects
headers:
Authorization: Token {{ TOKEN }}
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]
- type: JsonValid
- type: WordMatch
match_all_words: true
words: ['"name"']

View file

@ -2,12 +2,14 @@ rules:
- name: DeepSeek API Key
id: kingfisher.deepseek.1
pattern: |
(?xi)
(?x)
\b
(
sk-[a-f0-9]{32}
)
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.7
confidence: medium
examples:

View file

@ -0,0 +1,41 @@
rules:
- name: Defined Networking API Token
id: kingfisher.definednetworking.1
pattern: |
(?x)
\b
(
dnkey-
[A-Z0-9]{26}
-
[A-Z0-9]{52}
)
\b
min_entropy: 3.6
confidence: medium
examples:
- 'defined_api_token="dnkey-AHBDSNIG5ATR4LPUX4XTEVXEP4-ACW2JQ45HAWA2XA6FIJNSNBRY2Q4WMSCNNIFSL6VRZQYFZKI2VHA"'
references:
- https://docs.defined.net/api/defined-networking-api/
- https://docs.defined.net/api/networks-list/
- https://docs.defined.net/guides/rotating-api-keys/
validation:
type: Http
content:
request:
method: GET
url: https://api.defined.net/v1/networks
headers:
Accept: application/json
Authorization: "Bearer {{ TOKEN }}"
response_matcher:
- report_response: true
# 200 = valid + authorized
# 403 = valid token but missing required scope (still proves the token is real)
- type: StatusMatch
status: [200, 403]
- type: WordMatch
words:
- '"cidr"'
match_all_words: true

View file

@ -8,6 +8,8 @@ rules:
odt_[A-Z0-9]{32,255}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.3
confidence: medium
examples:

36
data/rules/diffbot.yml Normal file
View file

@ -0,0 +1,36 @@
rules:
- name: Diffbot API Key
id: kingfisher.diffbot.1
pattern: |
(?xi)
\b
diffbot
(?:.|[\n\r]){0,32}?
\b
(
[0-9a-z]{32}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.0
examples:
- diffbot_key = a7424adbafc4624e61482d0f60e43016
references:
- https://docs.diffbot.com/reference/account
validation:
type: Http
content:
request:
method: GET
url: >-
https://api.diffbot.com/v4/account?token={{ TOKEN }}
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]
- type: WordMatch
words:
- '"name"'
- '"email"'
- '"planCredits"'

View file

@ -2,13 +2,15 @@ rules:
- name: DigitalOcean API Key
id: kingfisher.digitalocean.1
pattern: |
(?xi)
(?x)
\b
(
(?:dop|doo)_v1_
[a-f0-9]{64}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.3
confidence: medium
examples:
@ -32,13 +34,11 @@ rules:
- name: DigitalOcean Refresh Token
id: kingfisher.digitalocean.2
pattern: |
(?xi)
\b
(?x)
(
dor_v1_
[a-f0-9]{64}
)
\b
min_entropy: 3.3
confidence: medium
examples:

View file

@ -4,12 +4,15 @@ rules:
pattern: |
(?xi)
(
https://discord\.com/api/webhooks/
\d{18}
https://discord(app)?\.com/api/webhooks/
[0-9]{17,20}
)/
(
[0-9a-z_\-]{68}
[0-9a-z_\-]{60,68}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.5
confidence: medium
examples:
@ -32,7 +35,6 @@ rules:
id: kingfisher.discord.2
pattern: |
(?xi)
\b
(
[MNO][A-Z0-9_-]{23}\.[A-Z0-9_-]{6}\.[A-Z0-9_-]{27}
)
@ -61,17 +63,14 @@ rules:
id: kingfisher.discord.3
pattern: |
(?xi)
\b
(?:discord|botid|bot_id)
(?:.|[\n\r]){0,64}?
\b
(
\d{17,19}
)
\b
min_entropy: 3.5
visible: false
confidence: medium
examples:
- discord = 12345678901234567
- 'bot_id: "123456789012345678"'
- 'bot_id: "123456789012345678"'

39
data/rules/disqus.yml Normal file
View file

@ -0,0 +1,39 @@
rules:
- name: Disqus API Key
id: kingfisher.disqus.1
pattern: |
(?xi)
\b
disqus
(?:.|[\n\r]){0,32}?
(?:SECRET|PRIVATE|ACCESS|KEY|TOKEN)
(?:.|[\n\r]){0,32}?
\b
(
[a-zA-Z0-9]{64}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.3
confidence: medium
examples:
- disqus_secret_key = jK5HbxY2QrPn7vMNL8tADcF3mWg4kXqR9sBdZyE1hVuT6fGwJpC0nI9vUxY2aM3K
- DISQUS_PRIVATE_TOKEN = Nh7vRf3mKp9wXc5tJq2YbL8sAg4dB6TzWeUx1nGQjCkPyDHVME0aI1FSx2Z5vY3n
references:
- https://disqus.com/api/docs/requests/
- https://disqus.com/api/docs/threads/list/
validation:
type: Http
content:
request:
method: GET
url: "https://disqus.com/api/3.0/threads/list.json?limit=1&api_secret={{ TOKEN }}"
headers:
Accept: application/json
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]
- type: WordMatch
words: ['"code":0', '"response"']

View file

@ -5,7 +5,6 @@ rules:
(?x)
[DJANGO]\w{0,8}SECRET_KEY
.{1,16}?
\b
(
[A-Za-z0-9*!$@\#&_%^-]{45,55}
)

50
data/rules/docker.yml Normal file
View file

@ -0,0 +1,50 @@
rules:
- name: Docker Registry Credentials (auths JSON)
id: kingfisher.docker.1
pattern: |
(?xis)
"auths"\s*:\s*\{
[^}]*?
" (?P<REG> (?:https?:\/\/)? [a-z0-9.\-:+/]+ ) "\s*:\s*\{
[^}]*?
"auth"\s*:\s*"(?P<B64> [A-Za-z0-9+/=]{16,} )"
[^}]*?
\}
[^}]*?
\}
pattern_requirements:
min_digits: 2
min_entropy: 2.0
confidence: medium
examples:
- |
{
"auths": {
"quay.io": {
"auth": "cmhkaCtyaHRhcDowM1BERl1RQTJQTDlaQUE5T1gzSU9IQjFYTUlXOVNGNU1XRzNSRVRHNThKVXpKMzEwV0ZZRVMOQTdGMExMNOYx"
}
}
}
- |
{"auths":{"index.docker.io/v1/":{"auth":"dXNlcjp0b2tlbg=="}}}
references:
- https://distribution.github.io/distribution/spec/api/
validation:
type: Http
content:
request:
method: GET
url: >
{%- assign r = REG -%}
{%- if r contains "://" -%}
{{ r | replace: "/$", "" }}/v2/auth
{%- else -%}
https://{{ r }}/v2/auth
{%- endif -%}
headers:
Authorization: "Basic {{ B64 }}"
Accept: application/json
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]

View file

@ -2,12 +2,14 @@ rules:
- name: Docker Hub Personal Access Token
id: kingfisher.dockerhub.1
pattern: |
(?xi)
(?x)
\b
(
dckr_pat_[A-Z0-9_-]{27}
dckr_pat_[A-Za-z0-9_-]{27}
)
(?: $ | [^A-Z0-9_-] )
(?: $ | [^A-Za-z0-9_-] )
pattern_requirements:
min_digits: 2
min_entropy: 3.3
confidence: medium
examples:
@ -29,4 +31,35 @@ rules:
- status:
- 200
type: StatusMatch
url: https://hub.docker.com/v2/access-tokens?page_size=1
url: https://hub.docker.com/v2/access-tokens?page_size=1
- name: Docker Hub Organization Access Token
id: kingfisher.dockerhub.2
pattern: |
(?x)
\b
(
dckr_oat_[A-Za-z0-9_-]{32}
)
(?: $ | [^A-Za-z0-9_-] )
pattern_requirements:
min_digits: 2
min_entropy: 3.3
confidence: medium
examples:
- docker login -u docker-test -p dckr_oat_7bA9zRt5-JqX3vP0l_MnY8sK2wE-dF6h
references:
- https://docs.docker.com/enterprise/security/access-tokens/
validation:
type: Http
content:
request:
headers:
Authorization: Bearer {{ TOKEN }}
Accept: application/json
method: GET
response_matcher:
- report_response: true
- status:
- 200
type: StatusMatch
url: https://hub.docker.com/v2/access-tokens?page_size=1

View file

@ -4,8 +4,12 @@ rules:
pattern: |
(?xi)
\b
(dp\.ct\.[A-Z0-9]{40,44})
(
dp\.ct\.[A-Z0-9]{40,44}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.3
confidence: medium
examples:

View file

@ -15,6 +15,8 @@ rules:
[a-f0-9]{32,64}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.5
confidence: medium
examples:

35
data/rules/dropbox.yml Normal file
View file

@ -0,0 +1,35 @@
rules:
- name: Dropbox API secret/key
id: kingfisher.dropbox.1
pattern: |
(?xi)
\b
(
sl\.[A-Z0-9\-\_]{130,152}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.3
confidence: medium
examples:
- 'curl -X POST https://api.dropboxapi.com/2/users/get_current_account --header "Authorization: Bearer sl.hAi61Jx1hs3XlhrnsCxnctrEmxK2Q-UK29hbdxxHyAykldSeHmipBAauxTzuBEIqt2jdyyUZw8kgY3t_ars-PNIPS27ySa1ab22132U3sUuqYTXHzf2XlvMxSesUhkzx2G11_9W1f-eo"'
- ' "access_token": "sl.AbX9y6Fe3AuH5o66-gmJpR032jwAwQPIVVzWXZNkdzcYT02akC2de219dZi6gxYPVnYPrpvISRSf9lxKWJzYLjtMPH-d9fo_0gXex7X37VIvpty4-G8f4-WX45AcEPfRnJJDwzv-",'
- 'curl -X POST https://api.dropboxapi.com/2/users/get_current_account --header "Authorization: Bearer sl.hAi61Jx1hs3XlhrnsCxnctrEmxK2Q-UK29hbdxxHyAykldSeHmipBAauxTzuBEIqt2jdyyUZw8kgY3t_ars-PNIPS27ySa1ab22132U3sUuqYTXHzf2XlvMxSesUhkzx2G11_9W1f-eo"'
- ' "access_token": "sl.AbX9y6Fe3AuH5o66-gmJpR032jwAwQPIVVzWXZNkdzcYT02akC2de219dZi6gxYPVnYPrpvISRSf9lxKWJzYLjtMPH-d9fo_0gXex7X37VIvpty4-G8f4-WX45AcEPfRnJJDwzv-",'
- sl.lMcWXvCOCR9yRAOXwDg1V_VTsbEXdu3Xpsgg35GQTrDahoIuUnij4H5b6bMnwobZx4XnniaQappZU9j-CCWd-LYW81juiU04-yvLhOPV47Nj7Fs8XSE-CweZp6j9nw4E2oWWJ5
validation:
type: Http
content:
request:
headers:
Authorization: Bearer {{ TOKEN }}
method: POST
response_matcher:
- report_response: true
- match_all_words: true
type: WordMatch
words:
- '"account_id":'
- '"email":'
url: https://api.dropboxapi.com/2/users/get_current_account

34
data/rules/duffel.yml Normal file
View file

@ -0,0 +1,34 @@
rules:
- name: Duffel API Token
id: kingfisher.duffel.1
pattern: |
(?xi)
\b
(
duffel_(?:test|live)_[a-z0-9_\-=]{43}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.2
confidence: medium
examples:
- DUFFEL_TOKEN=duffel_test_qwertyuiopasdfghjklzxcvbnm123456789abcdefgh
- 'Authorization: "Bearer duffel_live_abcd1234efgh5678ijkl9012mnop3456qrstuvwxyza"'
references:
- https://duffel.com/docs/api
validation:
type: Http
content:
request:
method: GET
url: https://api.duffel.com/airlines
headers:
Authorization: 'Bearer {{ TOKEN }}'
Accept: application/json
Duffel-Version: v1
response_matcher:
- report_response: true
- type: StatusMatch
status:
- 200

View file

@ -12,6 +12,8 @@ rules:
[A-Z0-9]{64}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.3
confidence: medium
examples:

View file

@ -9,6 +9,8 @@ rules:
[A-Za-z0-9]{54}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.5
confidence: medium
examples:

38
data/rules/elevenlabs.yml Normal file
View file

@ -0,0 +1,38 @@
rules:
- name: ElevenLabs API Key
id: kingfisher.elevenlabs.1
pattern: |
(?xi)
\b
(
sk_
[0-9a-f]{48}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.5
confidence: medium
examples:
- sk_2a30e5a0d39d5f2c5f6a9d2f95cd016049a6323985479bfd
- sk_da9c0613fdeecfab10b302d6f39a3e371f774feb9eafed56
- sk_82a331629e2128ef70396600809b6a2ff4e433154fa27e1b
references:
- https://elevenlabs.io/docs/api-reference/authentication
- https://elevenlabs.io/docs/api-reference/user/subscription/get
validation:
type: Http
content:
request:
method: GET
url: https://api.elevenlabs.io/v1/user/subscription
headers:
xi-api-key: '{{ TOKEN }}'
response_matcher:
- report_response: true
- type: WordMatch
match_all_words: false
words:
- '"tier"'
- '"missing_permissions"'

61
data/rules/endorlabs.yml Normal file
View file

@ -0,0 +1,61 @@
rules:
- name: Endor Labs API Key
id: kingfisher.endorlabs.1
visible: false
confidence: medium
min_entropy: 3.0
pattern: |
(?xi)
\b
ENDOR_API_CREDENTIALS_KEY
(?:.|[\n\r]){0,32}?
(
endr\+[A-Za-z0-9-]{16}
)
\b
examples:
- ENDOR_API_CREDENTIALS_KEY=endr+foo1234567890abc
pattern_requirements:
min_digits: 2
- name: Endor Labs API Secret
id: kingfisher.endorlabs.2
pattern: |
(?xi)
\b
ENDOR_API_CREDENTIALS_SECRET
(?:.|[\n\r]){0,32}?
(
endr\+[A-Za-z0-9-]{16}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.5
confidence: medium
examples:
- ENDOR_API_CREDENTIALS_SECRET=endr+bar1234567890abc
references:
- https://docs.endorlabs.com/rest-api/authentication/
depends_on_rule:
- rule_id: kingfisher.endorlabs.1
variable: ENDOR_API_KEY
validation:
type: Http
content:
request:
method: POST
# Endor Labs exchanges key+secret for an ENDOR_TOKEN via this endpoint
url: https://api.endorlabs.com/v1/auth/api-key
headers:
Content-Type: application/json
Accept: application/json
body: |
{"key":"{{ ENDOR_API_KEY }}","secret":"{{ TOKEN }}"}
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]
- type: JsonValid
- type: WordMatch
words: ['"token"']

34
data/rules/eraserio.yml Normal file
View file

@ -0,0 +1,34 @@
rules:
- name: Eraser API Key
id: kingfisher.eraser.1
pattern: |
(?xi)
\b
eraser
(?:[^A-Za-z0-9]{0,16})?
(?:SECRET|PRIVATE|ACCESS|KEY|TOKEN)
(?:[^A-Za-z0-9]{0,16})?
\b
(
[A-Za-z0-9]{20}
)
\b
min_entropy: 3.5
confidence: medium
examples:
- eraser_token = Q7MD4J9L2X0B6R3T8W1P
references:
- https://eraser.io/docs/api/authentication
validation:
type: Http
content:
request:
method: GET
url: https://app.eraser.io/api/reports/usage?rangeDays=1
headers:
Authorization: "Bearer {{ TOKEN }}"
accept: application/json
response_matcher:
- report_response: true
- type: StatusMatch
status: [200, 403]

42
data/rules/eventbrite.yml Normal file
View file

@ -0,0 +1,42 @@
rules:
- name: Eventbrite API Key
id: kingfisher.eventbrite.1
pattern: |
(?xi)
\b
eventbrite
(?:.|[\n\r]){0,32}?
(?:SECRET|PRIVATE|ACCESS|KEY|TOKEN)
(?:.|[\n\r]){0,32}?
\b
(
[0-9A-Z]{20}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.5
confidence: medium
examples:
- eventbrite secretkey X7W8HTTHLVYXPPVRZJZS
- eventbrite privatekey YTR4GR5T89WQP8HJKLDF
- '"eventbrite private access key ZXC2JK3HV4TY5UIO6PLK"'
- eventbrite token ABCDEF1234567890QRST
references:
- https://www.eventbrite.com/platform/docs/authentication
- https://www.eventbrite.com/platform/docs/organizations
validation:
type: Http
content:
request:
method: GET
url: https://www.eventbriteapi.com/v3/users/me/organizations/
headers:
Authorization: "Bearer {{ TOKEN }}"
Accept: application/json
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]
- type: WordMatch
words: ['"organizations"']

46
data/rules/exaai.yml Normal file
View file

@ -0,0 +1,46 @@
rules:
- name: Exa AI API Key
id: kingfisher.exa.1
pattern: |
(?xi)
(?:
\b(?:exa|exa[_-]?api|exa[_-]?key|exa[_-]?api[_-]?key)\b
(?:.|[\n\r]){0,96}?
|
\bx-api-key\b
(?:\s*[:=]\s*|(?:.|[\n\r]){0,16}?)
)
\b
(
[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}
)
\b
pattern_requirements:
min_digits: 4
min_entropy: 3.0
confidence: medium
examples:
- EXA_API_KEY=3f5a9c1e-2b4d-4a6f-8c10-1d2e3f4a5b6c
- 'exa_api_key: "3f5a9c1e-2b4d-4a6f-8c10-1d2e3f4a5b6c"'
- 'x-api-key: 3f5a9c1e-2b4d-4a6f-8c10-1d2e3f4a5b6c'
references:
- https://docs.exa.ai/reference/answer
- https://docs.exa.ai/reference/getting-started
validation:
type: Http
content:
request:
method: POST
url: https://api.exa.ai/answer
headers:
x-api-key: "{{ TOKEN }}"
Content-Type: application/json
Accept: application/json
body: |
{"query":"ping","text":false}
response_matcher:
- report_response: true
- type: StatusMatch
status: [200]
- type: WordMatch
words: ['"answer"']

View file

@ -2,17 +2,19 @@ rules:
- name: Facebook App ID
id: kingfisher.facebook.1
pattern: |
(?xi)
\b
(?xi)
\b
(?:facebook|fb)
(?:.|[\n\r]){0,8}?
(?:APP|APPLICATION)
(?:.|[\n\r]){0,16}?
\b
(?:.|[\n\r]){0,32}?
(?:APP|APPLICATION|CLIENT)
(?:.|[\n\r]){0,32}?
\b
(
\d{15}
)
\b
)
\b
pattern_requirements:
min_digits: 15
min_entropy: 2.0
visible: false
confidence: medium
@ -25,18 +27,24 @@ rules:
id: kingfisher.facebook.2
pattern: |
(?xi)
\b (?: facebook | fb )
.?
(?: api | app | application | client | consumer | customer | secret | key )
.?
(?: key | oauth | sec | secret )?
\b
(?: facebook | fb )
(?:.|[\n\r]){0,32}?
(?:SECRET|PRIVATE|ACCESS|KEY|TOKEN|AUTH)
(?:.|[\n\r]){0,48}?
.{0,2} \s{0,20} .{0,2} \s{0,20} .{0,2}
\b ([a-z0-9]{32}) \b
\b
(
[a-z0-9]{32}
)
\b
examples:
- ' # config.facebook.key = "34cebc81c056a21bc66e212f947d73ec"'
- " var fbApiKey = '0278fc1adf6dc1d82a156f306ce2c5cc';"
- ' fbApiKey: "171e84fd57f430fc59afa8fad3dbda2a",'
- '"facebook appSecret = "ce3f9f0362bbe5ab01dfc8ee565e4372"'
pattern_requirements:
min_digits: 2
validation:
type: Http
content:
@ -69,9 +77,12 @@ rules:
(?:access_token|access[\s-]token)
(?:.|[\n\r]){0,32}?
)?
(
EAACEdEose0cBA[A-Z0-9]{20,}
)
\b
(EAACEdEose0cBA[A-Z0-9]{20,})
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.3
confidence: medium
examples:

View file

@ -9,8 +9,12 @@ rules:
(?:SECRET|PRIVATE|ACCESS|KEY|TOKEN)
(?:.|[\n\r]){0,32}?
\b
([a-z0-9_-]{32})
(
[a-z0-9_-]{32}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.5
confidence: medium
examples:

View file

@ -8,6 +8,8 @@ rules:
figd_[A-Z0-9_-]{38,42}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.5
confidence: medium
examples:
@ -36,14 +38,14 @@ rules:
(?xi)
figma
(?:.|[\n\r]){0,32}?
\b
(
[0-9A-F]{4}
-[0-9A-F]{8}
(?:-[0-9A-F]{4}){3}
-[0-9A-F]{12}
)
\b
pattern_requirements:
min_digits: 2
examples:
- "--header='X-Figma-Token: 1394-0ca7a5be-8e22-40ee-8c40-778d41ab2313'"
references:

View file

@ -14,6 +14,8 @@ rules:
\.[A-Z0-9]{20}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.3
confidence: medium
examples:

38
data/rules/filezilla.yml Normal file
View file

@ -0,0 +1,38 @@
rules:
- name: FileZilla base64 encoded password
id: kingfisher.filezilla.1
pattern: <Pass\b[^>]*\bencoding\s*=\s*"(?:base64|radix64)"[^>]*>\s*([A-Za-z0-9+/]{8,}={0,2})\s*</Pass>
min_entropy: 3.2
confidence: low
pattern_requirements:
ignore_if_contains:
- "ZXhhbXBsZQ==" # "example" (base64)
- "cGFzc3dvcmQ=" # "password" (base64)
- "Y2hhbmdlbWU=" # "changeme" (base64)
examples:
- '<Pass encoding="base64">VGhpc0lzQVRlc3RQYXNzd29yZA==</Pass>'
- '<FileZilla3><RecentServers><Server><Pass encoding="base64">NjllNWU5ZWMwZDU0MmU5Y2QwOTY4MWM5YzZhMDdkYWVmNjg3OWE3MDMzM2Q4MWJmCg==</Pass></Server></RecentServers></FileZilla3>'
references:
- https://forum.filezilla-project.org/viewtopic.php?style=246&t=38820
- https://forum.filezilla-project.org/viewtopic.php?p=133138
- https://forum.filezilla-project.org/viewtopic.php?t=24758
- name: FileZilla stored password (Pass plaintext)
id: kingfisher.filezilla.2
pattern: <Pass>\s*([^<\r\n]{4,128})\s*</Pass>
min_entropy: 2.8
confidence: low
pattern_requirements:
ignore_if_contains:
- example
- Example
- password
- Password
- changeme
- ChangeMe
examples:
- "<Pass>ExamplePas123</Pass>"
- "<FileZilla3><Servers><Server><Pass>superS3cret!</Pass></Server></Servers></FileZilla3>"
references:
- https://stackoverflow.com/questions/29790136/filezilla-plain-text-password
- https://forum.filezilla-project.org/viewtopic.php?t=24758

View file

@ -13,6 +13,8 @@ rules:
[a-f0-9]{32}
)
\b
pattern_requirements:
min_digits: 2
min_entropy: 3.5
confidence: medium
examples:

Some files were not shown because too many files have changed in this diff Show more