docs
stormdoor.dev
GATE

/v1/secrets

Scans free text for leaked credentials — private keys, named-provider tokens, and generic high-entropy secrets — using gitleaks' default detection rules.

METHOD
POST
BODY CAP
64 KiB
CHECKS
7
FINDING CODES
7

POST /v1/secrets scans a block of free text — a support ticket, a pasted .env, a log line, anything you’re about to store or forward — for credentials that shouldn’t be there.

Request#

{ "text": "AWS_SECRET_ACCESS_KEY=AKIAZQ3XVGH4KJPBMNRT", "redact": "mask" }

(Not AWS’s own docs placeholder, AKIA...EXAMPLE — gitleaks’ aws-access-token rule allowlists anything ending EXAMPLE by design, so that value never fires here either.)

Field Type Required Notes
text string yes Bounded only by this gate’s 64 KB request-body cap (D-80) — no separate limit here. That’s roughly 60,000 characters of English text; fewer for text with accents or emoji.
redact string no Only "mask" is accepted; anything else is a 400 invalid_request. See “Redaction” below.

Checks this gate runs#

Every check here is pure rule-based text scanning — gitleaks’ own regexes, keyword prefilter, entropy thresholds and allowlists, all reimplemented over Go’s own regexp, no network calls, no model inference — so all of them are free on every plan (CLAUDE.md design rule 4: “Never withhold a zero-marginal-cost check”).

Check What it does
secret.private_key A -----BEGIN ... PRIVATE KEY----- PEM block — see secret.private_key.
secret.provider_token A named provider’s own token format — AWS, GitHub, Stripe, Slack, and ~215 more — see secret.provider_token.
secret.jwt A JSON Web Token, unless its claims mark it as a public anon key — see secret.jwt.
secret.connection_string A database or broker URL with a password in it — see secret.connection_string.
secret.url_credentials A password in an http(s) URL or a Basic Authorization header — see secret.url_credentials.
secret.test_mode_token A Stripe sk_test_/rk_test_ key — see secret.test_mode_token.
secret.generic_credential A keyword (api, key, secret, token, password, …) next to a high-entropy value, gitleaks’ catch-all for anything with no named pattern — see secret.generic_credential.

Eight finding codes cover roughly 220 individual detection rules plus our own patterns — gitleaks’ own rule id rides along in data.matches[].rule (e.g. "github-pat", "aws-access-token") for a caller who wants to act on the specific pattern without parsing a finding’s message.

Source and licence#

The detection rules are gitleaks’ own default ruleset (MIT licence), fetched at a pinned release (v8.30.1) and embedded like every other StormDoor reference list — not re-derived, not hand-picked. meta.ruleset reflects the pinned version. We reimplement gitleaks’ matching semantics (keyword prefilter, secretGroup extraction, Shannon-entropy thresholds, allowlists) over Go’s own regexp rather than shelling out to the gitleaks binary, so every rule runs unchanged but as one in-process scan.

What this gate does not cover#

  • It never tests a credential against the provider it looks like it belongs to. Format-only verification is the whole product here — calling AWS, GitHub, or Stripe with a value we found in someone’s request body would mean using a stranger’s credential to find out if it’s real, which we won’t do. A secret.provider_token finding means “this looks like a live AWS/GitHub/Stripe/etc. key,” not “this key still works.”
  • No free-floating entropy scan. Every check requires a recognisable shape (a PEM header, a provider’s own prefix, or a credential-shaped keyword next to a high-entropy value) — a bare high-entropy string with no such context is not flagged. That would flag every hash, UUID, and base64 image alongside real secrets.
  • We never echo the matched value. A finding’s message names the pattern that matched (from the rule’s own description), never the secret itself — the same rule /v1/pii follows, and the reason location is an offset, not a quote.

Overlapping matches#

A private-key match always wins over anything inside its PEM block. A named-provider match always wins over a generic-credential match on the same span — gitleaks’ own generic-vs-specific dedup, reimplemented as this gate’s overlap-resolution priority (same mechanism /v1/pii uses for e.g. a payment card partially overlapping a phone number).

Redaction#

redact: "mask" adds data.redacted to the response: your input text with every match replaced by *, one asterisk per character, so offsets still line up. It’s the only redaction mode — see the response format docs for why hashing, tokenising and removal are all cut rather than offered.

Matches, truncation and offsets#

Every match also appears in data.matches as { "code", "rule", "start", "end" }. rule is the specific gitleaks rule id that fired. start/end are Unicode code-point offsets of the secret itself, not the whole matched text — e.g. for AWS_SECRET_ACCESS_KEY=AKIA..., the offsets bound AKIA..., not the AWS_SECRET_ACCESS_KEY= prefix that helped identify it. A scan is capped at 100 matches; past that, data.truncated: true is set and only the first 100 (by position) are returned.

Example#

curl -s -X POST https://api.stormdoor.dev/v1/secrets \
  -H "Authorization: Bearer sk_live_..." \
  -H "content-type: application/json" \
  -d '{"text":"AWS_SECRET_ACCESS_KEY=AKIAZQ3XVGH4KJPBMNRT","redact":"mask"}'
{
  "ok": true,
  "verdict": "block",
  "findings": [
    {
      "code": "secret.provider_token",
      "severity": "high",
      "message": "Identified a pattern that may indicate AWS credentials, risking unauthorized cloud resource access and data breaches on AWS platforms.",
      "location": "23-43"
    }
  ],
  "data": {
    "matches": [
      { "code": "secret.provider_token", "rule": "aws-access-token", "start": 23, "end": 43 }
    ],
    "redacted": "AWS_SECRET_ACCESS_KEY=********************"
  },
  "checks_run": ["secret.generic_credential", "secret.private_key", "secret.provider_token"],
  "checks_skipped": [],
  "meta": { "gate": "secrets", "ruleset": "reference-..." }
}

See response format for how checks_skipped reasons work, and don’t proxy that array — or the raw match offsets — to your own end users.

Finding codes#

Each code links to its own page with what it looks at, why it matters and what to do.

secret.connection_stringhighsecret.connection_stringblock
secret.generic_credentialmediumsecret.generic_credentialsuspect
secret.jwthighsecret.jwtblock
secret.private_keycriticalsecret.private_keyblock
secret.provider_tokenhighsecret.provider_tokenblock
secret.test_mode_tokenlowsecret.test_mode_tokensuspect
secret.url_credentialsmediumsecret.url_credentialssuspect