{"id":50103596,"url":"https://github.com/docker/portcullis","last_synced_at":"2026-05-23T09:02:33.501Z","repository":{"id":359487748,"uuid":"1232972544","full_name":"docker/portcullis","owner":"docker","description":"A tiny Go library to detect and redact API tokens, cloud credentials, and other secret material in arbitrary text.","archived":false,"fork":false,"pushed_at":"2026-05-22T09:48:42.000Z","size":132,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-22T13:15:26.799Z","etag":null,"topics":["ai","secrets-detection","security"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/docker.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-08T13:06:53.000Z","updated_at":"2026-05-22T09:48:47.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/docker/portcullis","commit_stats":null,"previous_names":["docker/portcullis"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/docker/portcullis","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/docker%2Fportcullis","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/docker%2Fportcullis/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/docker%2Fportcullis/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/docker%2Fportcullis/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/docker","download_url":"https://codeload.github.com/docker/portcullis/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/docker%2Fportcullis/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33389229,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-23T04:15:53.637Z","status":"ssl_error","status_checked_at":"2026-05-23T04:15:53.242Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","secrets-detection","security"],"created_at":"2026-05-23T09:02:27.958Z","updated_at":"2026-05-23T09:02:33.496Z","avatar_url":"https://github.com/docker.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# portcullis\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/docker/portcullis.svg)](https://pkg.go.dev/github.com/docker/portcullis)\n\nA tiny Go library that detects and redacts API tokens, cloud\ncredentials, and other secret material in arbitrary text.\n\n```go\nimport \"github.com/docker/portcullis\"\n\nclean := portcullis.Redact(\"Run this with token=ghp_1234567890abcdef1234567890abcdef1234 please.\")\n// → \"Run this with token=[REDACTED] please.\"\n\nportcullis.Contains(\"not a secret\")                                   // false\nportcullis.Contains(\"token=ghp_1234567890abcdef1234567890abcdef1234\") // true\n```\n\n## Why\n\nLLM agents, log pipelines, error reporters, and anything else that\nechoes user-controlled or tool-produced text back into a third party\nneed to scrub credentials before they leak. `portcullis` is the\nextracted, dependency-free core of the redactor used by\n[`docker-agent`](https://github.com/docker/docker-agent), built around\ntwo design constraints:\n\n- **Cheap on clean input.** A single Aho–Corasick pass over the input\n  yields a bitset of every keyword present, after which each rule's\n  keyword check collapses to two `AND` instructions. Most messages\n  never pay for a regex.\n- **Idempotent.** The default marker `[REDACTED]` is chosen so it does\n  not match any built-in rule; redacting an already-redacted string is\n  a no-op, and pipelines that scrub at multiple stages don't amplify.\n\n## Install\n\n```sh\ngo get github.com/docker/portcullis\n```\n\nRequires Go 1.26.3+.\n\n## API\n\nThe public surface is intentionally tiny:\n\n```go\nconst Marker = \"[REDACTED]\"\n\nfunc Contains(text string) bool   // detect\nfunc Redact(text string) string   // scrub\n```\n\nBoth functions are safe for concurrent use. The compiled rule set and\nits Aho–Corasick automaton are built once on first call and shared\nacross goroutines.\n\n## What it detects\n\nThe built-in catalogue covers ~245 patterns spanning:\n\n- Cloud providers — AWS, GCP service accounts, Azure Storage,\n  Azure AD client secrets, DigitalOcean, Yandex,\n  Akamai, Cloudflare Origin CA.\n- Source forges \u0026 CI — GitHub (PAT / OAuth / app / fine-grained /\n  refresh), GitLab (full token family incl. `glimt-` /\n  `glagent-` / `glsoat-` / routable variants), Bitbucket,\n  Docker Hub (PAT / OAT), JFrog (key + reference token), Sonar,\n  Buildkite, CircleCI, Harness (`pat.` / `sat.`), Authress.\n- LLM / AI providers — OpenAI, Anthropic, DeepSeek, Google (AIza),\n  xAI / Grok, Cohere, Groq, Perplexity, Replicate, OpenRouter,\n  Hugging Face (user `hf_` + organisation `api_org_`),\n  AssemblyAI, Deepgram, NVIDIA NIM (`nvapi-`),\n  LangSmith (`lsv2_pt_` / `lsv2_sk_`), Pinecone (`pcsk_`).\n- Payment processors — Stripe (secret / restricted /\n  webhook), Razorpay, Plaid, Braintree.\n- Communication \u0026 ops — Slack (legacy, rotating, webhooks,\n  workflow webhooks), Discord (bot \u0026 webhook), Telegram, Twilio,\n  SendGrid, Mailgun, Mailchimp, Sendinblue, Microsoft Teams\n  webhooks, PubNub (publish + subscribe), Tines / Zapier webhooks.\n- SaaS \u0026 developer tools — Figma, Contentful, HubSpot, LaunchDarkly\n  (incl. `sdk-` keys), Doppler (full family), 1Password, Vercel,\n  Netlify, Render, Notion, Linear, Trello, ClickUp, Okta, ngrok,\n  Cisco Meraki, SettleMint, Fly.io macaroons, Heroku v1/v2,\n  OpenShift `sha256~` tokens, Voiceflow, Deno Deploy, Bitbucket\n  app passwords (`ATBB`), CircleCI v2 (`CCIPAT_`), Endor Labs,\n  Rootly, Sourcegraph Cody, Stripe payment-intent client secrets,\n  Nightfall DLP, Ramp.\n- Infra, web3 \u0026 databases — HashiCorp Vault (service / batch /\n  recovery), Terraform Cloud, Tailscale, PlanetScale, Supabase,\n  MongoDB / Postgres / MySQL / Redis / AMQP connection-string\n  passwords, Sidekiq Pro/Enterprise gem-server URLs,\n  Alchemy / Etherscan / Moralis (web3), Logz.io,\n  PEM private keys, JWTs, and more.\n\nConnection-string rules (MongoDB, Postgres, MySQL, Redis, AMQP, Azure\nStorage) redact only the password / key span so log readers can still\ntell which host or account was being addressed.\n\n## Development\n\nThe project is driven by [`gogo`](https://github.com/dgageot/gogo),\na small task runner. Install it once:\n\n```sh\ngo install github.com/dgageot/gogo@latest\n```\n\nThen, from the repository root:\n\n```sh\ngogo            # default: lint + test\ngogo test       # go test ./...\ngogo test-race  # go test -race ./...\ngogo bench      # go test -bench=. -benchmem -run=^$ ./...\ngogo lint       # golangci-lint run + go.mod tidy check\ngogo format     # golangci-lint fmt\ngogo tidy       # go mod tidy\ngogo -l         # list every task with its description\n```\n\nThe linter configuration lives in [`.golangci.yml`](./.golangci.yml).\nThe matching CI workflow runs lint + race-enabled tests against the\ngo.mod floor (Go 1.26.3) and the latest stable Go release on every PR\n— see [`.github/workflows/ci.yml`](./.github/workflows/ci.yml).\n\n## Performance\n\nOn a typical clean input the cost is dominated by a single linear scan\nover the bytes; the regex engine is never invoked. With a secret, only\nthe rules whose keywords are present run. Both functions allocate\nonly when text actually changes.\n\nOn an Apple M4 Max scrubbing a 9000-byte clean payload and a\nsecret-bearing 1.5 KB payload:\n\n```\nBenchmarkAhoScanCleanInput-16        257198      4823 ns/op  1865.95 MB/s     0 B/op    0 allocs/op\nBenchmarkAhoScanWithKeyword-16      1251084       956.0 ns/op 1636.96 MB/s     0 B/op    0 allocs/op\nBenchmarkRedactCleanInput-16         228036      4803 ns/op                    0 B/op    0 allocs/op\nBenchmarkContainsCleanInput-16       233336      4782 ns/op                    0 B/op    0 allocs/op\nBenchmarkRedactWithSecret-16         565590      2094 ns/op                 1585 B/op    2 allocs/op\nBenchmarkContainsWithSecret-16       912943      1312 ns/op                    0 B/op    0 allocs/op\n```\n\nThe AC scan dominates the clean-input path — `Redact` and `Contains`\nadd no measurable overhead on top of it because the rule loop\nshort-circuits on an empty keyword mask. `Contains` allocates zero\nbytes even on a secret-bearing input: it only needs the regex\n`MatchString`, which uses pooled state machines internally.\n\n## Provenance\n\nThe default ruleset is derived from the MIT-licensed\n[`github.com/docker/mcp-gateway/pkg/secretsscan`](https://github.com/docker/mcp-gateway)\npackage, which adapted it from\n[`github.com/aquasecurity/trivy/pkg/fanal/secret`](https://github.com/aquasecurity/trivy),\nextended with additional patterns for modern AI providers, payment\nprocessors, and infrastructure tokens.\n\n## License\n\nApache-2.0. See [LICENSE](./LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdocker%2Fportcullis","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdocker%2Fportcullis","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdocker%2Fportcullis/lists"}