Hemlighetsskanning
fremforge letar efter incheckade inloggningsuppgifter med gitleaks på tre ställen:
| Var | Vad den gör | Kan den stängas av? |
|---|---|---|
| Push-skydd | En pre-receive-hook skannar varje push och avvisar den direkt | Nej |
| Kontroll av pull requests | fremforge/secret-scan underkänner en pull request som lägger till en hemlighet, även i arkiv och Git LFS-filer | Ja, per organisation |
| Genomsökning av historiken | En gång i veckan läser gitleaks git hela historiken i varje repo och listar det som redan är incheckat | Nej |
Fynd från alla tre listas under Säkerhet › Fynd › Hemlighetsskanning (/<org>/_admin/security/findings/secrets), och på GET /_app/api/v1/orgs/{org}/code-security/secrets/findings.
En hemlighet som redan finns på den branch som pull requesten mergas in i underkänner inte kontrollen; se Kontroller av pull requests: bara nya fynd blockerar. Den listas fortfarande, och den veckovisa genomsökningen och Push-skydd är oförändrade.
Europeiska molnleverantörer
gitleaks egna regler täcker flera hundra format för inloggningsuppgifter, men inga från de europeiska molnleverantörerna. fremforge lägger till regler för dem, och de körs på alla tre ställena ovan:
| Leverantör | Regel-id | Vad den hittar |
|---|---|---|
| Hetzner Cloud | hetzner-cloud-api-token | En API-token under ett namn med HCLOUD_ eller HETZNER_, inklusive TF_VAR_hcloud_token |
| Scaleway | scaleway-secret-key | En hemlig nyckel under ett namn med SCW_ eller SCALEWAY_ |
| Scaleway | scaleway-key-pair | En åtkomstnyckel följd av sin secret_key, som i ~/.config/scw/config.yaml |
| OVHcloud | ovh-application-secret | OVH_APPLICATION_SECRET, OVH_CONSUMER_KEY eller OVH_CLIENT_SECRET |
| OVHcloud | ovh-conf-application-secret | application_secret, consumer_key eller client_secret i en fil ovh.conf |
| IONOS Cloud | ionos-cloud-token | En token under ett namn med IONOS_ |
| T Cloud / Open Telekom Cloud | otc-secret-access-key | En hemlig åtkomstnyckel under ett namn för hemlig nyckel med OTC_, OS_, HW_ eller OBS_, eller ett namn på *_SK som innehåller något av dem |
| T Cloud / Open Telekom Cloud | otc-terraform-provider-secret-key | secret_key skriven direkt i ett provider-block för opentelekomcloud |
| T Cloud / Open Telekom Cloud | otc-credentials-csv | Filen credentials.csv som konsolen laddar ned när du skapar en åtkomstnyckel |
De här tokens har inget fast prefix, så en regel matchar bara där leverantörens namn eller filformat säger vad värdet är. En lös sträng på 64 tecken eller ett UUID någon annanstans rapporteras inte. Platshållare (xxxx…, noll-UUID:t) och variabelreferenser (${HCLOUD_TOKEN}) ignoreras. För en inloggningsuppgift som de här reglerna inte täcker, lägg till ett eget mönster.
Fler detektorer
fremforge lägger också till regler för de här inloggningsuppgifterna, utöver gitleaks egna:
| Leverantör | Regel-id | Vad den hittar | Vid push |
|---|---|---|---|
| Supabase | supabase-access-token | En personlig åtkomsttoken, klassisk eller avgränsad, eller en OAuth-åtkomsttoken: sbp_, sbp_oauth_ eller sbp_v0_ följt av 40 hexadecimala tecken | Blockerar |
| Supabase | supabase-secret-key | En hemlig projektnyckel (sb_secret_…), som kringgår Row Level Security. Publicerbara nycklar (sb_publishable_…) är avsedda för webbläsare och rapporteras inte, och inte heller Supabase CLI:s publicerade lokala standardnyckel | Blockerar |
| Lovable | lovable-api-key | En API-nyckel för en arbetsyta (lov_…) | Blockerar |
| Pydantic | pydantic-logfire-token | En skrivtoken eller API-nyckel för Logfire, eller en nyckel för Pydantic AI Gateway (pylf_v…) | Blockerar |
| Cloudsmith | cloudsmith-api-key | En API-nyckel: 40 hexadecimala tecken under ett Cloudsmith-namn som CLOUDSMITH_API_KEY | Bara rapporterad |
Varje regel matchar tokens eget fasta prefix eller format, med gränser för längd och entropi, så den blockerar vid push som alla andra regler, och vägarna för undantag och förbikoppling gäller för den. En Cloudsmith-nyckel har inget prefix, så dess regel är bara rapporterad. En Cloudsmith-nyckel som tilldelas ett namn som CLOUDSMITH_API_KEY blockeras oftast ändå, av gitleaks generiska regel för API-nycklar.
Det här är bara detekteringsregler. fremforge erbjuder ingen giltighetskontroll för dem.
Lösenord i konfigurationsfiler
fremforge-password-config hittar ett lösenord som skrivits direkt i en konfigurations- eller skriptfil, till exempel DB_PASSWORD=… i en .env-fil, password: … i YAML, spring.datasource.password=… eller ENV REDIS_PASS=… i en Dockerfile. Den läser .env-filer, YAML, .properties, .ini, .conf, .cfg, .toml, skal-, PowerShell- och batchskript, Dockerfiles och compose-filer. Den letar efter en nyckel som är uppkallad efter ett lösenord (password, passwd, passphrase, pwd, pass) och som har ett bart värde som avslutar raden. Den utelämnar:
- referenser till ett annat värde (
${DB_PASSWORD},%(password)s,{{ … }}); - platshållare (
changeme,example,xxx); - översättningskataloger;
- inställningar som anger en hash eller en algoritm (
root_password_sha2,password.encoding.alg).
Det är en heuristik, inte ett tokenformat. Vi mätte den på CredData, en publik märkt uppsättning inloggningsuppgifter i repon med öppen källkod, mot gitleaks generiska regel för API-nycklar på samma filer. Den var mer precis och hittade fler av de verkliga lösenorden, på data som hölls utanför dess justering (precision 0,97 mot 0,95, recall 8 % mot 5 % av alla märkta lösenord). Den är bara rapporterad. Den läser inte källkod, och ett värde inom citattecken i YAML (password: "…") täcks inte: de formerna mättes också och slog inte den generiska regeln.
Lösenord som hittas av en klassificerare (fremforges egna organisationer)
Ett andra steg läser kod- och konfigurationsfiler efter hårdkodade lösenord som saknar tokenformat, till exempel db_password = "…" i Python eller password: "…" i YAML. Det körs i dag bara på fremforges egna organisationer. Det är ännu inte tillgängligt för kunders organisationer; det är ett separat beslut efter två veckors data om falska positiva.
Det fungerar i två steg, bakom reglerna ovan, i kontrollen av pull requests:
- Ett nyckelordsfilter behåller bara de rader som nämner ett lösenord eller har
user:password@i en URL, ungefär 1 % av raderna. - En maskininlärningsklassificerare poängsätter var och en av de raderna. Det är modellen från CredSweeper (Samsung, MIT-licens), omtränad av fremforge. Den körs inne i skannern utan nätverksåtkomst, och ingen kod eller inget värde lämnar den.
Ett fynd har regel-id:t fremforge-password-ml. Ett fynd i en testsökväg (test/, __tests__/, *.test.ts, test_*.py, *_test.go och liknande) behålls med regel-id:t fremforge-password-ml-test-path och märks som troligen en fixtur. Båda är bara rapporterade.
Det utelämnar:
- dokumentation, datafiler och allt som inte är kod eller konfiguration;
- översättningskataloger;
- konstanter som innehåller ett reguljärt uttryck om lösenord, till exempel
PASSWORD_RE; - rader som redan rapporterats av en annan regel.
Om klassificeraren inte kan köras eller tar längre tid än 120 sekunder rapporterar kontrollen de andra reglernas fynd som vanligt.
Hur den mättes. Vi tränade om modellen på CredDatas utvecklingsrepon, med bara de som har en tillåtande licens, och poängsatte den en gång på repon som hållits utanför träningen. Tröskeln låstes innan den poängen togs.
| Filer | Precision | Recall |
|---|---|---|
| Kod (värden inom citattecken) | 0,94 | 0,98 |
| Konfiguration | 0,96 | 0,99 |
Lösenord i URL:er och i andra filer nådde inte precisionen 0,9 och rapporteras inte. Träningsrepona och deras licenser listas i skannerns NOTICE-training-data.md.
Regler som bara rapporteras
cloudsmith-api-key, fremforge-password-config, fremforge-password-ml och fremforge-password-ml-test-path rapporteras bara. Deras fynd listas under Säkerhet › Fynd › Hemlighetsskanning, och de två gitleaks-reglerna även i genomsökningen av historiken (klassificeraren körs bara i kontrollen av pull requests). I en pull request visas de i fremforge/secret-scan som advisory (not blocking): de underkänner aldrig kontrollen och blockerar aldrig en push. Alla andra regler blockerar.
Inställningen
Blockera pull requests som lägger till en secret avgör om kontrollen av pull requests körs. Tills en organisation har sparat ett val körs kontrollen och blockerar. När den är avstängd körs kontrollen inte och dess status tas bort från branch-skyddet; Push-skydd och den veckovisa genomsökningen fortsätter att köras. Ange den under Säkerhet › Fynd › Hemlighetsskanning eller med PUT /_app/api/v1/orgs/{org}/code-security/secrets/settings och {"enabled": true} (policy:write).
Egna mönster
Din organisation kan lägga till egna format för hemligheter: en tokenform som bara du utfärdar, ett internt nyckelprefix, en partners inloggningsuppgift. Varje mönster blir en extra gitleaks-regel på alla tre ställena ovan, så en träff blockeras vid push, underkänner kontrollen av pull requests och hittas i historiken. Ett fynd från ett eget mönster har regel-id:t custom-<name> och visar mönstrets namn.
Lägg till dem under Säkerhet › Policyer › Push-skydd › Egna hemlighetsmönster, eller med POST /_app/api/v1/orgs/{org}/code-security/secrets/custom-patterns (policy:write; GET listar dem, PUT och DELETE på /custom-patterns/{id} ändrar och tar bort ett).
| Fält | Obligatoriskt | Vad det gör |
|---|---|---|
name | ja | Visas på varje fynd. Upp till 80 tecken. |
regex | ja | RE2-syntax, upp till 300 tecken. |
keywords | nej | Upp till 10. Mönstret körs bara på innehåll som innehåller något av dem, vilket håller pushar snabba. |
entropy | nej | 0 till 8. Träffar med mindre slumpmässighet än så, till exempel platshållare, rapporteras inte. |
allowlist_paths | nej | Upp till 20 sökvägsmönster (*, **, ?) där mönstret inte rapporteras. Ett mönster matchar på vilken katalognivå som helst. |
repository | nej | Ett av organisationens repon, efter namn. Utelämna för alla repon. |
repository_id | nej | Detsamma, efter repo-id. Ange repository eller repository_id, inte båda. |
sample | nej | Ett exempel som mönstret måste matcha. Kontrolleras när du sparar, sparas aldrig. |
Skicka "dry_run": true för att validera utan att spara.
Ett repo eller alla. Ett mönster utan repo gäller för alla organisationens repon. Ett mönster med ett repo gäller bara för det repot, på alla tre ställena, tillsammans med de som gäller hela organisationen. I konsolen väljer du repot i listan, eller Alla repon. Mönstret är knutet till själva repot, inte dess namn: om repot byter namn följer mönstret med. Ett repo som tas bort och senare skapas på nytt med samma namn är ett nytt repo och ärver det inte. Ett mönster vars repo har tagits bort eller flyttats till en annan organisation gäller ingenstans och visas så tills du ändrar eller tar bort det. Svaren innehåller både repository_id och repository, repots nuvarande namn.
# Validate only
curl -sS -X POST "https://frem.sh/_app/api/v1/orgs/$ORG/code-security/secrets/custom-patterns" \
-H "Authorization: Bearer $FREMFORGE_TOKEN" -H 'Content-Type: application/json' \
-d '{"name": "Acme deploy key", "regex": "acme_live_[A-Za-z0-9]{24}", "sample": "KEY=acme_live_abcdefghijklmnopqrstuvwx", "dry_run": true}'
# {"valid": true, "rule_id": "custom-acme-deploy-key"}
# Create (201)
curl -sS -X POST "https://frem.sh/_app/api/v1/orgs/$ORG/code-security/secrets/custom-patterns" \
-H "Authorization: Bearer $FREMFORGE_TOKEN" -H 'Content-Type: application/json' \
-d '{"name": "Acme deploy key", "regex": "acme_live_[A-Za-z0-9]{24}", "keywords": ["acme_live_"], "allowlist_paths": ["test/fixtures/**"]}'
# List
curl -sS "https://frem.sh/_app/api/v1/orgs/$ORG/code-security/secrets/custom-patterns" \
-H "Authorization: Bearer $FREMFORGE_TOKEN"
# Replace (the whole pattern) and delete
curl -sS -X PUT "https://frem.sh/_app/api/v1/orgs/$ORG/code-security/secrets/custom-patterns/$ID" \
-H "Authorization: Bearer $FREMFORGE_TOKEN" -H 'Content-Type: application/json' \
-d '{"name": "Acme deploy key", "regex": "acme_live_[A-Za-z0-9]{32}"}'
curl -sS -X DELETE "https://frem.sh/_app/api/v1/orgs/$ORG/code-security/secrets/custom-patterns/$ID" \
-H "Authorization: Bearer $FREMFORGE_TOKEN"Ett avvisat mönster svarar 400 med ett problem+json-innehåll vars type anger orsaken: invalid-repository, invalid-regex, regex-too-complex, regex-matches-empty, regex-too-broad, sample-not-matched, invalid-name, invalid-keywords, invalid-entropy eller invalid-allowlist-paths. Ett andra mönster med samma namn svarar 409 duplicate-name, ett 101:a too-many-patterns, och ett 21:a utan nyckelord too-many-without-keywords.
Med Terraform/OpenTofu-providern:
resource "fremforge_secret_custom_pattern" "acme_deploy_key" {
org = "acme"
name = "Acme deploy key"
regex = "acme_live_[A-Za-z0-9]{24}"
keywords = ["acme_live_"]
allowlist_paths = ["test/fixtures/**"]
# repository = "infra" # one repository only (provider 0.7.0 and later)
}Varför bara RE2. Ett mönster körs i push-hooken vid varje push. RE2 har ingen backtracking, så körtiden växer linjärt med indata och inget mönster kan få en push att stå still. Bakåtreferenser (\1) och lookarounds ((?=, (?!, (?<=) kräver backtracking och avvisas. Ett mönster avvisas också när det:
- matchar en tom sträng, eller vanlig text som
const x = 1;; - upprepas mer än 256 gånger (
{n,m}), eller nästlar grupper djupare än 6 nivåer.
Testa ett mönster innan du sparar det
Testa på repon i formuläret för att lägga till, eller API:t för torrkörning, kör ett kandidatmönster över den senaste commiten på varje repos standard-branch och visar var det skulle träffa. Inget sparas: mönstret lagras inte, inget fynd skapas, och resultatet behålls i 24 timmar.
Det visar repo, fil, rad, commit och fingeravtryck för varje träff, aldrig den matchade texten. Varje repo räknas en gång, i en av tre grupper:
- kontrollerade;
- kunde inte kontrolleras: kloningen misslyckades, tog för lång tid, skanningen misslyckades, eller repot nåddes inte inom tidsgränsen på 10 minuter;
- hoppades över: arkiverat, en spegel, tomt, för stort (över 100 MB, eller en utcheckning över 256 MB), eller över gränsen på 200 repon.
Ett mönster som är avgränsat till ett repo testas bara på det repot.
# Start one (202); the body is the same as creating a pattern
curl -sS -X POST "https://frem.sh/_app/api/v1/orgs/$ORG/code-security/secrets/custom-patterns/dry-runs" \
-H "Authorization: Bearer $FREMFORGE_TOKEN" -H 'Content-Type: application/json' \
-d '{"name": "Acme deploy key", "regex": "acme_live_[A-Za-z0-9]{24}", "keywords": ["acme_live_"]}'
# {"id": "…", "status": "queued", …}
# Read it back until status is done (or failed)
curl -sS "https://frem.sh/_app/api/v1/orgs/$ORG/code-security/secrets/custom-patterns/dry-runs/$ID" \
-H "Authorization: Bearer $FREMFORGE_TOKEN"
# {"status": "done", "repositories": {"total": 118, "scanned": 70, "not_checked": 48},
# "matches": [{"repository": "web", "path": "config/partner.txt", "line": 1, "commit": "…", "fingerprint": "…"}], …}Båda kräver policy:write, eftersom resultatet namnger filer i alla organisationens repon. En torrkörning per organisation körs åt gången, och en kan startas var 10:e minut. En körning som ingen skanner tar emot inom 2 minuter slutar som failed med error: expired; starta den igen några minuter senare. Att starta en loggas i granskningsloggen som code-security.secret_scan.custom_pattern.dry_run_started. En avvisad start svarar med samma typer som när ett mönster skapas, eller dry-run-in-progress (409), dry-run-cooldown (429) eller dry-run-unavailable (503).
Gränser. En organisation kan ha upp till 100 mönster, inklusive de som är avgränsade till ett repo. Högst 20 av dem får sakna keywords. Listsvaret anger båda som limit och limit_without_keywords.
Orsaken är tiden vid push. Ett mönster med nyckelord körs bara på innehåll som innehåller något av dem, så det kostar nästan ingenting. Ett mönster utan nyckelord körs på varje del av varje push. Uppmätt med vår push-hook tog 200 mönster utan nyckelord en push med 100 commits från ungefär 2 sekunder till 17. Ett nyckelord är oftast hemlighetens fasta prefix.
När du sparar eller tar bort ett mönster köas en ny skanning av hela historiken i varje repo, så att ett nytt mönster även hittar det som redan är incheckat. Det tar oftast upp till 15 minuter. Ändringar loggas i granskningsloggen som code-security.secret_scan.custom_pattern.created, .updated och .deleted.
Om mönstren inte kan läsas in vid push, till exempel medan api:et en kort stund inte kan nås, skannas pushen ändå med de inbyggda reglerna, och en rad i granskningsloggen registrerar att de egna mönstren inte tillämpades. Genomsökningen av historiken hittar sedan det som missades när den når standard-branchen.
Giltighetskontroller
En hemlighet som fortfarande fungerar är mer brådskande än en som redan har roterats. En giltighetskontroll frågar den tjänst som utfärdade en upptäckt hemlighet om den fortfarande är aktiv, och märker fyndet Aktiv, Inaktiv eller Okänd. Aktiva fynd listas först, i konsolen och i API:t (validity, validity_checked_at).
Varje leverantör är en egen inställning under Säkerhet › Policyer › Push-skydd › Giltighetskontroller, eller PUT /_app/api/v1/orgs/{org}/code-security/secrets/validity-settings/{provider} med {"enabled": true} (policy:write). Innan du slår på en anger sidan vilken värd kontrollen kontaktar och om leverantören är USA-driven, EU-driven, Storbritannien-driven eller Kanada-driven. API:t rapporterar detsamma som operator_jurisdiction (us, eu, uk, ca, eller null för den interna kontrollen). Storbritannien och Kanada har båda ett beslut om adekvat skyddsnivå från EU; ingen leverantör som drivs från något annat land utanför EU erbjuds i GET .../validity-settings.
Den här tabellen är den lista över leverantörer som personuppgiftsbiträdesavtalet (bilaga B §B.10) hänvisar till. fremforge erbjuder en kontroll bara för en leverantör i den, var och en med en skrivskyddad förfrågan till en fast värd, eller, där en leverantör levererar sina nycklar från regionala värdar (SendGrid, Mailgun, Datadog, Intercom, Postman, Square, HCP Terraform, Typeform), till en fast lista med värdar som tillfrågas i tur och ordning; du kan inte lägga till en egen URL. En leverantör som läggs till senare börjar avstängd.
| Leverantör | Regler som kontrolleras | Vart kontrollen går | Förfrågan | Drivs | Standard |
|---|---|---|---|---|---|
fremsh | API-tokens för frem.sh (ffp_) | Inom frem.sh. Inget externt anrop | Tokens hash mot frem.sh:s tokenlager | — | På |
github | GitHub-tokens | api.github.com | GET /rate_limit | USA-driven | Av |
gitlab | Personliga åtkomsttokens för GitLab.com (en token från en egen server blir Okänd) | gitlab.com | GET /api/v4/personal_access_tokens/self | USA-driven | Av |
aws | AWS-åtkomstnycklar | sts.amazonaws.com | GetCallerIdentity, som inte kräver någon behörighet | USA-driven | Av |
slack | Slack-tokens | slack.com | POST /api/auth.test, utan innehåll | USA-driven | Av |
stripe | Stripe API-nycklar | api.stripe.com | GET /v1/balance | USA-driven | Av |
hetzner | API-tokens för Hetzner Cloud | api.hetzner.cloud | GET /v1/locations | EU-driven | Av |
scaleway | Hemliga nycklar för Scaleway | api.scaleway.com | GET /account/v3/projects?page_size=1 | EU-driven | Av |
ionos | API-tokens för IONOS Cloud | api.ionos.com | GET /cloudapi/v6/ | EU-driven | Av |
npm | npm-åtkomsttokens | registry.npmjs.org | GET /-/whoami | USA-driven | Av |
openai | OpenAI API-nycklar | api.openai.com | GET /v1/models | USA-driven | Av |
anthropic | Anthropic API-nycklar (inte Admin API-nycklar) | api.anthropic.com | GET /v1/models | USA-driven | Av |
huggingface | Åtkomsttokens för Hugging Face (inte äldre api_org_-tokens) | huggingface.co | GET /api/whoami-v2 | USA-driven | Av |
digitalocean | DigitalOcean-tokens | api.digitalocean.com | GET /v2/account | USA-driven | Av |
sendgrid | SendGrid API-nycklar | api.sendgrid.com, sedan api.eu.sendgrid.com, tills en svarar | GET /v3/scopes | USA-driven | Av |
mailgun | Privata Mailgun API-nycklar | api.mailgun.net, sedan api.eu.mailgun.net, tills en svarar | GET /v3/domains | USA-driven | Av |
datadog | Datadog API-nycklar | Datadogs sex sajter i den här ordningen, tills en svarar: api.datadoghq.com, api.datadoghq.eu, api.us3.datadoghq.com, api.us5.datadoghq.com, api.ap1.datadoghq.com, api.ddog-gov.com | GET /api/v1/validate | USA-driven | Av |
azuredevops | Personliga åtkomsttokens för Azure DevOps. Bara Aktiv eller Okänd | app.vssps.visualstudio.com | GET /_apis/profile/profiles/me | USA-driven | Av |
ovh | API-inloggningsuppgifter för OVHcloud. Bara Aktiv eller Okänd | eu.api.ovh.com | GET /1.0/auth/currentCredential, signerad | EU-driven | Av |
adafruit | Adafruit IO-nycklar | io.adafruit.com | GET /api/v2/user | USA-driven | Av |
airtable | Personliga åtkomsttokens för Airtable | api.airtable.com | GET /v0/meta/whoami | USA-driven | Av |
asana | Personliga åtkomsttokens för Asana | app.asana.com | GET /api/1.0/users/me | USA-driven | Av |
doppler | Personliga Doppler-tokens | api.doppler.com | GET /v3/me | USA-driven | Av |
dropbox | Dropbox-åtkomsttokens | api.dropboxapi.com | POST /2/users/get_current_account, som läser kontot | USA-driven | Av |
easypost | EasyPost API-nycklar | api.easypost.com | GET /v2/addresses?page_size=1 | USA-driven | Av |
fastly | Fastly API-tokens | api.fastly.com | GET /tokens/self | USA-driven | Av |
heroku | Heroku API-nycklar | api.heroku.com | GET /account | USA-driven | Av |
intercom | Intercom-åtkomsttokens | api.intercom.io, sedan api.eu.intercom.io, sedan api.au.intercom.io, tills en svarar | GET /me | USA-driven | Av |
lob | Lob API-nycklar | api.lob.com | GET /v1/addresses?limit=1 | USA-driven | Av |
notion | Integrationstokens för Notion | api.notion.com | GET /v1/users/me | USA-driven | Av |
postman | Postman API-nycklar | api.getpostman.com, sedan api.eu.postman.com, tills en svarar | GET /me | USA-driven | Av |
readme | ReadMe API-nycklar | dash.readme.com | GET /api/v1 | USA-driven | Av |
rubygems | RubyGems API-nycklar | rubygems.org | GET /api/v1/gems.json | USA-driven | Av |
shippo | Shippo API-tokens | api.goshippo.com | GET /addresses/?results=1 | USA-driven | Av |
square | Square-åtkomsttokens | connect.squareup.com, sedan connect.squareupsandbox.com, tills en svarar | GET /v2/merchants/me | USA-driven | Av |
brevo | Brevo (Sendinblue) API-nycklar | api.brevo.com | GET /v3/account | EU-driven | Av |
gocardless | GoCardless-åtkomsttokens (live) | api.gocardless.com | GET /creditors?limit=1 | Storbritannien-driven | Av |
duffel | Duffel-åtkomsttokens | api.duffel.com | GET /air/airlines?limit=1 | Storbritannien-driven | Av |
cohere | Cohere API-nycklar | api.cohere.com | POST /v1/check-api-key, Coheres egen nyckelkontroll | Kanada-driven | Av |
hcpterraform | API-tokens för HCP Terraform. Bara Aktiv eller Okänd | app.terraform.io, sedan app.eu.terraform.io, tills en svarar | GET /api/v2/account/details | USA-driven | Av |
pulumi | Pulumi-åtkomsttokens. Bara Aktiv eller Okänd | api.pulumi.com | GET /api/user | USA-driven | Av |
sentry | Sentry-användartokens. Bara Aktiv eller Okänd | sentry.io | GET /api/0/ | USA-driven | Av |
messagebird | MessageBird-åtkomstnycklar. Bara Aktiv eller Okänd | rest.messagebird.com | GET /balance | EU-driven | Av |
typeform | Personliga åtkomsttokens för Typeform. Bara Aktiv eller Okänd | api.typeform.com, sedan api.eu.typeform.com, tills en svarar | GET /me | EU-driven | Av |
Personliga åtkomsttokens för Azure DevOps, Datadog API-nycklar och personliga åtkomsttokens för Asana hittas av tre regler från fremforge, azure-devops-pat, datadog-api-key och asana-personal-access-token, som körs på alla tre ställena ovan.
Vissa kontroller kan visa att en hemlighet är aktiv, men aldrig att den inte är det. Azure DevOps avvisar en aktiv token som är begränsad till en organisation eller saknar profile-scope, så ett avslag där blir Okänd, aldrig Inaktiv. En förfrågan till OVHcloud måste signeras med applikationsnyckeln, applikationshemligheten och konsumentnyckeln tillsammans. Kontrollen körs bara när genomsökningen av historiken hittar alla tre i samma fil, till exempel en ovh.conf, och alla svar utom ett lyckat blir Okänd. Tokens för HCP Terraform, Pulumi och Sentry kan höra till en egenhostad Terraform Enterprise, Pulumi eller Sentry, som avvisar dem på den publika tjänsten. MessageBird-nycklar från den nyare plattformen Bird kan avvisas av MessageBirds ursprungliga API. En Typeform-token utan account-scope kan avvisas på samma sätt som en död. Därför blir dessa fem Aktiv eller Okänd, aldrig Inaktiv.
En hemlighet är inaktiv bara när alla värdar säger det. En SendGrid-nyckel som är låst till EU-regionen misslyckas på den globala värden, en Datadog-nyckel hör till en av Datadogs sajter, och en nyckel för Intercom, Postman eller Typeform till en av deras regioner; en sandbox-token för Square misslyckas i produktion. Därför frågar kontrollen värdarna i den visade ordningen och stannar vid den första som svarar att hemligheten är aktiv. Den blir Inaktiv bara när alla värdar avvisar den.
Ingen automatisk kontroll: Atlassian, Twilio, Flutterwave, Mailchimp, Telegram, egen GitLab-server och T Cloud. Deras fynd har bara Kontrollera själv. En Atlassian-token kräver även sajten och kontots e-postadress, och en Twilio API-nyckel kräver sitt SID. Flutterwave-regeln hittar bara testnycklar. En Mailchimp-nyckel anger sin egen datacentervärd, så det finns ingen fast värd att kontrollera. Telegram drivs från utanför EU, Storbritannien, Kanada och USA. En egen GitLab-server, eller någon annan värd du väljer, är ett mål som fremforge inte kontaktar för din räkning. T Cloud är det moln som fremforge självt körs på, och dess identitetstjänst kan avsiktligt inte nås från fremforges kontroller. För en T Cloud-nyckel ber kommandot OBS att lista dina buckets: en nyckel som inte är känd svarar InvalidAccessKeyId.
En nyckel som är aktiv men inte får göra kontrollens läsning räknas som Aktiv: en Stripe-nyckel som nekas saldot, en Scaleway-nyckel som nekas projekten, en Anthropic-nyckel som avvisas med permission_error, en OpenAI-nyckel som avvisas för att behörigheter saknas, en Dropbox-token som avvisas med missing_scope, eller en nyckel för Heroku, RubyGems, Square, Asana, GoCardless eller Duffel som avvisas med 403. För de leverantörer som lades till 2026-10-24 blir bara det exakta svar som var och en ger för en nyckel som inte finns Inaktiv; alla andra svar blir Okänd. OpenAI:s invalid_api_key är det enda svaret från OpenAI som läses som Inaktiv. Admin API-nycklar för Anthropic och äldre organisationstokens för Hugging Face kontrolleras inte, eftersom slutpunkterna ovan inte kan avgöra om de är aktiva.
Så fungerar en kontroll, och vad som sparas. Varje kontroll är skrivskyddad. Den frågar vem en token tillhör eller om den är giltig, och ändrar aldrig något hos leverantören. Hemligheten sparas fortfarande aldrig. Medan genomsökningen av historiken läser ett repo krypterar skannern varje matchande värde med en nyckel som api:et skapar för just den skanningen. Api:et öppnar det, kör kontrollen, behåller bara utfallet och när det kontrollerades, och kastar värdet. Nyckeln tas bort när skanningen är klar. Skannern själv har ingen nätverksåtkomst till leverantörerna.
En token för frem.sh kontrolleras mot frem.sh:s eget tokenlager, och dess tillstånd läses direkt: om token återkallas visas fyndet som Inaktiv direkt. För de andra leverantörerna är tillståndet från den senaste genomsökningen som läste hemligheten.
Okänd betyder att leverantören inte gav något tydligt svar, till exempel en timeout eller en hastighetsbegränsning, en AWS-nyckel vars hemliga halva inte hittades inom fem rader från den, eller en OVHcloud-inloggningsuppgift vars tre delar inte hittades tillsammans. Okänd visas aldrig som Inaktiv.
När du slår på en leverantör skannas historiken i varje repo om, eftersom en hittad hemlighets värde bara finns medan genomsökningen läser den. När du stänger av den rensas den leverantörens utfall. Ändringar loggas i granskningsloggen som code-security.secret_scan.validity.updated.
Kontrollera själv och markera sedan
Du behöver inte slå på en giltighetskontroll för att veta om en hemlighet fortfarande fungerar. För en hemlighet som utfärdats av någon av leverantörerna ovan, eller av Atlassian, Twilio, Flutterwave, Mailchimp, Telegram, en egen GitLab-server eller T Cloud, har fyndet Kontrollera själv: leverantörens egen skrivskyddade förfrågan som ett kommando att köra i din terminal, till exempel för en GitHub-token:
read -rs TOKEN && curl -s -o /dev/null -w '%{http_code}\n' -H "Authorization: Bearer $TOKEN" https://api.github.com/rate_limitKommandot innehåller aldrig hemligheten. Det väntar på att du skriver eller klistrar in den, visar den inte och håller den borta från skalhistoriken. Den går bara till leverantören, aldrig till fremforge. Fyndet anger vad kommandot skriver ut när hemligheten är aktiv (här 200) och när den inte är det (401).
Registrera sedan vad du kom fram till med Markera aktiv eller Markera roterad i fyndets meny, eller PUT /_app/api/v1/orgs/{org}/code-security/secrets/findings/{id}/mark med {"mark": "active"}, {"mark": "rotated"} eller {"mark": null} (findings:write). Ett fynd som markerats aktivt listas med de aktiva. Varje plats markeras separat: en markering hör till ett fynd (en fil, rad och commit) och behålls mellan genomsökningar av historiken, precis som ett avfärdande. Om samma hemlighet hittades i två commits, markera båda. fremforge sparar inget som härletts från hemligheten och som skulle kunna knyta ihop platserna. En markering avfärdar inte fyndet. Varje markering loggas i granskningsloggen som code-security.secrets.marked. Findings API returnerar markeringen som mark och kommandot som self_check.
Rotera som standard, och vilka som ska roteras först
Behandla varje hemlighet som hittas här som komprometterad, och rotera den, om inte dess leverantör eller du har bekräftat att den inte längre fungerar. Att ta bort en hemlighet ur koden återkallar den inte: den finns kvar i historiken, där alla med läsåtkomst kan hitta den.
För att hjälpa dig avgöra vilka som ska roteras först när ingen leverantör har svarat ordnas fynden efter hur sannolikt det är att hemligheten fortfarande är aktiv. Uppskattningen använder bara det som fremforge redan vet, aldrig själva hemligheten, och kontaktar ingen:
| Signal | Effekt |
|---|---|
| Exakt samma rad finns fortfarande i standard-branchens nuvarande kod | Troligen aktiv |
| Push-skydd blockerade samma sorts hemlighet i det här repot de senaste 90 dagarna | Troligen aktiv |
| Raden ändrades eller togs bort senare på standard-branchen | Möjligen aktiv: att ta bort den återkallade den inte |
| Commiten finns bara på en annan branch än standard-branchen | Möjligen aktiv |
| Incheckad de senaste 90 dagarna | Höjer uppskattningen |
| Incheckad för mer än två år sedan, och inte i den nuvarande koden | Mindre troligt aktiv |
En leverantörs eget svar (Aktiv eller Inaktiv) och din egen markering har alltid företräde. Uppskattningen visas, med upp till två av sina skäl, på varje fynd som ingen leverantör har svarat på och som du inte har markerat. Signalerna från koden registreras av den veckovisa genomsökningen av historiken, så ett fynd som söktes igenom före den genomsökning som lade till dem visar bara signalen från Push-skydd fram till nästa. Findings API returnerar den som likely_live (level och reasons), tillsammans med committed_at. Den är null när en leverantör har svarat eller fyndet är markerat. Det är en uppskattning, inte en kontroll: “Mindre troligt aktiv” betyder fortfarande att du ska rotera.
Vad som sparas
Bara ett fingeravtryck av träffen sparas, aldrig den matchade texten. Regeln, sökvägen, raden och commiten räcker för att öppna filen i den commiten. En giltighetskontroll lägger till utfallet och dess tidpunkt. För en token för frem.sh sparas också id:t för den matchande tokenposten, aldrig själva token.
När en hemlighet hittas
Rotera inloggningsuppgiften vid källan först. Att ta bort raden gör inte värdet oläckt: alla som har historiken har det fortfarande. Ta sedan bort den ur koden: Öppna fix-PR i fyndets kolumn Åtgärd flyttar en inloggningsuppgift i Go, Python, JavaScript eller TypeScript till en miljövariabel, utan AI; se Regelbaserade fixar. Pull requesten tar inte bort värdet ur historiken, så rotering kommer först i båda fallen.