pleno-dlp

module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 7, 2026 License: AGPL-3.0

README

pleno-dlp

Trufflehog-compatible DLP scanner — secrets and PII — over the local filesystem, git history, and SaaS content. AGPL-3.0.

go install github.com/plenoai/pleno-dlp/cmd/pleno-dlp@latest

pleno-dlp scan filesystem ./repo
pleno-dlp scan git --repo ./repo --max-depth 200
pleno-dlp scan filesystem ./repo --format sarif --verify > findings.sarif

Two surfaces in one repo. Pick the one that matches your scan target:

  • Go binary (cmd/pleno-dlp/) — filesystem and local git history. Trufflehog-compatible detector interface, archive-aware (zip / tar / tar.gz / gzip), base64 / percent / hex decoder pipeline. Tag pattern vX.Y.Z. This README.
  • Python package (python/) — SaaS sources via saas-retriever (GitHub, GitLab, Bitbucket, Slack, Notion, Confluence, Jira). Backends: trufflehog / gitleaks / native (regex) for secrets; pii for delegated PII inference. Tag pattern py-vX.Y.Z. See python/README.md.

Detector matrix

27 detectors today. Verify column lists detectors that can confirm a candidate against the upstream provider (--verify flag); detectors without an upstream verification path emit findings as Verified=false.

Detector Match Verify
AWS AKIA… access-key + nearest 40-char secret sts:GetCallerIdentity
GCP service account JSON key blob OAuth token exchange
Azure storage key base64 88-char regex only
GitHub classic + fine-grained PAT GET /user
GitLab glpat-… GET /personal_access_tokens/self
Stripe sk_live_ / sk_test_ / rk_live_ GET /v1/charges
Slack bot xoxb-… auth.test
Slack webhook hooks.slack.com/services/… regex only
OpenAI sk-… GET /v1/models
Anthropic sk-ant-… GET /v1/models
Datadog API key + App key pair GET /api/v1/validate
NPM npm_… GET /-/whoami
PyPI pypi-AgEIc… GET upload.pypi.org/legacy/
HuggingFace hf_… GET /api/whoami-v2
Cloudflare API token (keyword-gated) GET /user/tokens/verify
SendGrid SG.… GET /v3/scopes
Twilio AC… SID + 32-hex auth token pair GET /Accounts/<sid>.json
JWT three-segment base64url regex only (decodes claims to ExtraData)
Private key (PEM) -----BEGIN … PRIVATE KEY----- regex only
DigitalOcean dop_v1_… GET /v2/account
Sentry DSN https://<32hex>@…/<id> regex only
MongoDB Atlas public+private key pair GET /api/atlas/v2/orgs (Basic)
HubSpot pat-… GET /integrations/v1/me
Salesforce refresh 5Aep861… OAuth refresh regex only (Severity=Medium)
New Relic NRRA / NRAK / NRII keys GET /v2/applications.json (NRRA only)
PagerDuty 20-char alnum (keyword-gated) GET /users
Postman PMAK-… GET /me
Mailgun key-… (legacy) / …-…-… (new) GET /v3/domains
Terraform Cloud …atlasv1.… GET /api/v2/account/details

Add org-specific patterns without forking the binary — see Custom rules below.

Severity and CI gating

Every finding carries a Severity:

When Severity
Verified=true Critical
Unverified explicit detector High
Generic high-entropy / JWT / PEM unverified Medium

Use --fail-on to choose what blocks the build:

pleno-dlp scan filesystem ./repo --fail-on critical    # only Critical = exit 1
pleno-dlp scan filesystem ./repo --fail-on high        # High and Critical
pleno-dlp scan filesystem ./repo                       # default: any finding

SARIF output maps Severity to GitHub Code Scanning levels (Critical/High → error, Medium → warning, Low/Info → note). partialFingerprints carries secret/v1 (sha256(detector|raw)) so GitHub dedups the same leak across PRs.

Custom rules

JSON file passed via --rules:

[
  {
    "name": "ACME Internal API Key",
    "keywords": ["ACME_API_KEY", "x-acme-token"],
    "regex": "ACME_[A-Z0-9]{20}",
    "entropy_min": 3.5,
    "severity": "high",
    "verify_url": "https://api.acme.example/verify",
    "verify_header": "Authorization: Bearer {{ .Secret }}"
  }
]

keywords are required (they gate the regex from running on every chunk). verify_url is optional; when set, a 200 response counts as verified, 401/403 as unverified, transport errors surface as VerificationErr.

pleno-dlp scan filesystem ./repo --rules ./acme-rules.json

Decoding and archives

The engine expands every chunk through:

  1. Archive walker — zip, tar, tar.gz, plain gzip, recursively up to depth 4 (configurable). Inner entries carry ExtraData["archive_path"] = "outer.zip!inner.tar.gz!leak.env" so the trail is visible in output.
  2. Decoder pipeline — base64 (std + url-safe), percent-encoded, hex (>=40 chars). Decoded variants are scanned alongside the original; hits stamp ExtraData["decoded_from"].

A printable-byte gate keeps binary noise from reaching detectors and hard limits (50 MiB per entry, 200 MiB total expanded, depth cap) defeat zip-bomb DoS.

Git history scan

pleno-dlp scan git --repo ./repo
pleno-dlp scan git --repo ./repo --branch main --max-depth 500
pleno-dlp scan git --repo ./repo --since 2024-01-01T00:00:00Z
pleno-dlp scan git --repo ./repo --include 'src/**' --exclude '**/*_test.go'

Walks every commit reachable from HEAD (or --branch) oldest-first, diffs each commit against its first parent, emits one Chunk per added/modified blob with full GitMeta (repo path, commit SHA, file, first-changed line, committer email).

Output formats

--format table       # human-readable, default
--format json        # array of findings, machine-parseable
--format sarif       # SARIF 2.1.0, GitHub Code Scanning compliant

Pipe SARIF to GitHub Code Scanning:

# .github/workflows/secret-scan.yml
- run: pleno-dlp scan filesystem . --format sarif > findings.sarif
- uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: findings.sarif

Install

# Latest release
go install github.com/plenoai/pleno-dlp/cmd/pleno-dlp@latest

# Pre-built archive (linux / darwin / windows × amd64 / arm64)
# https://github.com/plenoai/pleno-dlp/releases

# From source
git clone https://github.com/plenoai/pleno-dlp
cd pleno-dlp
go build ./cmd/pleno-dlp

Development

go test ./... -race    # full test suite, race-clean
go build ./...

Releases trigger exclusively on tag push:

  • vX.Y.Z → Go binary release via GoReleaser trusted publishing.
  • py-vX.Y.Z → Python package release to PyPI via trusted publishing.

main push runs build + tests only.

License

AGPL-3.0 — matching pleno-anonymize.

Directories

Path Synopsis
cmd
pleno-dlp command
Command pleno-dlp is a Go-native secret scanner with a trufflehog-compatible detector layer and a fresh source-connector layer.
Command pleno-dlp is a Go-native secret scanner with a trufflehog-compatible detector layer and a fresh source-connector layer.
pleno-dlp/cmd
Package cmd hosts cobra subcommands for the pleno-dlp binary.
Package cmd hosts cobra subcommands for the pleno-dlp binary.
pkg
archive
Package archive expands a byte slice that looks like a container file (zip, tar, tar.gz, plain gzip) into its inner entries so detectors run against the contents instead of the compressed envelope.
Package archive expands a byte slice that looks like a container file (zip, tar, tar.gz, plain gzip) into its inner entries so detectors run against the contents instead of the compressed envelope.
decoder
Package decoder expands a chunk of bytes into the original plus any decoded variants worth re-scanning.
Package decoder expands a chunk of bytes into the original plus any decoded variants worth re-scanning.
detectors
Package detectors defines the trufflehog-compatible Detector interface and the Result shape returned to the engine.
Package detectors defines the trufflehog-compatible Detector interface and the Result shape returned to the engine.
detectors/all
Package all blank-imports every concrete detector so that their init() functions run and register themselves with pkg/detectors.
Package all blank-imports every concrete detector so that their init() functions run and register themselves with pkg/detectors.
detectors/anthropic
Package anthropic detects Anthropic API keys (sk-ant-…) and verifies them with a 1-token /v1/messages probe.
Package anthropic detects Anthropic API keys (sk-ant-…) and verifies them with a 1-token /v1/messages probe.
detectors/asana
Package asana detects Asana personal access tokens (PAT shape: 1/<16 digits>/<32 hex>) and verifies them against /users/me.
Package asana detects Asana personal access tokens (PAT shape: 1/<16 digits>/<32 hex>) and verifies them against /users/me.
detectors/atlassian
Package atlassian detects Atlassian Cloud API tokens (24-char base62).
Package atlassian detects Atlassian Cloud API tokens (24-char base62).
detectors/aws
Package aws detects AWS access key id / secret access key pairs and optionally verifies them via sts:GetCallerIdentity.
Package aws detects AWS access key id / secret access key pairs and optionally verifies them via sts:GetCallerIdentity.
detectors/bitbucketcloud
Package bitbucketcloud detects Bitbucket Cloud repository / workspace / project access tokens (`ATCTT3xFfGF0…` and the legacy 32-char base62 app passwords) and verifies them as Bearer credentials against /2.0/user.
Package bitbucketcloud detects Bitbucket Cloud repository / workspace / project access tokens (`ATCTT3xFfGF0…` and the legacy 32-char base62 app passwords) and verifies them as Bearer credentials against /2.0/user.
detectors/brevo
Package brevo detects Brevo (formerly Sendinblue) API keys (xkeysib-<64 hex>-<16 alnum>) and verifies them against /v3/account.
Package brevo detects Brevo (formerly Sendinblue) API keys (xkeysib-<64 hex>-<16 alnum>) and verifies them against /v3/account.
detectors/cloudflare
Package cloudflare detects Cloudflare API tokens (40-char URL-safe) when they appear near a "cloudflare" or CF_API_TOKEN keyword, and verifies them at /client/v4/user/tokens/verify.
Package cloudflare detects Cloudflare API tokens (40-char URL-safe) when they appear near a "cloudflare" or CF_API_TOKEN keyword, and verifies them at /client/v4/user/tokens/verify.
detectors/cohere
Package cohere detects Cohere API keys (40-char base62) and verifies them against /v1/check-api-key.
Package cohere detects Cohere API keys (40-char base62) and verifies them against /v1/check-api-key.
detectors/confluence
Package confluence detects Atlassian Confluence API tokens (24-char base62) near a "confluence" keyword.
Package confluence detects Atlassian Confluence API tokens (24-char base62) near a "confluence" keyword.
detectors/custom
Package custom turns a JSON config file into runtime Detector objects so teams can add org-specific patterns ("ACME_API_KEY=…", internal token prefixes, license-key shapes) without forking the binary.
Package custom turns a JSON config file into runtime Detector objects so teams can add org-specific patterns ("ACME_API_KEY=…", internal token prefixes, license-key shapes) without forking the binary.
detectors/datadog
Package datadog detects Datadog API keys (32 hex) optionally paired with Application keys (40 hex), and verifies them via /api/v1/validate.
Package datadog detects Datadog API keys (32 hex) optionally paired with Application keys (40 hex), and verifies them via /api/v1/validate.
detectors/digitalocean
Package digitalocean detects DigitalOcean personal access tokens (dop_v1_<64 hex>) and verifies them via /v2/account.
Package digitalocean detects DigitalOcean personal access tokens (dop_v1_<64 hex>) and verifies them via /v2/account.
detectors/discord
Package discord detects Discord bot tokens (`<base64-id>.<base64-ts>.<hmac>`) and verifies them against /users/@me with the `Bot <token>` Authorization scheme.
Package discord detects Discord bot tokens (`<base64-id>.<base64-ts>.<hmac>`) and verifies them against /users/@me with the `Bot <token>` Authorization scheme.
detectors/dropbox
Package dropbox detects Dropbox short-lived access tokens (`sl.…`) and long-lived app/refresh tokens, verifying them via /2/users/get_current_account.
Package dropbox detects Dropbox short-lived access tokens (`sl.…`) and long-lived app/refresh tokens, verifying them via /2/users/get_current_account.
detectors/flyio
Package flyio detects Fly.io macaroon tokens (fm1_/fm2_ prefixes) and verifies them by hitting the Machines API.
Package flyio detects Fly.io macaroon tokens (fm1_/fm2_ prefixes) and verifies them by hitting the Machines API.
detectors/gcp
Package gcp detects Google Cloud service-account JSON credentials and verifies them by exchanging a self-signed RS256 JWT for an OAuth2 access token at https://oauth2.googleapis.com/token.
Package gcp detects Google Cloud service-account JSON credentials and verifies them by exchanging a self-signed RS256 JWT for an OAuth2 access token at https://oauth2.googleapis.com/token.
detectors/github
Package github detects GitHub Personal Access Tokens (classic and fine-grained) and verifies them against api.github.com/user.
Package github detects GitHub Personal Access Tokens (classic and fine-grained) and verifies them against api.github.com/user.
detectors/gitlab
Package gitlab detects GitLab Personal Access Tokens (glpat-…) and verifies them against api/v4/personal_access_tokens/self.
Package gitlab detects GitLab Personal Access Tokens (glpat-…) and verifies them against api/v4/personal_access_tokens/self.
detectors/groq
Package groq detects Groq Cloud API keys (`gsk_…`) and verifies them against /openai/v1/models.
Package groq detects Groq Cloud API keys (`gsk_…`) and verifies them against /openai/v1/models.
detectors/heroku
Package heroku detects Heroku API tokens (UUIDs) and verifies them against /account.
Package heroku detects Heroku API tokens (UUIDs) and verifies them against /account.
detectors/hubspot
Package hubspot detects HubSpot Private App access tokens (pat-...) and verifies them against /integrations/v1/me.
Package hubspot detects HubSpot Private App access tokens (pat-...) and verifies them against /integrations/v1/me.
detectors/huggingface
Package huggingface detects HuggingFace user access tokens (hf_…) and verifies them via /api/whoami-v2.
Package huggingface detects HuggingFace user access tokens (hf_…) and verifies them via /api/whoami-v2.
detectors/intercom
Package intercom detects Intercom access tokens (`dG9rOg…` — base64 of "tok:") and verifies them against /me.
Package intercom detects Intercom access tokens (`dG9rOg…` — base64 of "tok:") and verifies them against /me.
detectors/jira
Package jira detects Atlassian Jira API tokens (24-char base62) near a "jira" / "atlassian" keyword.
Package jira detects Atlassian Jira API tokens (24-char base62) near a "jira" / "atlassian" keyword.
detectors/jwt
Package jwt detects JSON Web Tokens (header.payload.signature, base64url encoded) and surfaces the iss/sub claims in ExtraData.
Package jwt detects JSON Web Tokens (header.payload.signature, base64url encoded) and surfaces the iss/sub claims in ExtraData.
detectors/linear
Package linear detects Linear personal API keys (lin_api_<40>) and verifies them against the GraphQL endpoint.
Package linear detects Linear personal API keys (lin_api_<40>) and verifies them against the GraphQL endpoint.
detectors/mailchimp
Package mailchimp detects Mailchimp API keys (32 hex + "-us" + dc number) and verifies them against the per-datacenter API root.
Package mailchimp detects Mailchimp API keys (32 hex + "-us" + dc number) and verifies them against the per-datacenter API root.
detectors/mailgun
Package mailgun detects Mailgun API keys (legacy "key-..." and the newer "<32 hex>-<8 hex>-<8 hex>" shape) and verifies them against /v3/domains using HTTP Basic auth (api:<key>).
Package mailgun detects Mailgun API keys (legacy "key-..." and the newer "<32 hex>-<8 hex>-<8 hex>" shape) and verifies them against /v3/domains using HTTP Basic auth (api:<key>).
detectors/mistral
Package mistral detects Mistral AI API keys (32-char base62) and verifies them against /v1/models.
Package mistral detects Mistral AI API keys (32-char base62) and verifies them against /v1/models.
detectors/mixpanel
Package mixpanel detects Mixpanel service-account credentials.
Package mixpanel detects Mixpanel service-account credentials.
detectors/mongodbatlas
Package mongodbatlas detects MongoDB Atlas Programmatic API key pairs (8-char public key + UUID-shaped private key) and verifies them against /api/atlas/v2/orgs.
Package mongodbatlas detects MongoDB Atlas Programmatic API key pairs (8-char public key + UUID-shaped private key) and verifies them against /api/atlas/v2/orgs.
detectors/netlify
Package netlify detects Netlify personal access tokens (nfp_<40>) and verifies them against /api/v1/user.
Package netlify detects Netlify personal access tokens (nfp_<40>) and verifies them against /api/v1/user.
detectors/newrelic
Package newrelic detects New Relic keys in three flavors:
Package newrelic detects New Relic keys in three flavors:
detectors/notion
Package notion detects Notion integration tokens (secret_<43>) and verifies them against /v1/users/me.
Package notion detects Notion integration tokens (secret_<43>) and verifies them against /v1/users/me.
detectors/npm
Package npm detects npm automation/granular tokens (npm_…) and verifies them against registry.npmjs.org/-/whoami.
Package npm detects npm automation/granular tokens (npm_…) and verifies them against registry.npmjs.org/-/whoami.
detectors/okta
Package okta detects Okta API tokens (00...
Package okta detects Okta API tokens (00...
detectors/openai
Package openai detects OpenAI API keys (sk-…, sk-proj-…) and verifies them against the /v1/models endpoint.
Package openai detects OpenAI API keys (sk-…, sk-proj-…) and verifies them against the /v1/models endpoint.
detectors/openrouter
Package openrouter detects OpenRouter API keys (`sk-or-v1-…`) and verifies them against /api/v1/auth/key.
Package openrouter detects OpenRouter API keys (`sk-or-v1-…`) and verifies them against /api/v1/auth/key.
detectors/pagerduty
Package pagerduty detects PagerDuty REST API tokens (20-char alnum) and verifies them against /users.
Package pagerduty detects PagerDuty REST API tokens (20-char alnum) and verifies them against /users.
detectors/paypal
Package paypal detects PayPal REST API client_id / client_secret pairs and verifies them by minting an OAuth access token at /v1/oauth2/token.
Package paypal detects PayPal REST API client_id / client_secret pairs and verifies them by minting an OAuth access token at /v1/oauth2/token.
detectors/plaid
Package plaid detects Plaid client_id (24-hex) + secret (30-hex) pairs and verifies them by POSTing to /categories/get, the cheapest sandbox-safe endpoint that authenticates the pair without side effects.
Package plaid detects Plaid client_id (24-hex) + secret (30-hex) pairs and verifies them by POSTing to /categories/get, the cheapest sandbox-safe endpoint that authenticates the pair without side effects.
detectors/postman
Package postman detects Postman API keys (PMAK-...) and verifies them against /me.
Package postman detects Postman API keys (PMAK-...) and verifies them against /me.
detectors/postmark
Package postmark detects Postmark server API tokens (UUID shape) and verifies them against /server.
Package postmark detects Postmark server API tokens (UUID shape) and verifies them against /server.
detectors/privatekey
Package privatekey detects PEM-encoded private keys (RSA, EC, OpenSSH, PGP, DSA, Ed25519, generic PKCS8).
Package privatekey detects PEM-encoded private keys (RSA, EC, OpenSSH, PGP, DSA, Ed25519, generic PKCS8).
detectors/pypi
Package pypi detects PyPI upload tokens (pypi-AgEIc…) and verifies them against the upload endpoint.
Package pypi detects PyPI upload tokens (pypi-AgEIc…) and verifies them against the upload endpoint.
detectors/render
Package render detects Render API keys (rnd_<14>) and verifies them via /v1/owners.
Package render detects Render API keys (rnd_<14>) and verifies them via /v1/owners.
detectors/replicate
Package replicate detects Replicate API tokens (`r8_…`) and verifies them against /v1/account.
Package replicate detects Replicate API tokens (`r8_…`) and verifies them against /v1/account.
detectors/salesforcerefresh
Package salesforcerefresh detects Salesforce OAuth refresh tokens (5Aep861...
Package salesforcerefresh detects Salesforce OAuth refresh tokens (5Aep861...
detectors/segment
Package segment detects Segment write keys (32-char base62-ish).
Package segment detects Segment write keys (32-char base62-ish).
detectors/sendgrid
Package sendgrid detects SendGrid API keys (SG.<id>.<secret>) and verifies them against /v3/scopes.
Package sendgrid detects SendGrid API keys (SG.<id>.<secret>) and verifies them against /v3/scopes.
detectors/sentry
Package sentry detects Sentry DSN URLs (https://<32 hex>@<host>/<project>).
Package sentry detects Sentry DSN URLs (https://<32 hex>@<host>/<project>).
detectors/slack
Package slack detects Slack bot tokens (xoxb-…) and verifies them against auth.test.
Package slack detects Slack bot tokens (xoxb-…) and verifies them against auth.test.
detectors/square
Package square detects Square access tokens (production `EAAA…` and sandbox `sq0atp-…`) and verifies them via /v2/locations.
Package square detects Square access tokens (production `EAAA…` and sandbox `sq0atp-…`) and verifies them via /v2/locations.
detectors/stripe
Package stripe detects Stripe live/test secret keys (sk_live_, sk_test_, rk_live_) and verifies them via the /v1/charges list endpoint.
Package stripe detects Stripe live/test secret keys (sk_live_, sk_test_, rk_live_) and verifies them via the /v1/charges list endpoint.
detectors/terraformcloud
Package terraformcloud detects Terraform Cloud / Enterprise API tokens (<14 alnum>.atlasv1.<60+ url-safe>) and verifies them against /api/v2/account/details.
Package terraformcloud detects Terraform Cloud / Enterprise API tokens (<14 alnum>.atlasv1.<60+ url-safe>) and verifies them against /api/v2/account/details.
detectors/together
Package together detects Together.ai API keys (64-char lowercase hex) and verifies them against /v1/models.
Package together detects Together.ai API keys (64-char lowercase hex) and verifies them against /v1/models.
detectors/twilio
Package twilio detects Twilio Account SID + Auth Token pairs and verifies them against /2010-04-01/Accounts/<sid>.json.
Package twilio detects Twilio Account SID + Auth Token pairs and verifies them against /2010-04-01/Accounts/<sid>.json.
detectors/vercel
Package vercel detects Vercel API access tokens.
Package vercel detects Vercel API access tokens.
engine
Package engine drives the scan loop: it pulls chunks from a Source, runs each registered Detector against chunks whose data contains at least one of the detector's keywords, and forwards results to the configured output sink.
Package engine drives the scan loop: it pulls chunks from a Source, runs each registered Detector against chunks whose data contains at least one of the detector's keywords, and forwards results to the configured output sink.
output
Package output owns the user-visible reporting surface.
Package output owns the user-visible reporting surface.
sources
Package sources defines the Source interface and the Chunk shape that detectors consume.
Package sources defines the Source interface and the Chunk shape that detectors consume.
sources/all
Package all blank-imports every concrete source so their init() registers against pkg/sources.registry.
Package all blank-imports every concrete source so their init() registers against pkg/sources.registry.
sources/filesystem
Package filesystem is a Source that walks one or more paths and emits one Chunk per regular file.
Package filesystem is a Source that walks one or more paths and emits one Chunk per regular file.
sources/git
Package git is a Source that walks the commit history of a local git repository and emits one Chunk per added/modified file blob per commit.
Package git is a Source that walks the commit history of a local git repository and emits one Chunk per added/modified file blob per commit.
sources/stdin
Package stdin is a Source that reads a single chunk from os.Stdin (or any io.Reader, for tests) and emits it once.
Package stdin is a Source that reads a single chunk from os.Stdin (or any io.Reader, for tests) and emits it once.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL