├── testdata
├── expected
│ ├── report
│ │ ├── empty.json
│ │ ├── junit_empty.xml
│ │ ├── csv_simple.csv
│ │ ├── json_simple.json
│ │ └── junit_simple.xml
│ └── git
│ │ ├── small-branch-foo.txt
│ │ └── small.txt
├── repos
│ ├── small
│ │ ├── dotGit
│ │ │ ├── HEAD
│ │ │ ├── COMMIT_EDITMSG
│ │ │ ├── ORIG_HEAD
│ │ │ ├── refs
│ │ │ │ ├── heads
│ │ │ │ │ ├── foo
│ │ │ │ │ ├── main
│ │ │ │ │ ├── api-pkg
│ │ │ │ │ └── remove-secrets
│ │ │ │ └── remotes
│ │ │ │ │ └── origin
│ │ │ │ │ ├── HEAD
│ │ │ │ │ ├── foo
│ │ │ │ │ ├── main
│ │ │ │ │ └── api-pkg
│ │ │ ├── description
│ │ │ ├── index
│ │ │ ├── FETCH_HEAD
│ │ │ ├── packed-refs
│ │ │ ├── logs
│ │ │ │ ├── refs
│ │ │ │ │ ├── remotes
│ │ │ │ │ │ └── origin
│ │ │ │ │ │ │ ├── foo
│ │ │ │ │ │ │ ├── api-pkg
│ │ │ │ │ │ │ ├── main
│ │ │ │ │ │ │ └── HEAD
│ │ │ │ │ └── heads
│ │ │ │ │ │ ├── api-pkg
│ │ │ │ │ │ ├── remove-secrets
│ │ │ │ │ │ ├── foo
│ │ │ │ │ │ └── main
│ │ │ │ └── HEAD
│ │ │ ├── objects
│ │ │ │ ├── 15
│ │ │ │ │ └── 2888a42422b2ff5868b8d003d626120a9cb738
│ │ │ │ ├── 32
│ │ │ │ │ └── bfaec6697c1a693f71b183d3389ad2547bbb3c
│ │ │ │ ├── 49
│ │ │ │ │ └── 1504d5a31946ce75e22554cc34203d8e5ff3ca
│ │ │ │ ├── 53
│ │ │ │ │ └── cd7a3c6eb4937f413e3c25e4a9f39289afa69e
│ │ │ │ ├── 78
│ │ │ │ │ └── 9ba677976d5db481de55c799d67acbf8e3f16a
│ │ │ │ ├── 90
│ │ │ │ │ └── 6335481df9a4b48906c90318b4fac76b67fe73
│ │ │ │ ├── 98
│ │ │ │ │ └── 1ab8417104c91bb9a4657f5d436c760c0aff50
│ │ │ │ ├── 02
│ │ │ │ │ └── d85657604c34e7b7fbb324a0c6c8b13c2c3760
│ │ │ │ ├── 2e
│ │ │ │ │ └── 1db472eeba53f06c4026ae4566ea022e36598e
│ │ │ │ ├── 4f
│ │ │ │ │ └── 77f1b3cc39d4b17e4cf4ba0a38f5daed9875b4
│ │ │ │ ├── 5c
│ │ │ │ │ └── 547e4215d9594c3935bdfefdf4f500016a4112
│ │ │ │ ├── 8d
│ │ │ │ │ └── c20a62e189d3446cfb6ec328dbd379d64feb20
│ │ │ │ ├── 9a
│ │ │ │ │ └── 932e37eaa9fb64b09e47e5e859c9b2c8cb47ad
│ │ │ │ ├── a1
│ │ │ │ │ └── 22b33c6bad3ee54724f52f2caad385ab1982ab
│ │ │ │ ├── a5
│ │ │ │ │ └── caae6d742e49a33982f1fdc608ce861ea59be5
│ │ │ │ ├── a9
│ │ │ │ │ └── aa0c942dcef669a94f207a77426106b25efd1a
│ │ │ │ ├── ac
│ │ │ │ │ └── bef43fdb053ec01e8e16697536d47853460cbc
│ │ │ │ ├── bc
│ │ │ │ │ └── f47ef84f29bb7ed6e653d61fccd30d0ecce886
│ │ │ │ ├── ca
│ │ │ │ │ └── da78a9bf157ec05573f19e682d211f811c2e2d
│ │ │ │ ├── d8
│ │ │ │ │ └── 32479114dc6be7207edc7c37ce91dd11b93161
│ │ │ │ ├── da
│ │ │ │ │ ├── 2622b4d97e32c5801511244b809144b6b3ea78
│ │ │ │ │ └── eb160a13200a3422e73296a6892784a113e0d6
│ │ │ │ ├── df
│ │ │ │ │ └── 7eaa59fc89b3e7258167605db2e582f1a78e6f
│ │ │ │ ├── e5
│ │ │ │ │ └── c0849a65c586eab87dcfc31fec74f0fd7c62cb
│ │ │ │ ├── f1
│ │ │ │ │ └── b58b97808f8e744f6a23c693859df5b5968901
│ │ │ │ ├── fa
│ │ │ │ │ └── 468655086f149d41a8e7db14ed054bebec7687
│ │ │ │ └── pack
│ │ │ │ │ ├── pack-2cdc2976b84768d0829c75cc8d8fc4d849be62cd.idx
│ │ │ │ │ └── pack-2cdc2976b84768d0829c75cc8d8fc4d849be62cd.pack
│ │ │ ├── info
│ │ │ │ └── exclude
│ │ │ └── config
│ │ ├── README.md
│ │ ├── api
│ │ │ ├── api.go
│ │ │ ├── ignoreCommit.go
│ │ │ └── ignoreGlobal.go
│ │ ├── .gitleaksignore
│ │ └── main.go
│ ├── staged
│ │ ├── dotGit
│ │ │ ├── HEAD
│ │ │ ├── COMMIT_EDITMSG
│ │ │ ├── ORIG_HEAD
│ │ │ ├── refs
│ │ │ │ ├── heads
│ │ │ │ │ ├── foo
│ │ │ │ │ ├── api-pkg
│ │ │ │ │ ├── main
│ │ │ │ │ └── remove-secrets
│ │ │ │ └── remotes
│ │ │ │ │ └── origin
│ │ │ │ │ ├── HEAD
│ │ │ │ │ ├── foo
│ │ │ │ │ ├── main
│ │ │ │ │ └── api-pkg
│ │ │ ├── description
│ │ │ ├── FETCH_HEAD
│ │ │ ├── index
│ │ │ ├── packed-refs
│ │ │ ├── logs
│ │ │ │ ├── refs
│ │ │ │ │ ├── remotes
│ │ │ │ │ │ └── origin
│ │ │ │ │ │ │ ├── api-pkg
│ │ │ │ │ │ │ ├── foo
│ │ │ │ │ │ │ ├── main
│ │ │ │ │ │ │ └── HEAD
│ │ │ │ │ └── heads
│ │ │ │ │ │ ├── api-pkg
│ │ │ │ │ │ ├── remove-secrets
│ │ │ │ │ │ ├── foo
│ │ │ │ │ │ └── main
│ │ │ │ └── HEAD
│ │ │ ├── objects
│ │ │ │ ├── 15
│ │ │ │ │ └── 2888a42422b2ff5868b8d003d626120a9cb738
│ │ │ │ ├── 46
│ │ │ │ │ └── 18d7e4512b6b0b1dab85cf846d9f43474ec8be
│ │ │ │ ├── 49
│ │ │ │ │ └── 1504d5a31946ce75e22554cc34203d8e5ff3ca
│ │ │ │ ├── 65
│ │ │ │ │ └── 83d6db4a57bbeda62d50fc91649036d499418d
│ │ │ │ ├── 66
│ │ │ │ │ └── bc70d0c0bfbb6468b3f90c3f1e9f2ddba02b43
│ │ │ │ ├── 78
│ │ │ │ │ └── 9ba677976d5db481de55c799d67acbf8e3f16a
│ │ │ │ ├── 90
│ │ │ │ │ └── 6335481df9a4b48906c90318b4fac76b67fe73
│ │ │ │ ├── 02
│ │ │ │ │ └── d85657604c34e7b7fbb324a0c6c8b13c2c3760
│ │ │ │ ├── 2e
│ │ │ │ │ └── 1db472eeba53f06c4026ae4566ea022e36598e
│ │ │ │ ├── 5c
│ │ │ │ │ └── 547e4215d9594c3935bdfefdf4f500016a4112
│ │ │ │ ├── 9a
│ │ │ │ │ └── 932e37eaa9fb64b09e47e5e859c9b2c8cb47ad
│ │ │ │ ├── a1
│ │ │ │ │ └── 22b33c6bad3ee54724f52f2caad385ab1982ab
│ │ │ │ ├── a5
│ │ │ │ │ └── caae6d742e49a33982f1fdc608ce861ea59be5
│ │ │ │ ├── a9
│ │ │ │ │ └── aa0c942dcef669a94f207a77426106b25efd1a
│ │ │ │ ├── b1
│ │ │ │ │ └── 6d768dd595a59f947abe087901183d219d7e54
│ │ │ │ ├── bc
│ │ │ │ │ └── f47ef84f29bb7ed6e653d61fccd30d0ecce886
│ │ │ │ ├── bf
│ │ │ │ │ └── 3f24164d7256b4021575cbdb2f97b98e6f057e
│ │ │ │ ├── d8
│ │ │ │ │ └── 32479114dc6be7207edc7c37ce91dd11b93161
│ │ │ │ ├── da
│ │ │ │ │ └── 2622b4d97e32c5801511244b809144b6b3ea78
│ │ │ │ ├── e5
│ │ │ │ │ └── c0849a65c586eab87dcfc31fec74f0fd7c62cb
│ │ │ │ ├── f1
│ │ │ │ │ └── b58b97808f8e744f6a23c693859df5b5968901
│ │ │ │ └── pack
│ │ │ │ │ ├── pack-2cdc2976b84768d0829c75cc8d8fc4d849be62cd.idx
│ │ │ │ │ └── pack-2cdc2976b84768d0829c75cc8d8fc4d849be62cd.pack
│ │ │ ├── info
│ │ │ │ └── exclude
│ │ │ └── config
│ │ ├── .gitleaksignore
│ │ ├── README.md
│ │ ├── api
│ │ │ └── api.go
│ │ └── main.go
│ ├── symlinks
│ │ ├── file_symlink
│ │ │ └── symlinked_id_ed25519
│ │ └── source_file
│ │ │ └── id_ed25519
│ └── nogit
│ │ ├── .gitleaksignore
│ │ ├── api.go
│ │ └── main.go
├── baseline
│ ├── baseline.sarif
│ ├── baseline.csv
│ └── baseline.json
└── config
│ ├── path_only.toml
│ ├── entropy_group.toml
│ ├── bad_entropy_group.toml
│ ├── allow_global_aws_re.toml
│ ├── base.toml
│ ├── generic.toml
│ ├── escaped_character_group.toml
│ ├── extend_2.toml
│ ├── extend_1.toml
│ ├── extend_3.toml
│ ├── allow_path.toml
│ ├── allow_aws_re.toml
│ ├── allow_commit.toml
│ └── generic_with_py_path.toml
├── .github
├── FUNDING.yml
├── PULL_REQUEST_TEMPLATE.md
├── ISSUE_TEMPLATE
│ ├── maintenance.md
│ ├── feature_request.md
│ └── bug_report.md
└── workflows
│ ├── gitleaks.yml
│ ├── test.yml
│ └── release.yml
├── report
├── constants.go
├── json.go
├── finding_test.go
├── report.go
├── finding.go
├── csv.go
├── json_test.go
├── csv_test.go
├── report_test.go
├── sarif_test.go
├── junit.go
└── junit_test.go
├── .gitignore
├── cmd
├── generate
│ ├── secrets
│ │ └── regen.go
│ └── config
│ │ └── rules
│ │ ├── heroku.go
│ │ ├── algolia.go
│ │ ├── twilio.go
│ │ ├── databricks.go
│ │ ├── facebook.go
│ │ ├── age.go
│ │ ├── hubspot.go
│ │ ├── clojars.go
│ │ ├── frameio.go
│ │ ├── npm.go
│ │ ├── airtable.go
│ │ ├── prefect.go
│ │ ├── pulumi.go
│ │ ├── readme.go
│ │ ├── beamer.go
│ │ ├── sentry.go
│ │ ├── duffel.go
│ │ ├── etsy.go
│ │ ├── fastly.go
│ │ ├── twitch.go
│ │ ├── intercom.go
│ │ ├── okta.go
│ │ ├── flickr.go
│ │ ├── mailchimp.go
│ │ ├── rubygems.go
│ │ ├── trello.go
│ │ ├── zendesk.go
│ │ ├── codecov.go
│ │ ├── droneci.go
│ │ ├── finnhub.go
│ │ ├── adafruit.go
│ │ ├── sendgrid.go
│ │ ├── travisci.go
│ │ ├── aws.go
│ │ ├── datadog.go
│ │ ├── contentful.go
│ │ ├── freshbooks.go
│ │ ├── mattermost.go
│ │ ├── typeform.go
│ │ ├── dynatrace.go
│ │ ├── mapbox.go
│ │ ├── netlify.go
│ │ ├── postman.go
│ │ ├── squarespace.go
│ │ ├── gitter.go
│ │ ├── pypi.go
│ │ ├── kraken.go
│ │ ├── stripe.go
│ │ ├── openai.go
│ │ ├── coinbase.go
│ │ ├── gocardless.go
│ │ ├── rapidapi.go
│ │ ├── launchdarkly.go
│ │ ├── sendinblue.go
│ │ ├── hashicorp.go
│ │ ├── doppler.go
│ │ ├── shippo.go
│ │ ├── nytimes.go
│ │ ├── atlassian.go
│ │ ├── privatekey.go
│ │ ├── teams.go
│ │ ├── definednetworking.go
│ │ ├── adobe.go
│ │ ├── easypost.go
│ │ ├── square.go
│ │ ├── vault.go
│ │ ├── linear.go
│ │ ├── alibaba.go
│ │ ├── asana.go
│ │ ├── bittrex.go
│ │ ├── finicity.go
│ │ ├── gcp.go
│ │ ├── kucoin.go
│ │ ├── snyk.go
│ │ ├── authress.go
│ │ ├── sendbird.go
│ │ ├── sumologic.go
│ │ ├── bitbucket.go
│ │ ├── confluent.go
│ │ ├── lob.go
│ │ ├── linkedin.go
│ │ ├── jwt.go
│ │ ├── generic.go
│ │ ├── dropbox.go
│ │ ├── digitalocean.go
│ │ ├── gitlab.go
│ │ ├── messagebird.go
│ │ ├── discord.go
│ │ ├── flutterwave.go
│ │ ├── mailgun.go
│ │ ├── plaid.go
│ │ ├── yandex.go
│ │ ├── grafana.go
│ │ ├── telegram.go
│ │ ├── newrelic.go
│ │ ├── shopify.go
│ │ ├── config.tmpl
│ │ ├── planetscale.go
│ │ ├── sidekiq.go
│ │ ├── github.go
│ │ └── twitter.go
└── version.go
├── config
├── utils.go
├── rule.go
├── allowlist.go
└── allowlist_test.go
├── .pre-commit-hooks.yaml
├── Dockerfile
├── .goreleaser.yml
├── Makefile
├── main.go
├── scripts
└── pre-commit.py
├── USERS.md
├── LICENSE
├── detect
├── location_test.go
├── baseline.go
└── location.go
└── go.mod
/testdata/expected/report/empty.json:
--------------------------------------------------------------------------------
1 | []
2 |
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/HEAD:
--------------------------------------------------------------------------------
1 | ref: refs/heads/main
2 |
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/HEAD:
--------------------------------------------------------------------------------
1 | ref: refs/heads/main
2 |
--------------------------------------------------------------------------------
/testdata/repos/staged/.gitleaksignore:
--------------------------------------------------------------------------------
1 | api/api.go:aws-access-key:6
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/COMMIT_EDITMSG:
--------------------------------------------------------------------------------
1 | add .gitleaksignore file
2 |
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/COMMIT_EDITMSG:
--------------------------------------------------------------------------------
1 | add .gitleaksignore test files
2 |
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/ORIG_HEAD:
--------------------------------------------------------------------------------
1 | cada78a9bf157ec05573f19e682d211f811c2e2d
2 |
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/ORIG_HEAD:
--------------------------------------------------------------------------------
1 | 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587
2 |
--------------------------------------------------------------------------------
/testdata/repos/symlinks/file_symlink/symlinked_id_ed25519:
--------------------------------------------------------------------------------
1 | ../source_file/id_ed25519
--------------------------------------------------------------------------------
/testdata/repos/small/README.md:
--------------------------------------------------------------------------------
1 | # test
2 | This is a repo used for testing gitleaks
3 |
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/refs/heads/foo:
--------------------------------------------------------------------------------
1 | f1b58b97808f8e744f6a23c693859df5b5968901
2 |
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/refs/heads/main:
--------------------------------------------------------------------------------
1 | 53cd7a3c6eb4937f413e3c25e4a9f39289afa69e
2 |
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/refs/remotes/origin/HEAD:
--------------------------------------------------------------------------------
1 | ref: refs/remotes/origin/main
2 |
--------------------------------------------------------------------------------
/testdata/repos/staged/README.md:
--------------------------------------------------------------------------------
1 | # test
2 | This is a repo used for testing gitleaks
3 |
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/refs/heads/foo:
--------------------------------------------------------------------------------
1 | f1b58b97808f8e744f6a23c693859df5b5968901
2 |
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/refs/remotes/origin/HEAD:
--------------------------------------------------------------------------------
1 | ref: refs/remotes/origin/main
2 |
--------------------------------------------------------------------------------
/testdata/repos/nogit/.gitleaksignore:
--------------------------------------------------------------------------------
1 | ../testdata/repos/nogit/api.go:aws-access-key:20
2 |
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/refs/heads/api-pkg:
--------------------------------------------------------------------------------
1 | a122b33c6bad3ee54724f52f2caad385ab1982ab
2 |
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/refs/heads/api-pkg:
--------------------------------------------------------------------------------
1 | a122b33c6bad3ee54724f52f2caad385ab1982ab
2 |
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/refs/heads/main:
--------------------------------------------------------------------------------
1 | bf3f24164d7256b4021575cbdb2f97b98e6f057e
2 |
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/refs/heads/remove-secrets:
--------------------------------------------------------------------------------
1 | a122b33c6bad3ee54724f52f2caad385ab1982ab
2 |
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/refs/remotes/origin/foo:
--------------------------------------------------------------------------------
1 | f1b58b97808f8e744f6a23c693859df5b5968901
2 |
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/refs/remotes/origin/main:
--------------------------------------------------------------------------------
1 | 2e1db472eeba53f06c4026ae4566ea022e36598e
2 |
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/refs/remotes/origin/foo:
--------------------------------------------------------------------------------
1 | f1b58b97808f8e744f6a23c693859df5b5968901
2 |
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/refs/remotes/origin/main:
--------------------------------------------------------------------------------
1 | 2e1db472eeba53f06c4026ae4566ea022e36598e
2 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [zricethezav]
4 |
--------------------------------------------------------------------------------
/report/constants.go:
--------------------------------------------------------------------------------
1 | package report
2 |
3 | const version = "v8.0.0"
4 | const driver = "gitleaks"
5 |
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/refs/remotes/origin/api-pkg:
--------------------------------------------------------------------------------
1 | a122b33c6bad3ee54724f52f2caad385ab1982ab
2 |
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/refs/heads/remove-secrets:
--------------------------------------------------------------------------------
1 | a122b33c6bad3ee54724f52f2caad385ab1982ab
2 |
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/refs/remotes/origin/api-pkg:
--------------------------------------------------------------------------------
1 | a122b33c6bad3ee54724f52f2caad385ab1982ab
2 |
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/description:
--------------------------------------------------------------------------------
1 | Unnamed repository; edit this file 'description' to name the repository.
2 |
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/description:
--------------------------------------------------------------------------------
1 | Unnamed repository; edit this file 'description' to name the repository.
2 |
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/index:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/small/dotGit/index
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/FETCH_HEAD:
--------------------------------------------------------------------------------
1 | 2e1db472eeba53f06c4026ae4566ea022e36598e branch 'main' of github.com:gitleaks/test
2 |
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/FETCH_HEAD:
--------------------------------------------------------------------------------
1 | 2e1db472eeba53f06c4026ae4566ea022e36598e branch 'main' of github.com:gitleaks/test
2 |
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/index:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/staged/dotGit/index
--------------------------------------------------------------------------------
/testdata/repos/small/api/api.go:
--------------------------------------------------------------------------------
1 | package api
2 |
3 | import "fmt"
4 |
5 | func PrintHello() {
6 | fmt.Println("hello")
7 | }
8 |
--------------------------------------------------------------------------------
/testdata/baseline/baseline.sarif:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/sarif-2.1.0.json",
3 | "version": "2.1.0",
4 | "runs": [
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/testdata/config/path_only.toml:
--------------------------------------------------------------------------------
1 | title = "gitleaks config"
2 |
3 | [[rules]]
4 | description = "Python Files"
5 | id = "python-files-only"
6 | path = '''.py'''
7 |
--------------------------------------------------------------------------------
/testdata/repos/small/.gitleaksignore:
--------------------------------------------------------------------------------
1 | api/ignoreGlobal.go:aws-access-key:20
2 | 53cd7a3c6eb4937f413e3c25e4a9f39289afa69e:api/ignoreCommit.go:aws-access-key:20
3 |
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/packed-refs:
--------------------------------------------------------------------------------
1 | # pack-refs with: peeled fully-peeled sorted
2 | 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 refs/remotes/origin/main
3 |
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/packed-refs:
--------------------------------------------------------------------------------
1 | # pack-refs with: peeled fully-peeled sorted
2 | 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 refs/remotes/origin/main
3 |
--------------------------------------------------------------------------------
/testdata/baseline/baseline.csv:
--------------------------------------------------------------------------------
1 | RuleID,Commit,File,Secret,Match,StartLine,EndLine,StartColumn,EndColumn,Author,Message,Date,Email,Fingerprint
2 | 1,b,c,f,s,m,s,e,s,e,a,m,f,r,f
--------------------------------------------------------------------------------
/testdata/expected/report/junit_empty.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/logs/refs/remotes/origin/foo:
--------------------------------------------------------------------------------
1 | 0000000000000000000000000000000000000000 f1b58b97808f8e744f6a23c693859df5b5968901 Zach Rice 1635896935 -0500 update by push
2 |
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/logs/refs/remotes/origin/api-pkg:
--------------------------------------------------------------------------------
1 | 0000000000000000000000000000000000000000 a122b33c6bad3ee54724f52f2caad385ab1982ab Zach Rice 1635896552 -0500 update by push
2 |
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/objects/02/d85657604c34e7b7fbb324a0c6c8b13c2c3760:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/small/dotGit/objects/02/d85657604c34e7b7fbb324a0c6c8b13c2c3760
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/objects/15/2888a42422b2ff5868b8d003d626120a9cb738:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/small/dotGit/objects/15/2888a42422b2ff5868b8d003d626120a9cb738
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/objects/2e/1db472eeba53f06c4026ae4566ea022e36598e:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/small/dotGit/objects/2e/1db472eeba53f06c4026ae4566ea022e36598e
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/objects/32/bfaec6697c1a693f71b183d3389ad2547bbb3c:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/small/dotGit/objects/32/bfaec6697c1a693f71b183d3389ad2547bbb3c
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/objects/49/1504d5a31946ce75e22554cc34203d8e5ff3ca:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/small/dotGit/objects/49/1504d5a31946ce75e22554cc34203d8e5ff3ca
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/objects/4f/77f1b3cc39d4b17e4cf4ba0a38f5daed9875b4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/small/dotGit/objects/4f/77f1b3cc39d4b17e4cf4ba0a38f5daed9875b4
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/objects/53/cd7a3c6eb4937f413e3c25e4a9f39289afa69e:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/small/dotGit/objects/53/cd7a3c6eb4937f413e3c25e4a9f39289afa69e
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/objects/5c/547e4215d9594c3935bdfefdf4f500016a4112:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/small/dotGit/objects/5c/547e4215d9594c3935bdfefdf4f500016a4112
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/objects/78/9ba677976d5db481de55c799d67acbf8e3f16a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/small/dotGit/objects/78/9ba677976d5db481de55c799d67acbf8e3f16a
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/objects/8d/c20a62e189d3446cfb6ec328dbd379d64feb20:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/small/dotGit/objects/8d/c20a62e189d3446cfb6ec328dbd379d64feb20
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/objects/90/6335481df9a4b48906c90318b4fac76b67fe73:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/small/dotGit/objects/90/6335481df9a4b48906c90318b4fac76b67fe73
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/objects/98/1ab8417104c91bb9a4657f5d436c760c0aff50:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/small/dotGit/objects/98/1ab8417104c91bb9a4657f5d436c760c0aff50
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/objects/9a/932e37eaa9fb64b09e47e5e859c9b2c8cb47ad:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/small/dotGit/objects/9a/932e37eaa9fb64b09e47e5e859c9b2c8cb47ad
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/objects/a1/22b33c6bad3ee54724f52f2caad385ab1982ab:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/small/dotGit/objects/a1/22b33c6bad3ee54724f52f2caad385ab1982ab
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/objects/a5/caae6d742e49a33982f1fdc608ce861ea59be5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/small/dotGit/objects/a5/caae6d742e49a33982f1fdc608ce861ea59be5
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/objects/a9/aa0c942dcef669a94f207a77426106b25efd1a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/small/dotGit/objects/a9/aa0c942dcef669a94f207a77426106b25efd1a
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/objects/ac/bef43fdb053ec01e8e16697536d47853460cbc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/small/dotGit/objects/ac/bef43fdb053ec01e8e16697536d47853460cbc
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/objects/bc/f47ef84f29bb7ed6e653d61fccd30d0ecce886:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/small/dotGit/objects/bc/f47ef84f29bb7ed6e653d61fccd30d0ecce886
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/objects/ca/da78a9bf157ec05573f19e682d211f811c2e2d:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/small/dotGit/objects/ca/da78a9bf157ec05573f19e682d211f811c2e2d
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/objects/d8/32479114dc6be7207edc7c37ce91dd11b93161:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/small/dotGit/objects/d8/32479114dc6be7207edc7c37ce91dd11b93161
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/objects/da/2622b4d97e32c5801511244b809144b6b3ea78:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/small/dotGit/objects/da/2622b4d97e32c5801511244b809144b6b3ea78
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/objects/da/eb160a13200a3422e73296a6892784a113e0d6:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/small/dotGit/objects/da/eb160a13200a3422e73296a6892784a113e0d6
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/objects/df/7eaa59fc89b3e7258167605db2e582f1a78e6f:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/small/dotGit/objects/df/7eaa59fc89b3e7258167605db2e582f1a78e6f
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/objects/e5/c0849a65c586eab87dcfc31fec74f0fd7c62cb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/small/dotGit/objects/e5/c0849a65c586eab87dcfc31fec74f0fd7c62cb
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/objects/f1/b58b97808f8e744f6a23c693859df5b5968901:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/small/dotGit/objects/f1/b58b97808f8e744f6a23c693859df5b5968901
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/objects/fa/468655086f149d41a8e7db14ed054bebec7687:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/small/dotGit/objects/fa/468655086f149d41a8e7db14ed054bebec7687
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/logs/refs/remotes/origin/api-pkg:
--------------------------------------------------------------------------------
1 | 0000000000000000000000000000000000000000 a122b33c6bad3ee54724f52f2caad385ab1982ab Zach Rice 1635896552 -0500 update by push
2 |
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/logs/refs/remotes/origin/foo:
--------------------------------------------------------------------------------
1 | 0000000000000000000000000000000000000000 f1b58b97808f8e744f6a23c693859df5b5968901 Zach Rice 1635896935 -0500 update by push
2 |
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/objects/02/d85657604c34e7b7fbb324a0c6c8b13c2c3760:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/staged/dotGit/objects/02/d85657604c34e7b7fbb324a0c6c8b13c2c3760
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/objects/15/2888a42422b2ff5868b8d003d626120a9cb738:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/staged/dotGit/objects/15/2888a42422b2ff5868b8d003d626120a9cb738
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/objects/2e/1db472eeba53f06c4026ae4566ea022e36598e:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/staged/dotGit/objects/2e/1db472eeba53f06c4026ae4566ea022e36598e
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/objects/46/18d7e4512b6b0b1dab85cf846d9f43474ec8be:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/staged/dotGit/objects/46/18d7e4512b6b0b1dab85cf846d9f43474ec8be
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/objects/49/1504d5a31946ce75e22554cc34203d8e5ff3ca:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/staged/dotGit/objects/49/1504d5a31946ce75e22554cc34203d8e5ff3ca
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/objects/5c/547e4215d9594c3935bdfefdf4f500016a4112:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/staged/dotGit/objects/5c/547e4215d9594c3935bdfefdf4f500016a4112
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/objects/65/83d6db4a57bbeda62d50fc91649036d499418d:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/staged/dotGit/objects/65/83d6db4a57bbeda62d50fc91649036d499418d
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/objects/66/bc70d0c0bfbb6468b3f90c3f1e9f2ddba02b43:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/staged/dotGit/objects/66/bc70d0c0bfbb6468b3f90c3f1e9f2ddba02b43
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/objects/78/9ba677976d5db481de55c799d67acbf8e3f16a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/staged/dotGit/objects/78/9ba677976d5db481de55c799d67acbf8e3f16a
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/objects/90/6335481df9a4b48906c90318b4fac76b67fe73:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/staged/dotGit/objects/90/6335481df9a4b48906c90318b4fac76b67fe73
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/objects/9a/932e37eaa9fb64b09e47e5e859c9b2c8cb47ad:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/staged/dotGit/objects/9a/932e37eaa9fb64b09e47e5e859c9b2c8cb47ad
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/objects/a1/22b33c6bad3ee54724f52f2caad385ab1982ab:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/staged/dotGit/objects/a1/22b33c6bad3ee54724f52f2caad385ab1982ab
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/objects/a5/caae6d742e49a33982f1fdc608ce861ea59be5:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/staged/dotGit/objects/a5/caae6d742e49a33982f1fdc608ce861ea59be5
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/objects/a9/aa0c942dcef669a94f207a77426106b25efd1a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/staged/dotGit/objects/a9/aa0c942dcef669a94f207a77426106b25efd1a
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/objects/b1/6d768dd595a59f947abe087901183d219d7e54:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/staged/dotGit/objects/b1/6d768dd595a59f947abe087901183d219d7e54
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/objects/bc/f47ef84f29bb7ed6e653d61fccd30d0ecce886:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/staged/dotGit/objects/bc/f47ef84f29bb7ed6e653d61fccd30d0ecce886
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/objects/bf/3f24164d7256b4021575cbdb2f97b98e6f057e:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/staged/dotGit/objects/bf/3f24164d7256b4021575cbdb2f97b98e6f057e
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/objects/d8/32479114dc6be7207edc7c37ce91dd11b93161:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/staged/dotGit/objects/d8/32479114dc6be7207edc7c37ce91dd11b93161
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/objects/da/2622b4d97e32c5801511244b809144b6b3ea78:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/staged/dotGit/objects/da/2622b4d97e32c5801511244b809144b6b3ea78
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/objects/e5/c0849a65c586eab87dcfc31fec74f0fd7c62cb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/staged/dotGit/objects/e5/c0849a65c586eab87dcfc31fec74f0fd7c62cb
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/objects/f1/b58b97808f8e744f6a23c693859df5b5968901:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/staged/dotGit/objects/f1/b58b97808f8e744f6a23c693859df5b5968901
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/logs/refs/heads/api-pkg:
--------------------------------------------------------------------------------
1 | 0000000000000000000000000000000000000000 a122b33c6bad3ee54724f52f2caad385ab1982ab Zach Rice 1635896543 -0500 branch: Created from HEAD
2 |
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/logs/refs/heads/api-pkg:
--------------------------------------------------------------------------------
1 | 0000000000000000000000000000000000000000 a122b33c6bad3ee54724f52f2caad385ab1982ab Zach Rice 1635896543 -0500 branch: Created from HEAD
2 |
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/logs/refs/remotes/origin/main:
--------------------------------------------------------------------------------
1 | 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 2e1db472eeba53f06c4026ae4566ea022e36598e Zach Rice 1635896648 -0500 pull origin main: fast-forward
2 |
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/logs/refs/remotes/origin/main:
--------------------------------------------------------------------------------
1 | 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 2e1db472eeba53f06c4026ae4566ea022e36598e Zach Rice 1635896648 -0500 pull origin main: fast-forward
2 |
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/logs/refs/remotes/origin/HEAD:
--------------------------------------------------------------------------------
1 | 0000000000000000000000000000000000000000 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 Zach Rice 1635896329 -0500 clone: from github.com:gitleaks/test.git
2 |
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/objects/pack/pack-2cdc2976b84768d0829c75cc8d8fc4d849be62cd.idx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/small/dotGit/objects/pack/pack-2cdc2976b84768d0829c75cc8d8fc4d849be62cd.idx
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/objects/pack/pack-2cdc2976b84768d0829c75cc8d8fc4d849be62cd.pack:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/small/dotGit/objects/pack/pack-2cdc2976b84768d0829c75cc8d8fc4d849be62cd.pack
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/logs/refs/remotes/origin/HEAD:
--------------------------------------------------------------------------------
1 | 0000000000000000000000000000000000000000 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 Zach Rice 1635896329 -0500 clone: from github.com:gitleaks/test.git
2 |
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/objects/pack/pack-2cdc2976b84768d0829c75cc8d8fc4d849be62cd.idx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/staged/dotGit/objects/pack/pack-2cdc2976b84768d0829c75cc8d8fc4d849be62cd.idx
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/objects/pack/pack-2cdc2976b84768d0829c75cc8d8fc4d849be62cd.pack:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/gitleaks/master/testdata/repos/staged/dotGit/objects/pack/pack-2cdc2976b84768d0829c75cc8d8fc4d849be62cd.pack
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ### Description:
2 | Explain the purpose of the PR.
3 |
4 | ### Checklist:
5 |
6 | * [ ] Does your PR pass tests?
7 | * [ ] Have you written new tests for your changes?
8 | * [ ] Have you lint your code locally prior to submission?
9 |
--------------------------------------------------------------------------------
/testdata/config/entropy_group.toml:
--------------------------------------------------------------------------------
1 | title = "gitleaks config"
2 |
3 | [[rules]]
4 | id = "discord-api-key"
5 | description = "Discord API key"
6 | regex = '''(?i)(discord[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-h0-9]{64})['\"]'''
7 | secretGroup = 3
8 | entropy = 3.5
9 |
--------------------------------------------------------------------------------
/testdata/config/bad_entropy_group.toml:
--------------------------------------------------------------------------------
1 | title = "gitleaks config"
2 |
3 | [[rules]]
4 | id = "discord-api-key"
5 | description = "Discord API key"
6 | regex = '''(?i)(discord[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-h0-9]{64})['\"]'''
7 | secretGroup = 5
8 | entropy = 3.5
9 |
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/info/exclude:
--------------------------------------------------------------------------------
1 | # git ls-files --others --exclude-from=.git/info/exclude
2 | # Lines that start with '#' are comments.
3 | # For a project mostly in C, the following would be a good set of
4 | # exclude patterns (uncomment them if you want to use them):
5 | # *.[oa]
6 | # *~
7 |
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/info/exclude:
--------------------------------------------------------------------------------
1 | # git ls-files --others --exclude-from=.git/info/exclude
2 | # Lines that start with '#' are comments.
3 | # For a project mostly in C, the following would be a good set of
4 | # exclude patterns (uncomment them if you want to use them):
5 | # *.[oa]
6 | # *~
7 |
--------------------------------------------------------------------------------
/testdata/config/allow_global_aws_re.toml:
--------------------------------------------------------------------------------
1 | [[rules]]
2 | description = "AWS Access Key"
3 | id = "aws-access-key"
4 | regex = '''(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}'''
5 | tags = ["key", "AWS"]
6 |
7 | [allowlist]
8 | regexes = ['''AKIALALEMEL33243OLIA''']
9 |
--------------------------------------------------------------------------------
/testdata/config/base.toml:
--------------------------------------------------------------------------------
1 | title = "gitleaks config"
2 |
3 | [extend]
4 | path="../testdata/config/extend_1.toml"
5 |
6 | [[rules]]
7 | description = "AWS Secret Key"
8 | id = "aws-secret-key"
9 | regex = '''(?i)aws_(.{0,20})?=?.[\'\"0-9a-zA-Z\/+]{40}'''
10 | tags = ["key", "AWS"]
11 |
--------------------------------------------------------------------------------
/testdata/config/generic.toml:
--------------------------------------------------------------------------------
1 | title = "gitleaks config"
2 |
3 | [[rules]]
4 | description = "Generic API Key"
5 | id = "generic-api-key"
6 | regex = '''(?i)((key|api|token|secret|password)[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([0-9a-zA-Z\-_=]{8,64})['\"]'''
7 | entropy = 3.7
8 | secretGroup = 4
9 |
--------------------------------------------------------------------------------
/testdata/expected/report/csv_simple.csv:
--------------------------------------------------------------------------------
1 | RuleID,Commit,File,SymlinkFile,Secret,Match,StartLine,EndLine,StartColumn,EndColumn,Author,Message,Date,Email,Fingerprint,Tags
2 | test-rule,0000000000000000,auth.py,,a secret,line containing secret,1,2,1,2,John Doe,opps,10-19-2003,johndoe@gmail.com,fingerprint,tag1 tag2 tag3
3 |
--------------------------------------------------------------------------------
/testdata/config/escaped_character_group.toml:
--------------------------------------------------------------------------------
1 | title = "gitleaks config"
2 | # https://learnxinyminutes.com/docs/toml/ for toml reference
3 |
4 | [[rules]]
5 | id = "pypi-upload-token"
6 | description = "PyPI upload token"
7 | regex = '''pypi-AgEIcHlwaS5vcmc[A-Za-z0-9\-_]{50,1000}'''
8 | tags = ["key", "pypi"]
--------------------------------------------------------------------------------
/testdata/config/extend_2.toml:
--------------------------------------------------------------------------------
1 | title = "gitleaks extended 2"
2 |
3 | [extend]
4 | path="../testdata/config/extend_3.toml"
5 |
6 | [[rules]]
7 | description = "AWS Secret Key"
8 | id = "aws-secret-key-again"
9 | regex = '''(?i)aws_(.{0,20})?=?.[\'\"0-9a-zA-Z\/+]{40}'''
10 | tags = ["key", "AWS"]
11 |
--------------------------------------------------------------------------------
/testdata/repos/staged/api/api.go:
--------------------------------------------------------------------------------
1 | package api
2 |
3 | import "fmt"
4 |
5 | func PrintHello() {
6 | aws_token := "AKIALALEMEL33243OLIA" // fingerprint of that secret is added to .gitleaksignore
7 | aws_token2 := "AKIALALEMEL33243OLIA" // this one is not
8 | fmt.Println(aws_token)
9 | fmt.Println(aws_token2)
10 | }
11 |
--------------------------------------------------------------------------------
/testdata/config/extend_1.toml:
--------------------------------------------------------------------------------
1 | title = "gitleaks extended 1"
2 |
3 | [extend]
4 | path="../testdata/config/extend_2.toml"
5 |
6 | [[rules]]
7 | description = "AWS Access Key"
8 | id = "aws-access-key"
9 | regex = '''(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}'''
10 | tags = ["key", "AWS"]
11 |
--------------------------------------------------------------------------------
/testdata/expected/git/small-branch-foo.txt:
--------------------------------------------------------------------------------
1 | import (
2 | "fmt"
3 | "os"
4 | )
5 | // seems safer
6 | aws_token := os.Getenv("AWS_TOKEN")
7 | package foo
8 |
9 | import "fmt"
10 |
11 | func Foo() {
12 | fmt.Println("foo")
13 |
14 | // seems safe
15 | aws_token := "AKIALALEMEL33243OLIA"
16 | fmt.Println(aws_token)
17 | }
18 |
--------------------------------------------------------------------------------
/testdata/config/extend_3.toml:
--------------------------------------------------------------------------------
1 | title = "gitleaks extended 3"
2 |
3 | ## This should not be loaded since we can only extend configs to a depth of 3
4 |
5 | [[rules]]
6 | description = "AWS Secret Key"
7 | id = "aws-secret-key-again-again"
8 | regex = '''(?i)aws_(.{0,20})?=?.[\'\"0-9a-zA-Z\/+]{40}'''
9 | tags = ["key", "AWS"]
10 |
--------------------------------------------------------------------------------
/testdata/config/allow_path.toml:
--------------------------------------------------------------------------------
1 | title = "simple config with allowlist for .go files"
2 |
3 | [[rules]]
4 | description = "AWS Access Key"
5 | id = "aws-access-key"
6 | regex = '''(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}'''
7 | tags = ["key", "AWS"]
8 | [rules.allowlist]
9 | paths = ['''.go''']
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.exe~
4 | *.dll
5 | *.so
6 | *.dylib
7 | *.DS_STORE
8 | *.idea
9 | *.got
10 | gitleaks
11 | build
12 |
13 | # configs
14 | .gitleaks.toml
15 | cmd/generate/config/gitleaks.toml
16 |
17 | # test results
18 | testdata/expected/report/*.got.*
19 |
20 | # Test binary
21 | *.out
22 |
23 | dist/
24 |
--------------------------------------------------------------------------------
/report/json.go:
--------------------------------------------------------------------------------
1 | package report
2 |
3 | import (
4 | "encoding/json"
5 | "io"
6 | )
7 |
8 | func writeJson(findings []Finding, w io.WriteCloser) error {
9 | if len(findings) == 0 {
10 | findings = []Finding{}
11 | }
12 | defer w.Close()
13 |
14 | encoder := json.NewEncoder(w)
15 | encoder.SetIndent("", " ")
16 | return encoder.Encode(findings)
17 | }
18 |
--------------------------------------------------------------------------------
/testdata/config/allow_aws_re.toml:
--------------------------------------------------------------------------------
1 | title = "simple config with allowlist for aws"
2 |
3 | [[rules]]
4 | description = "AWS Access Key"
5 | id = "aws-access-key"
6 | regex = '''(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}'''
7 | tags = ["key", "AWS"]
8 | [rules.allowlist]
9 | regexes = ['''AKIALALEMEL33243OLIA''']
10 |
--------------------------------------------------------------------------------
/testdata/config/allow_commit.toml:
--------------------------------------------------------------------------------
1 | title = "simple config with allowlist for a specific commit"
2 |
3 | [[rules]]
4 | description = "AWS Access Key"
5 | id = "aws-access-key"
6 | regex = '''(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}'''
7 | tags = ["key", "AWS"]
8 | [rules.allowlist]
9 | commits = ['''allowthiscommit''']
10 |
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/config:
--------------------------------------------------------------------------------
1 | [core]
2 | repositoryformatversion = 0
3 | filemode = true
4 | bare = false
5 | logallrefupdates = true
6 | ignorecase = true
7 | precomposeunicode = true
8 | [remote "origin"]
9 | url = git@github.com:gitleaks/test.git
10 | fetch = +refs/heads/*:refs/remotes/origin/*
11 | [branch "main"]
12 | remote = origin
13 | merge = refs/heads/main
14 |
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/config:
--------------------------------------------------------------------------------
1 | [core]
2 | repositoryformatversion = 0
3 | filemode = true
4 | bare = false
5 | logallrefupdates = true
6 | ignorecase = true
7 | precomposeunicode = true
8 | [remote "origin"]
9 | url = git@github.com:gitleaks/test.git
10 | fetch = +refs/heads/*:refs/remotes/origin/*
11 | [branch "main"]
12 | remote = origin
13 | merge = refs/heads/main
14 |
--------------------------------------------------------------------------------
/testdata/repos/nogit/api.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | func main() {
6 |
7 | var a = "initial"
8 | fmt.Println(a)
9 |
10 | var b, c int = 1, 2
11 | fmt.Println(b, c)
12 |
13 | var d = true
14 | fmt.Println(d)
15 |
16 | var e int
17 | fmt.Println(e)
18 |
19 | // opps I added a secret at line 20
20 | awsToken := "AKIALALEMEL33243OLIA"
21 |
22 | f := "apple"
23 | fmt.Println(f)
24 | }
25 |
--------------------------------------------------------------------------------
/cmd/generate/secrets/regen.go:
--------------------------------------------------------------------------------
1 | // Package reggen generates text based on regex definitions
2 | // This is a slightly altered version of https://github.com/lucasjones/reggen
3 | package secrets
4 |
5 | import (
6 | "github.com/lucasjones/reggen"
7 | )
8 |
9 | func NewSecret(regex string) string {
10 | g, err := reggen.NewGenerator(regex)
11 | if err != nil {
12 | panic(err)
13 | }
14 | return g.Generate(1)
15 | }
16 |
--------------------------------------------------------------------------------
/testdata/repos/nogit/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | func main() {
6 |
7 | var a = "initial"
8 | fmt.Println(a)
9 |
10 | var b, c int = 1, 2
11 | fmt.Println(b, c)
12 |
13 | var d = true
14 | fmt.Println(d)
15 |
16 | var e int
17 | fmt.Println(e)
18 |
19 | // opps I added a secret at line 20
20 | awsToken := "AKIALALEMEL33243OLIA"
21 |
22 | f := "apple"
23 | fmt.Println(f)
24 | }
25 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/maintenance.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Maintenance request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: enhancement
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the solution you'd like**
11 | A clear and concise description of what you want to happen.
12 |
13 | **Additional context**
14 | Add any other context or screenshots about the feature request here.
15 |
16 | cc @zricethezav
17 |
--------------------------------------------------------------------------------
/testdata/repos/small/api/ignoreCommit.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | func main() {
6 |
7 | var a = "initial"
8 | fmt.Println(a)
9 |
10 | var b, c int = 1, 2
11 | fmt.Println(b, c)
12 |
13 | var d = true
14 | fmt.Println(d)
15 |
16 | var e int
17 | fmt.Println(e)
18 |
19 | // opps I added a secret at line 20
20 | awsToken := "AKIALALEMEL33243OLIA"
21 |
22 | f := "apple"
23 | fmt.Println(f)
24 | }
25 |
--------------------------------------------------------------------------------
/testdata/repos/small/api/ignoreGlobal.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | func main() {
6 |
7 | var a = "initial"
8 | fmt.Println(a)
9 |
10 | var b, c int = 1, 2
11 | fmt.Println(b, c)
12 |
13 | var d = true
14 | fmt.Println(d)
15 |
16 | var e int
17 | fmt.Println(e)
18 |
19 | // opps I added a secret at line 20
20 | awsToken := "AKIALALEMEL33243OLIA"
21 |
22 | f := "apple"
23 | fmt.Println(f)
24 | }
25 |
--------------------------------------------------------------------------------
/testdata/repos/small/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | )
7 |
8 | func main() {
9 |
10 | var a = "initial"
11 | fmt.Println(a)
12 |
13 | var b, c int = 1, 2
14 | fmt.Println(b, c)
15 |
16 | var d = true
17 | fmt.Println(d)
18 |
19 | var e int
20 | fmt.Println(e)
21 |
22 | // load secret via env
23 | awsToken := os.Getenv("AWS_TOKEN")
24 |
25 | f := "apple"
26 | fmt.Println(f)
27 | }
28 |
--------------------------------------------------------------------------------
/testdata/repos/staged/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | )
7 |
8 | func main() {
9 |
10 | var a = "initial"
11 | fmt.Println(a)
12 |
13 | var b, c int = 1, 2
14 | fmt.Println(b, c)
15 |
16 | var d = true
17 | fmt.Println(d)
18 |
19 | var e int
20 | fmt.Println(e)
21 |
22 | // load secret via env
23 | awsToken := os.Getenv("AWS_TOKEN")
24 |
25 | f := "apple"
26 | fmt.Println(f)
27 | }
28 |
--------------------------------------------------------------------------------
/.github/workflows/gitleaks.yml:
--------------------------------------------------------------------------------
1 | name: gitleaks
2 | on: [push, workflow_dispatch]
3 | jobs:
4 | scan:
5 | name: gitleaks
6 | runs-on: ubuntu-latest
7 | steps:
8 | - uses: actions/checkout@v3
9 | with:
10 | fetch-depth: 0
11 | - uses: gitleaks/gitleaks-action@v2
12 | env:
13 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
14 | GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE}}
15 |
--------------------------------------------------------------------------------
/testdata/repos/symlinks/source_file/id_ed25519:
--------------------------------------------------------------------------------
1 | -----BEGIN OPENSSH PRIVATE KEY-----
2 | b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
3 | QyNTUxOQAAACA8YWKYztuuvxUIMomc3zv0OdXCT57Cc2cRYu3TMbX9XAAAAJDiKO3C4ijt
4 | wgAAAAtzc2gtZWQyNTUxOQAAACA8YWKYztuuvxUIMomc3zv0OdXCT57Cc2cRYu3TMbX9XA
5 | AAAECzmj8DGxg5YHtBK4AmBttMXDQHsPAaCyYHQjJ4YujRBTxhYpjO266/FQgyiZzfO/Q5
6 | 1cJPnsJzZxFi7dMxtf1cAAAADHJvb3RAZGV2aG9zdAE=
7 | -----END OPENSSH PRIVATE KEY-----
8 |
--------------------------------------------------------------------------------
/cmd/version.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/spf13/cobra"
7 | )
8 |
9 | var Version = "version is set by build process"
10 |
11 | func init() {
12 | rootCmd.AddCommand(versionCmd)
13 | }
14 |
15 | var versionCmd = &cobra.Command{
16 | Use: "version",
17 | Short: "display gitleaks version",
18 | Run: runVersion,
19 | }
20 |
21 | func runVersion(cmd *cobra.Command, args []string) {
22 | fmt.Println(Version)
23 | }
24 |
--------------------------------------------------------------------------------
/config/utils.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "regexp"
5 | )
6 |
7 | func anyRegexMatch(f string, res []*regexp.Regexp) bool {
8 | for _, re := range res {
9 | if regexMatched(f, re) {
10 | return true
11 | }
12 | }
13 | return false
14 | }
15 |
16 | func regexMatched(f string, re *regexp.Regexp) bool {
17 | if re == nil {
18 | return false
19 | }
20 | if re.FindString(f) != "" {
21 | return true
22 | }
23 | return false
24 | }
25 |
--------------------------------------------------------------------------------
/.pre-commit-hooks.yaml:
--------------------------------------------------------------------------------
1 | - id: gitleaks
2 | name: Detect hardcoded secrets
3 | description: Detect hardcoded secrets using Gitleaks
4 | entry: gitleaks protect --verbose --redact --staged
5 | language: golang
6 | pass_filenames: false
7 | - id: gitleaks-docker
8 | name: Detect hardcoded secrets
9 | description: Detect hardcoded secrets using Gitleaks
10 | entry: zricethezav/gitleaks protect --verbose --redact --staged
11 | language: docker_image
12 |
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/logs/refs/heads/remove-secrets:
--------------------------------------------------------------------------------
1 | 0000000000000000000000000000000000000000 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 Zach Rice 1635896362 -0500 branch: Created from HEAD
2 | 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 906335481df9a4b48906c90318b4fac76b67fe73 Zach Rice 1635896426 -0500 commit: load token via env var
3 | 906335481df9a4b48906c90318b4fac76b67fe73 a122b33c6bad3ee54724f52f2caad385ab1982ab Zach Rice 1635896518 -0500 commit: add api package
4 |
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/logs/refs/heads/remove-secrets:
--------------------------------------------------------------------------------
1 | 0000000000000000000000000000000000000000 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 Zach Rice 1635896362 -0500 branch: Created from HEAD
2 | 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 906335481df9a4b48906c90318b4fac76b67fe73 Zach Rice 1635896426 -0500 commit: load token via env var
3 | 906335481df9a4b48906c90318b4fac76b67fe73 a122b33c6bad3ee54724f52f2caad385ab1982ab Zach Rice 1635896518 -0500 commit: add api package
4 |
--------------------------------------------------------------------------------
/testdata/expected/report/json_simple.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "Description": "",
4 | "StartLine": 1,
5 | "EndLine": 2,
6 | "StartColumn": 1,
7 | "EndColumn": 2,
8 | "Match": "line containing secret",
9 | "Secret": "a secret",
10 | "File": "auth.py",
11 | "SymlinkFile": "",
12 | "Commit": "0000000000000000",
13 | "Entropy": 0,
14 | "Author": "John Doe",
15 | "Email": "johndoe@gmail.com",
16 | "Date": "10-19-2003",
17 | "Message": "opps",
18 | "Tags": [],
19 | "RuleID": "test-rule",
20 | "Fingerprint": ""
21 | }
22 | ]
23 |
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/logs/refs/heads/foo:
--------------------------------------------------------------------------------
1 | 0000000000000000000000000000000000000000 2e1db472eeba53f06c4026ae4566ea022e36598e Zach Rice 1635896716 -0500 branch: Created from HEAD
2 | 2e1db472eeba53f06c4026ae4566ea022e36598e 491504d5a31946ce75e22554cc34203d8e5ff3ca Zach Rice 1635896886 -0500 commit: adding foo package with secret
3 | 491504d5a31946ce75e22554cc34203d8e5ff3ca f1b58b97808f8e744f6a23c693859df5b5968901 Zach Rice 1635896931 -0500 commit: removing secret from foo package
4 |
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/logs/refs/heads/foo:
--------------------------------------------------------------------------------
1 | 0000000000000000000000000000000000000000 2e1db472eeba53f06c4026ae4566ea022e36598e Zach Rice 1635896716 -0500 branch: Created from HEAD
2 | 2e1db472eeba53f06c4026ae4566ea022e36598e 491504d5a31946ce75e22554cc34203d8e5ff3ca Zach Rice 1635896886 -0500 commit: adding foo package with secret
3 | 491504d5a31946ce75e22554cc34203d8e5ff3ca f1b58b97808f8e744f6a23c693859df5b5968901 Zach Rice 1635896931 -0500 commit: removing secret from foo package
4 |
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/logs/refs/heads/main:
--------------------------------------------------------------------------------
1 | 0000000000000000000000000000000000000000 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 Zach Rice 1635896329 -0500 clone: from github.com:gitleaks/test.git
2 | 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 2e1db472eeba53f06c4026ae4566ea022e36598e Zach Rice 1635896648 -0500 pull origin main: Fast-forward
3 | 2e1db472eeba53f06c4026ae4566ea022e36598e bf3f24164d7256b4021575cbdb2f97b98e6f057e Rafael Figueiredo 1679239434 -0300 commit: add .gitleaksignore file
4 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM golang:1.19 AS build
2 | WORKDIR /go/src/github.com/zricethezav/gitleaks
3 | COPY . .
4 | RUN VERSION=$(git describe --tags --abbrev=0) && \
5 | CGO_ENABLED=0 go build -o bin/gitleaks -ldflags "-X="github.com/zricethezav/gitleaks/v8/cmd.Version=${VERSION}
6 |
7 | FROM alpine:3.16
8 | RUN adduser -D gitleaks && \
9 | apk add --no-cache bash git openssh-client
10 | COPY --from=build /go/src/github.com/zricethezav/gitleaks/bin/* /usr/bin/
11 | USER gitleaks
12 |
13 | RUN git config --global --add safe.directory '*'
14 |
15 | ENTRYPOINT ["gitleaks"]
16 |
--------------------------------------------------------------------------------
/report/finding_test.go:
--------------------------------------------------------------------------------
1 | package report
2 |
3 | import "testing"
4 |
5 | func TestRedact(t *testing.T) {
6 | tests := []struct {
7 | findings []Finding
8 | redact bool
9 | }{
10 | {
11 | redact: true,
12 | findings: []Finding{
13 | {
14 | Secret: "line containing secret",
15 | Match: "secret",
16 | },
17 | }},
18 | }
19 | for _, test := range tests {
20 | for _, f := range test.findings {
21 | f.Redact()
22 | if f.Secret != "REDACTED" {
23 | t.Error("redact not redacting: ", f.Secret)
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Test
2 |
3 | on:
4 | push:
5 | branches:
6 | - "*"
7 | pull_request:
8 | branches:
9 | - "*"
10 |
11 | jobs:
12 | test:
13 | runs-on: ubuntu-latest
14 | steps:
15 | - uses: actions/checkout@v3
16 |
17 | - name: Set up Go
18 | uses: actions/setup-go@v2
19 | with:
20 | go-version: 1.19
21 |
22 | - name: Build
23 | run: go build -v ./...
24 |
25 | - name: Test
26 | run: make test
27 |
28 | - name: Validate Config
29 | run: cd cmd/generate/config && go run main.go
30 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/heroku.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/config"
5 | )
6 |
7 | func Heroku() *config.Rule {
8 | // define rule
9 | r := config.Rule{
10 | Description: "Heroku API Key",
11 | RuleID: "heroku-api-key",
12 | Regex: generateSemiGenericRegex([]string{"heroku"}, hex8_4_4_4_12()),
13 | SecretGroup: 1,
14 | Keywords: []string{"heroku"},
15 | }
16 |
17 | // validate
18 | tps := []string{
19 | `const HEROKU_KEY = "12345678-ABCD-ABCD-ABCD-1234567890AB"`, // gitleaks:allow
20 | }
21 | return validate(r, tps, nil)
22 | }
23 |
--------------------------------------------------------------------------------
/.goreleaser.yml:
--------------------------------------------------------------------------------
1 | project_name: gitleaks
2 |
3 | builds:
4 | - main: main.go
5 | binary: gitleaks
6 | goos:
7 | - darwin
8 | - linux
9 | - windows
10 | goarch:
11 | - amd64
12 | - "386"
13 | - arm
14 | - arm64
15 | goarm:
16 | - "6"
17 | - "7"
18 | ldflags:
19 | - -s -w -X=github.com/zricethezav/gitleaks/v8/cmd.Version={{.Version}}
20 | archives:
21 | - builds: [gitleaks]
22 | format_overrides:
23 | - goos: windows
24 | format: zip
25 | replacements:
26 | amd64: x64
27 | 386: x32
28 | release:
29 | prerelease: true
30 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/algolia.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func AlgoliaApiKey() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | Description: "Algolia API Key",
12 | RuleID: "algolia-api-key",
13 | Regex: generateSemiGenericRegex([]string{"algolia"}, `[a-z0-9]{32}`),
14 | Keywords: []string{"algolia"},
15 | }
16 |
17 | // validate
18 | tps := []string{
19 | "algolia_key := " + secrets.NewSecret(hex("32")),
20 | }
21 | return validate(r, tps, nil)
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/twilio.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "regexp"
5 |
6 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
7 | "github.com/zricethezav/gitleaks/v8/config"
8 | )
9 |
10 | func Twilio() *config.Rule {
11 | // define rule
12 | r := config.Rule{
13 | Description: "Twilio API Key",
14 | RuleID: "twilio-api-key",
15 | Regex: regexp.MustCompile(`SK[0-9a-fA-F]{32}`),
16 | Keywords: []string{"twilio"},
17 | }
18 |
19 | // validate
20 | tps := []string{
21 | "twilioAPIKey := \"SK" + secrets.NewSecret(hex("32")) + "\"",
22 | }
23 | return validate(r, tps, nil)
24 | }
25 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/databricks.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func Databricks() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | Description: "Databricks API token",
12 | RuleID: "databricks-api-token",
13 | Regex: generateUniqueTokenRegex(`dapi[a-h0-9]{32}`),
14 | Keywords: []string{"dapi"},
15 | }
16 |
17 | // validate
18 | tps := []string{
19 | generateSampleSecret("databricks", "dapi"+secrets.NewSecret(hex("32"))),
20 | }
21 | return validate(r, tps, nil)
22 | }
23 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/facebook.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func Facebook() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | Description: "Facebook Access Token",
12 | RuleID: "facebook",
13 | Regex: generateSemiGenericRegex([]string{"facebook"}, hex("32")),
14 | SecretGroup: 1,
15 | Keywords: []string{"facebook"},
16 | }
17 |
18 | // validate
19 | tps := []string{
20 | generateSampleSecret("facebook", secrets.NewSecret(hex("32"))),
21 | }
22 | return validate(r, tps, nil)
23 | }
24 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/age.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "regexp"
5 |
6 | "github.com/zricethezav/gitleaks/v8/config"
7 | )
8 |
9 | func AgeSecretKey() *config.Rule {
10 | // define rule
11 | r := config.Rule{
12 | Description: "Age secret key",
13 | RuleID: "age secret key",
14 | Regex: regexp.MustCompile(`AGE-SECRET-KEY-1[QPZRY9X8GF2TVDW0S3JN54KHCE6MUA7L]{58}`),
15 | Keywords: []string{"AGE-SECRET-KEY-1"},
16 | }
17 |
18 | // validate
19 | tps := []string{
20 | `apiKey := "AGE-SECRET-KEY-1QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ`, // gitleaks:allow
21 | }
22 | return validate(r, tps, nil)
23 | }
24 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/hubspot.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/config"
5 | )
6 |
7 | func HubSpot() *config.Rule {
8 | // define rule
9 | r := config.Rule{
10 | Description: "HubSpot API Token",
11 | RuleID: "hubspot-api-key",
12 | Regex: generateSemiGenericRegex([]string{"hubspot"},
13 | `[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}`),
14 | SecretGroup: 1,
15 | Keywords: []string{"hubspot"},
16 | }
17 |
18 | // validate
19 | tps := []string{
20 | `const hubspotKey = "12345678-ABCD-ABCD-ABCD-1234567890AB"`, // gitleaks:allow
21 | }
22 | return validate(r, tps, nil)
23 | }
24 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/clojars.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "regexp"
5 |
6 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
7 | "github.com/zricethezav/gitleaks/v8/config"
8 | )
9 |
10 | func Clojars() *config.Rule {
11 | // define rule
12 | r := config.Rule{
13 | Description: "Clojars API token",
14 | RuleID: "clojars-api-token",
15 | Regex: regexp.MustCompile(`(?i)(CLOJARS_)[a-z0-9]{60}`),
16 | Keywords: []string{"clojars"},
17 | }
18 |
19 | // validate
20 | tps := []string{
21 | generateSampleSecret("clojars", "CLOJARS_"+secrets.NewSecret(alphaNumeric("60"))),
22 | }
23 | return validate(r, tps, nil)
24 | }
25 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: test test-cover
2 |
3 | PKG=github.com/zricethezav/gitleaks
4 | VERSION := `git fetch --tags && git tag | sort -V | tail -1`
5 | LDFLAGS=-ldflags "-X=github.com/zricethezav/gitleaks/v8/cmd.Version=$(VERSION)"
6 | COVER=--cover --coverprofile=cover.out
7 |
8 | test-cover:
9 | go test -v ./... --race $(COVER) $(PKG)
10 | go tool cover -html=cover.out
11 |
12 | format:
13 | go fmt ./...
14 |
15 | test: format
16 | go vet ./...
17 | go test -v ./... --race $(PKG)
18 |
19 | build: format
20 | go vet ./...
21 | go mod tidy
22 | go build $(LDFLAGS)
23 |
24 | clean:
25 | find . -type f -name '*.got.*' -delete
26 | find . -type f -name '*.out' -delete
27 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/frameio.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "regexp"
5 |
6 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
7 | "github.com/zricethezav/gitleaks/v8/config"
8 | )
9 |
10 | func FrameIO() *config.Rule {
11 | // define rule
12 | r := config.Rule{
13 | Description: "Frame.io API token",
14 | RuleID: "frameio-api-token",
15 | Regex: regexp.MustCompile(`fio-u-(?i)[a-z0-9\-_=]{64}`),
16 | Keywords: []string{"fio-u-"},
17 | }
18 |
19 | // validate
20 | tps := []string{
21 | generateSampleSecret("frameio", "fio-u-"+secrets.NewSecret(alphaNumericExtended("64"))),
22 | }
23 | return validate(r, tps, nil)
24 | }
25 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/npm.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func NPM() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "npm-access-token",
12 | Description: "npm access token",
13 | Regex: generateUniqueTokenRegex(`npm_[a-z0-9]{36}`),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "npm_",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("npmAccessToken", "npm_"+secrets.NewSecret(alphaNumeric("36"))),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/airtable.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func Airtable() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | Description: "Airtable API Key",
12 | RuleID: "airtable-api-key",
13 | Regex: generateSemiGenericRegex([]string{"airtable"}, alphaNumeric("17")),
14 | SecretGroup: 1,
15 | Keywords: []string{"airtable"},
16 | }
17 |
18 | // validate
19 | tps := []string{
20 | generateSampleSecret("airtable", secrets.NewSecret(alphaNumeric("17"))),
21 | }
22 | return validate(r, tps, nil)
23 | }
24 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/prefect.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func Prefect() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "prefect-api-token",
12 | Description: "Prefect API token",
13 | Regex: generateUniqueTokenRegex(`pnu_[a-z0-9]{36}`),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "pnu_",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("api-token", "pnu_"+secrets.NewSecret(alphaNumeric("36"))),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/pulumi.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func PulumiAPIToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "pulumi-api-token",
12 | Description: "Pulumi API token",
13 | Regex: generateUniqueTokenRegex(`pul-[a-f0-9]{40}`),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "pul-",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("pulumi-api-token", "pul-"+secrets.NewSecret(hex("40"))),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/readme.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func ReadMe() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "readme-api-token",
12 | Description: "Readme API token",
13 | Regex: generateUniqueTokenRegex(`rdme_[a-z0-9]{70}`),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "rdme_",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("api-token", "rdme_"+secrets.NewSecret(alphaNumeric("70"))),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/beamer.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func Beamer() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | Description: "Beamer API token",
12 | RuleID: "beamer-api-token",
13 | SecretGroup: 1,
14 | Regex: generateSemiGenericRegex([]string{"beamer"},
15 | `b_[a-z0-9=_\-]{44}`),
16 | Keywords: []string{"beamer"},
17 | }
18 |
19 | // validate
20 | tps := []string{
21 | generateSampleSecret("beamer", "b_"+secrets.NewSecret(alphaNumericExtended("44"))),
22 | }
23 | return validate(r, tps, nil)
24 | }
25 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/sentry.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func SentryAccessToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "sentry-access-token",
12 | Description: "Sentry Access Token",
13 | Regex: generateSemiGenericRegex([]string{"sentry"}, hex("64")),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "sentry",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("sentry", secrets.NewSecret(hex("64"))),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/duffel.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "regexp"
5 |
6 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
7 | "github.com/zricethezav/gitleaks/v8/config"
8 | )
9 |
10 | func Duffel() *config.Rule {
11 | // define rule
12 | r := config.Rule{
13 | RuleID: "duffel-api-token",
14 | Description: "Duffel API token",
15 | Regex: regexp.MustCompile(`duffel_(test|live)_(?i)[a-z0-9_\-=]{43}`),
16 | Keywords: []string{"duffel"},
17 | }
18 |
19 | // validate
20 | tps := []string{
21 | generateSampleSecret("duffel", "duffel_test_"+secrets.NewSecret(alphaNumericExtended("43"))),
22 | }
23 | return validate(r, tps, nil)
24 | }
25 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/etsy.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func EtsyAccessToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "etsy-access-token",
12 | Description: "Etsy Access Token",
13 | Regex: generateSemiGenericRegex([]string{"etsy"}, alphaNumeric("24")),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "etsy",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("etsy", secrets.NewSecret(alphaNumeric("24"))),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/fastly.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func FastlyAPIToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | Description: "Fastly API key",
12 | RuleID: "fastly-api-token",
13 | Regex: generateSemiGenericRegex([]string{"fastly"}, alphaNumericExtended("32")),
14 | SecretGroup: 1,
15 | Keywords: []string{"fastly"},
16 | }
17 |
18 | // validate
19 | tps := []string{
20 | generateSampleSecret("fastly", secrets.NewSecret(alphaNumericExtended("32"))),
21 | }
22 | return validate(r, tps, nil)
23 | }
24 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/twitch.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func TwitchAPIToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "twitch-api-token",
12 | Description: "Twitch API token",
13 | Regex: generateSemiGenericRegex([]string{"twitch"}, alphaNumeric("30")),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "twitch",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("twitch", secrets.NewSecret(alphaNumeric("30"))),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/intercom.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func Intercom() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | Description: "Intercom API Token",
12 | RuleID: "intercom-api-key",
13 | Regex: generateSemiGenericRegex([]string{"intercom"}, alphaNumericExtended("60")),
14 | SecretGroup: 1,
15 | Keywords: []string{"intercom"},
16 | }
17 |
18 | // validate
19 | tps := []string{
20 | generateSampleSecret("intercom", secrets.NewSecret(alphaNumericExtended("60"))),
21 | }
22 | return validate(r, tps, nil)
23 | }
24 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/okta.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func OktaAccessToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "okta-access-token",
12 | Description: "Okta Access Token",
13 | Regex: generateSemiGenericRegex([]string{"okta"},
14 | alphaNumericExtended("42")),
15 | SecretGroup: 1,
16 | Keywords: []string{
17 | "okta",
18 | },
19 | }
20 |
21 | // validate
22 | tps := []string{
23 | generateSampleSecret("okta", secrets.NewSecret(alphaNumeric("42"))),
24 | }
25 | return validate(r, tps, nil)
26 | }
27 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/flickr.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func FlickrAccessToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "flickr-access-token",
12 | Description: "Flickr Access Token",
13 | Regex: generateSemiGenericRegex([]string{"flickr"}, alphaNumeric("32")),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "flickr",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("flickr", secrets.NewSecret(alphaNumeric("32"))),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/mailchimp.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func MailChimp() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "mailchimp-api-key",
12 | Description: "Mailchimp API key",
13 | Regex: generateSemiGenericRegex([]string{"mailchimp"}, `[a-f0-9]{32}-us20`),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "mailchimp",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("mailchimp", secrets.NewSecret(hex("32"))+"-us20"),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/rubygems.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func RubyGemsAPIToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "rubygems-api-token",
12 | Description: "Rubygem API token",
13 | Regex: generateUniqueTokenRegex(`rubygems_[a-f0-9]{48}`),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "rubygems_",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("rubygemsAPIToken", "rubygems_"+secrets.NewSecret(hex("48"))),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/trello.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func TrelloAccessToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "trello-access-token",
12 | Description: "Trello Access Token",
13 | Regex: generateSemiGenericRegex([]string{"trello"}, `[a-zA-Z-0-9]{32}`),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "trello",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("trello", secrets.NewSecret(`[a-zA-Z-0-9]{32}`)),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/zendesk.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func ZendeskSecretKey() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "zendesk-secret-key",
12 | Description: "Zendesk Secret Key",
13 | Regex: generateSemiGenericRegex([]string{"zendesk"}, alphaNumeric("40")),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "zendesk",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("zendesk", secrets.NewSecret(alphaNumeric("40"))),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/codecov.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func CodecovAccessToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "codecov-access-token",
12 | Description: "Codecov Access Token",
13 | Regex: generateSemiGenericRegex([]string{"codecov"}, alphaNumeric("32")),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "codecov",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("codecov", secrets.NewSecret(alphaNumeric("32"))),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/droneci.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func DroneciAccessToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "droneci-access-token",
12 | Description: "Droneci Access Token",
13 | Regex: generateSemiGenericRegex([]string{"droneci"}, alphaNumeric("32")),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "droneci",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("droneci", secrets.NewSecret(alphaNumeric("32"))),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/finnhub.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func FinnhubAccessToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "finnhub-access-token",
12 | Description: "Finnhub Access Token",
13 | Regex: generateSemiGenericRegex([]string{"finnhub"}, alphaNumeric("20")),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "finnhub",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("finnhub", secrets.NewSecret(alphaNumeric("20"))),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/adafruit.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func AdafruitAPIKey() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | Description: "Adafruit API Key",
12 | RuleID: "adafruit-api-key",
13 | Regex: generateSemiGenericRegex([]string{"adafruit"}, alphaNumericExtendedShort("32")),
14 | SecretGroup: 1,
15 | Keywords: []string{"adafruit"},
16 | }
17 |
18 | // validate
19 | tps := []string{
20 | generateSampleSecret("adafruit", secrets.NewSecret(alphaNumericExtendedShort("32"))),
21 | }
22 | return validate(r, tps, nil)
23 | }
24 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/sendgrid.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func SendGridAPIToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "sendgrid-api-token",
12 | Description: "SendGrid API token",
13 | Regex: generateUniqueTokenRegex(`SG\.(?i)[a-z0-9=_\-\.]{66}`),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "SG.",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("sengridAPIToken", "SG."+secrets.NewSecret(alphaNumericExtended("66"))),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/travisci.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func TravisCIAccessToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "travisci-access-token",
12 | Description: "Travis CI Access Token",
13 | Regex: generateSemiGenericRegex([]string{"travis"}, alphaNumeric("22")),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "travis",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("travis", secrets.NewSecret(alphaNumeric("22"))),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/aws.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "regexp"
5 |
6 | "github.com/zricethezav/gitleaks/v8/config"
7 | )
8 |
9 | func AWS() *config.Rule {
10 | // define rule
11 | r := config.Rule{
12 | Description: "AWS",
13 | RuleID: "aws-access-token",
14 | Regex: regexp.MustCompile(
15 | "(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}"),
16 | Keywords: []string{
17 | "AKIA",
18 | "AGPA",
19 | "AIDA",
20 | "AROA",
21 | "AIPA",
22 | "ANPA",
23 | "ANVA",
24 | "ASIA",
25 | },
26 | }
27 |
28 | // validate
29 | tps := []string{generateSampleSecret("AWS", "AKIALALEMEL33243OLIB")} // gitleaks:allow
30 | return validate(r, tps, nil)
31 | }
32 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/datadog.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func DatadogtokenAccessToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "datadog-access-token",
12 | Description: "Datadog Access Token",
13 | Regex: generateSemiGenericRegex([]string{"datadog"},
14 | alphaNumeric("40")),
15 | SecretGroup: 1,
16 | Keywords: []string{
17 | "datadog",
18 | },
19 | }
20 |
21 | // validate
22 | tps := []string{
23 | generateSampleSecret("datadog", secrets.NewSecret(alphaNumeric("40"))),
24 | }
25 | return validate(r, tps, nil)
26 | }
27 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/contentful.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func Contentful() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | Description: "Contentful delivery API token",
12 | RuleID: "contentful-delivery-api-token",
13 | Regex: generateSemiGenericRegex([]string{"contentful"},
14 | alphaNumericExtended("43")),
15 | SecretGroup: 1,
16 | Keywords: []string{"contentful"},
17 | }
18 |
19 | // validate
20 | tps := []string{
21 | generateSampleSecret("contentful", secrets.NewSecret(alphaNumeric("43"))),
22 | }
23 | return validate(r, tps, nil)
24 | }
25 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/freshbooks.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func FreshbooksAccessToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "freshbooks-access-token",
12 | Description: "Freshbooks Access Token",
13 | Regex: generateSemiGenericRegex([]string{"freshbooks"}, alphaNumeric("64")),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "freshbooks",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("freshbooks", secrets.NewSecret(alphaNumeric("64"))),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/mattermost.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func MattermostAccessToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "mattermost-access-token",
12 | Description: "Mattermost Access Token",
13 | Regex: generateSemiGenericRegex([]string{"mattermost"}, alphaNumeric("26")),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "mattermost",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("mattermost", secrets.NewSecret(alphaNumeric("26"))),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/typeform.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func Typeform() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "typeform-api-token",
12 | Description: "Typeform API token",
13 | Regex: generateSemiGenericRegex([]string{"typeform"},
14 | `tfp_[a-z0-9\-_\.=]{59}`),
15 | SecretGroup: 1,
16 | Keywords: []string{
17 | "tfp_",
18 | },
19 | }
20 |
21 | // validate
22 | tps := []string{
23 | generateSampleSecret("typeformAPIToken", "tfp_"+secrets.NewSecret(alphaNumericExtended("59"))),
24 | }
25 | return validate(r, tps, nil)
26 | }
27 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/dynatrace.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "regexp"
5 |
6 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
7 | "github.com/zricethezav/gitleaks/v8/config"
8 | )
9 |
10 | func Dynatrace() *config.Rule {
11 | // define rule
12 | r := config.Rule{
13 | Description: "Dynatrace API token",
14 | RuleID: "dynatrace-api-token",
15 | Regex: regexp.MustCompile(`dt0c01\.(?i)[a-z0-9]{24}\.[a-z0-9]{64}`),
16 | Keywords: []string{"dynatrace"},
17 | }
18 |
19 | // validate
20 | tps := []string{
21 | generateSampleSecret("dynatrace", "dt0c01."+secrets.NewSecret(alphaNumeric("24"))+"."+secrets.NewSecret(alphaNumeric("64"))),
22 | }
23 | return validate(r, tps, nil)
24 | }
25 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/mapbox.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func MapBox() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | Description: "MapBox API token",
12 | RuleID: "mapbox-api-token",
13 | Regex: generateSemiGenericRegex([]string{"mapbox"}, `pk\.[a-z0-9]{60}\.[a-z0-9]{22}`),
14 | SecretGroup: 1,
15 | Keywords: []string{"mapbox"},
16 | }
17 |
18 | // validate
19 | tps := []string{
20 | generateSampleSecret("mapbox", "pk."+secrets.NewSecret(alphaNumeric("60"))+"."+secrets.NewSecret(alphaNumeric("22"))),
21 | }
22 | return validate(r, tps, nil)
23 | }
24 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/netlify.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func NetlifyAccessToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "netlify-access-token",
12 | Description: "Netlify Access Token",
13 | Regex: generateSemiGenericRegex([]string{"netlify"},
14 | alphaNumericExtended("40,46")),
15 | SecretGroup: 1,
16 | Keywords: []string{
17 | "netlify",
18 | },
19 | }
20 |
21 | // validate
22 | tps := []string{
23 | generateSampleSecret("netlify", secrets.NewSecret(alphaNumericExtended("40,46"))),
24 | }
25 | return validate(r, tps, nil)
26 | }
27 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/postman.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func PostManAPI() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "postman-api-token",
12 | Description: "Postman API token",
13 | Regex: generateUniqueTokenRegex(`PMAK-(?i)[a-f0-9]{24}\-[a-f0-9]{34}`),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "PMAK-",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("postmanAPItoken", "PMAK-"+secrets.NewSecret(hex("24"))+"-"+secrets.NewSecret(hex("34"))),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/squarespace.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func SquareSpaceAccessToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "squarespace-access-token",
12 | Description: "Squarespace Access Token",
13 | Regex: generateSemiGenericRegex([]string{"squarespace"}, hex8_4_4_4_12()),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "squarespace",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("squarespace", secrets.NewSecret(hex8_4_4_4_12())),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/gitter.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func GitterAccessToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "gitter-access-token",
12 | Description: "Gitter Access Token",
13 | Regex: generateSemiGenericRegex([]string{"gitter"},
14 | alphaNumericExtendedShort("40")),
15 | SecretGroup: 1,
16 | Keywords: []string{
17 | "gitter",
18 | },
19 | }
20 |
21 | // validate
22 | tps := []string{
23 | generateSampleSecret("gitter",
24 | secrets.NewSecret(alphaNumericExtendedShort("40"))),
25 | }
26 | return validate(r, tps, nil)
27 | }
28 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/pypi.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "regexp"
5 |
6 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
7 | "github.com/zricethezav/gitleaks/v8/config"
8 | )
9 |
10 | func PyPiUploadToken() *config.Rule {
11 | // define rule
12 | r := config.Rule{
13 | Description: "PyPI upload token",
14 | RuleID: "pypi-upload-token",
15 | Regex: regexp.MustCompile(
16 | `pypi-AgEIcHlwaS5vcmc[A-Za-z0-9\-_]{50,1000}`),
17 | Keywords: []string{
18 | "pypi-AgEIcHlwaS5vcmc",
19 | },
20 | }
21 |
22 | // validate
23 | tps := []string{"pypiToken := \"pypi-AgEIcHlwaS5vcmc" + secrets.NewSecret(hex("32")) +
24 | secrets.NewSecret(hex("32")) + "\""}
25 | return validate(r, tps, nil)
26 | }
27 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "os"
5 | "os/signal"
6 |
7 | "github.com/rs/zerolog"
8 | "github.com/rs/zerolog/log"
9 | "github.com/zricethezav/gitleaks/v8/cmd"
10 | )
11 |
12 | func main() {
13 | // send all logs to stdout
14 | log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
15 |
16 | // this block sets up a go routine to listen for an interrupt signal
17 | // which will immediately exit gitleaks
18 | stopChan := make(chan os.Signal, 1)
19 | signal.Notify(stopChan, os.Interrupt)
20 | go listenForInterrupt(stopChan)
21 |
22 | cmd.Execute()
23 | }
24 |
25 | func listenForInterrupt(stopScan chan os.Signal) {
26 | <-stopScan
27 | log.Fatal().Msg("Interrupt signal received. Exiting...")
28 | }
29 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/kraken.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func KrakenAccessToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "kraken-access-token",
12 | Description: "Kraken Access Token",
13 | Regex: generateSemiGenericRegex([]string{"kraken"},
14 | alphaNumericExtendedLong("80,90")),
15 | SecretGroup: 1,
16 | Keywords: []string{
17 | "kraken",
18 | },
19 | }
20 |
21 | // validate
22 | tps := []string{
23 | generateSampleSecret("kraken",
24 | secrets.NewSecret(alphaNumericExtendedLong("80,90"))),
25 | }
26 | return validate(r, tps, nil)
27 | }
28 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/stripe.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "regexp"
5 |
6 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
7 | "github.com/zricethezav/gitleaks/v8/config"
8 | )
9 |
10 | func StripeAccessToken() *config.Rule {
11 | // define rule
12 | r := config.Rule{
13 | Description: "Stripe Access Token",
14 | RuleID: "stripe-access-token",
15 | Regex: regexp.MustCompile(`(?i)(sk|pk)_(test|live)_[0-9a-z]{10,32}`),
16 | Keywords: []string{
17 | "sk_test",
18 | "pk_test",
19 | "sk_live",
20 | "pk_live",
21 | },
22 | }
23 |
24 | // validate
25 | tps := []string{"stripeToken := \"sk_test_" + secrets.NewSecret(alphaNumeric("30")) + "\""}
26 | return validate(r, tps, nil)
27 | }
28 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: enhancement
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
22 | cc @zricethezav
23 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/openai.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func OpenAI() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "openai-api-key",
12 | Description: "OpenAI API Key",
13 | Regex: generateUniqueTokenRegex(`sk-[a-zA-Z0-9]{20}T3BlbkFJ[a-zA-Z0-9]{20}`),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "T3BlbkFJ",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("openaiApiKey", "sk-"+secrets.NewSecret(alphaNumeric("20"))+"T3BlbkFJ"+secrets.NewSecret(alphaNumeric("20"))),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/coinbase.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func CoinbaseAccessToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "coinbase-access-token",
12 | Description: "Coinbase Access Token",
13 | Regex: generateSemiGenericRegex([]string{"coinbase"},
14 | alphaNumericExtendedShort("64")),
15 | SecretGroup: 1,
16 | Keywords: []string{
17 | "coinbase",
18 | },
19 | }
20 |
21 | // validate
22 | tps := []string{
23 | generateSampleSecret("coinbase",
24 | secrets.NewSecret(alphaNumericExtendedShort("64"))),
25 | }
26 | return validate(r, tps, nil)
27 | }
28 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/gocardless.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func GoCardless() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "gocardless-api-token",
12 | Description: "GoCardless API token",
13 | Regex: generateSemiGenericRegex([]string{"gocardless"}, `live_(?i)[a-z0-9\-_=]{40}`),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "live_",
17 | "gocardless",
18 | },
19 | }
20 |
21 | // validate
22 | tps := []string{
23 | generateSampleSecret("gocardless", "live_"+secrets.NewSecret(alphaNumericExtended("40"))),
24 | }
25 | return validate(r, tps, nil)
26 | }
27 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/rapidapi.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func RapidAPIAccessToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "rapidapi-access-token",
12 | Description: "RapidAPI Access Token",
13 | Regex: generateSemiGenericRegex([]string{"rapidapi"},
14 | alphaNumericExtendedShort("50")),
15 | SecretGroup: 1,
16 | Keywords: []string{
17 | "rapidapi",
18 | },
19 | }
20 |
21 | // validate
22 | tps := []string{
23 | generateSampleSecret("rapidapi",
24 | secrets.NewSecret(alphaNumericExtendedShort("50"))),
25 | }
26 | return validate(r, tps, nil)
27 | }
28 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/launchdarkly.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func LaunchDarklyAccessToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "launchdarkly-access-token",
12 | Description: "Launchdarkly Access Token",
13 | Regex: generateSemiGenericRegex([]string{"launchdarkly"}, alphaNumericExtended("40")),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "launchdarkly",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("launchdarkly", secrets.NewSecret(alphaNumericExtended("40"))),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/sendinblue.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func SendInBlueAPIToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "sendinblue-api-token",
12 | Description: "Sendinblue API token",
13 | Regex: generateUniqueTokenRegex(`xkeysib-[a-f0-9]{64}\-(?i)[a-z0-9]{16}`),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "xkeysib-",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("sendinblue", "xkeysib-"+secrets.NewSecret(hex("64"))+"-"+secrets.NewSecret(alphaNumeric("16"))),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/hashicorp.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "regexp"
5 |
6 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
7 | "github.com/zricethezav/gitleaks/v8/config"
8 | )
9 |
10 | func Hashicorp() *config.Rule {
11 | // define rule
12 | r := config.Rule{
13 | Description: "HashiCorp Terraform user/org API token",
14 | RuleID: "hashicorp-tf-api-token",
15 | Regex: regexp.MustCompile(`(?i)[a-z0-9]{14}\.atlasv1\.[a-z0-9\-_=]{60,70}`),
16 | Keywords: []string{"atlasv1"},
17 | }
18 |
19 | // validate
20 | tps := []string{
21 | generateSampleSecret("hashicorpToken", secrets.NewSecret(hex("14"))+".atlasv1."+secrets.NewSecret(alphaNumericExtended("60,70"))),
22 | }
23 | return validate(r, tps, nil)
24 | }
25 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/doppler.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "regexp"
5 |
6 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
7 | "github.com/zricethezav/gitleaks/v8/config"
8 | )
9 |
10 | func Doppler() *config.Rule {
11 | // define rule
12 | r := config.Rule{
13 | Description: "Doppler API token",
14 | RuleID: "doppler-api-token",
15 | Regex: regexp.MustCompile(`(dp\.pt\.)(?i)[a-z0-9]{43}`),
16 | Keywords: []string{"doppler"},
17 | }
18 |
19 | // validate
20 | tps := []string{
21 | generateSampleSecret("doppler", "dp.pt."+secrets.NewSecret(alphaNumeric("43"))),
22 | }
23 | return validate(r, tps, nil)
24 | }
25 |
26 | // TODO add additional doppler formats:
27 | // https://docs.doppler.com/reference/auth-token-formats
28 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/shippo.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func ShippoAPIToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "shippo-api-token",
12 | Description: "Shippo API token",
13 | Regex: generateUniqueTokenRegex(`shippo_(live|test)_[a-f0-9]{40}`),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "shippo_",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("shippo", "shippo_live_"+secrets.NewSecret(hex("40"))),
23 | generateSampleSecret("shippo", "shippo_test_"+secrets.NewSecret(hex("40"))),
24 | }
25 | return validate(r, tps, nil)
26 | }
27 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/nytimes.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func NytimesAccessToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "nytimes-access-token",
12 | Description: "Nytimes Access Token",
13 | Regex: generateSemiGenericRegex([]string{
14 | "nytimes", "new-york-times,", "newyorktimes"},
15 | alphaNumericExtended("32")),
16 | SecretGroup: 1,
17 | Keywords: []string{
18 | "nytimes",
19 | "new-york-times",
20 | "newyorktimes",
21 | },
22 | }
23 |
24 | // validate
25 | tps := []string{
26 | generateSampleSecret("nytimes", secrets.NewSecret(alphaNumeric("32"))),
27 | }
28 | return validate(r, tps, nil)
29 | }
30 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/atlassian.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func Atlassian() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | Description: "Atlassian API token",
12 | RuleID: "atlassian-api-token",
13 | Regex: generateSemiGenericRegex([]string{
14 | "atlassian", "confluence", "jira"}, alphaNumeric("24")),
15 | SecretGroup: 1,
16 | Keywords: []string{"atlassian", "confluence", "jira"},
17 | }
18 |
19 | // validate
20 | tps := []string{
21 | generateSampleSecret("atlassian", secrets.NewSecret(alphaNumeric("24"))),
22 | generateSampleSecret("confluence", secrets.NewSecret(alphaNumeric("24"))),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
--------------------------------------------------------------------------------
/report/report.go:
--------------------------------------------------------------------------------
1 | package report
2 |
3 | import (
4 | "os"
5 | "strings"
6 |
7 | "github.com/zricethezav/gitleaks/v8/config"
8 | )
9 |
10 | const (
11 | // https://cwe.mitre.org/data/definitions/798.html
12 | CWE = "CWE-798"
13 | CWE_DESCRIPTION = "Use of Hard-coded Credentials"
14 | )
15 |
16 | func Write(findings []Finding, cfg config.Config, ext string, reportPath string) error {
17 | file, err := os.Create(reportPath)
18 | if err != nil {
19 | return err
20 | }
21 | ext = strings.ToLower(ext)
22 | switch ext {
23 | case ".json", "json":
24 | err = writeJson(findings, file)
25 | case ".csv", "csv":
26 | err = writeCsv(findings, file)
27 | case ".xml", "junit":
28 | err = writeJunit(findings, file)
29 | case ".sarif", "sarif":
30 | err = writeSarif(cfg, findings, file)
31 | }
32 |
33 | return err
34 | }
35 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/privatekey.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "regexp"
5 |
6 | "github.com/zricethezav/gitleaks/v8/config"
7 | )
8 |
9 | func PrivateKey() *config.Rule {
10 | // define rule
11 | r := config.Rule{
12 | Description: "Private Key",
13 | RuleID: "private-key",
14 | Regex: regexp.MustCompile(`(?i)-----BEGIN[ A-Z0-9_-]{0,100}PRIVATE KEY( BLOCK)?-----[\s\S-]*KEY( BLOCK)?----`),
15 | Keywords: []string{"-----BEGIN"},
16 | }
17 |
18 | // validate
19 | tps := []string{`-----BEGIN PRIVATE KEY-----
20 | anything
21 | -----END PRIVATE KEY-----`,
22 | `-----BEGIN RSA PRIVATE KEY-----
23 | abcdefghijklmnopqrstuvwxyz
24 | -----END RSA PRIVATE KEY-----
25 | `,
26 | `-----BEGIN PRIVATE KEY BLOCK-----
27 | anything
28 | -----END PRIVATE KEY BLOCK-----`,
29 | } // gitleaks:allow
30 | return validate(r, tps, nil)
31 | }
32 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: bug
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 |
16 | **Expected behavior**
17 | A clear and concise description of what you expected to happen.
18 |
19 | **Screenshots**
20 | If applicable, add screenshots to help explain your problem.
21 |
22 | **Basic Info (please complete the following information):**
23 | - OS:
24 | - Gitleaks Version:
25 |
26 | **Additional context**
27 | Add any other context about the problem here.
28 |
29 | cc @zricethezav
30 |
31 |
38 |
--------------------------------------------------------------------------------
/scripts/pre-commit.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | """Helper script to be used as a pre-commit hook."""
3 | import os
4 | import sys
5 | import subprocess
6 |
7 |
8 | def gitleaksEnabled():
9 | """Determine if the pre-commit hook for gitleaks is enabled."""
10 | out = subprocess.getoutput("git config --bool hooks.gitleaks")
11 | if out == "false":
12 | return False
13 | return True
14 |
15 |
16 | if gitleaksEnabled():
17 | exitCode = os.WEXITSTATUS(os.system('gitleaks protect -v --staged'))
18 | if exitCode == 1:
19 | print('''Warning: gitleaks has detected sensitive information in your changes.
20 | To disable the gitleaks precommit hook run the following command:
21 |
22 | git config hooks.gitleaks false
23 | ''')
24 | sys.exit(1)
25 | else:
26 | print('gitleaks precommit disabled\
27 | (enable with `git config hooks.gitleaks true`)')
28 |
--------------------------------------------------------------------------------
/testdata/config/generic_with_py_path.toml:
--------------------------------------------------------------------------------
1 | title = "gitleaks config"
2 |
3 | [[rules]]
4 | description = "Generic API Key"
5 | id = "generic-api-key"
6 | regex = '''(?i)((key|api|token|secret|password)[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([0-9a-zA-Z\-_=]{8,64})['\"]'''
7 | path = '''.py'''
8 | entropy = 3.7
9 | secretGroup = 4
10 |
11 | [allowlist]
12 | description = "global allow lists"
13 | regexes = [
14 | '''219-09-9999''',
15 | '''078-05-1120''',
16 | '''(9[0-9]{2}|666)-\d{2}-\d{4}''',
17 | '''process''',
18 | '''getenv''',
19 | '''\.env''',
20 | '''env\(''',
21 | '''env\.''',
22 | '''setting''',
23 | '''load''',
24 | '''token''',
25 | '''password''',
26 | '''secret''',
27 | '''api\_key''',
28 | '''apikey''',
29 | '''api\-key''',
30 | ]
31 | paths = [
32 | '''gitleaks.toml''',
33 | '''(.*?)(jpg|gif|doc|pdf|bin|svg|socket)$''',
34 | '''(go.mod|go.sum)$'''
35 | ]
36 |
37 |
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/logs/refs/heads/main:
--------------------------------------------------------------------------------
1 | 0000000000000000000000000000000000000000 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 Zach Rice 1635896329 -0500 clone: from github.com:gitleaks/test.git
2 | 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 2e1db472eeba53f06c4026ae4566ea022e36598e Zach Rice 1635896648 -0500 pull origin main: Fast-forward
3 | 2e1db472eeba53f06c4026ae4566ea022e36598e 4f77f1b3cc39d4b17e4cf4ba0a38f5daed9875b4 Richard Gomez 1681920523 -0400 commit: add .gitleaksignore test
4 | 4f77f1b3cc39d4b17e4cf4ba0a38f5daed9875b4 cada78a9bf157ec05573f19e682d211f811c2e2d Richard Gomez 1681920658 -0400 commit (amend): add .gitleaksignore test
5 | cada78a9bf157ec05573f19e682d211f811c2e2d 2e1db472eeba53f06c4026ae4566ea022e36598e Richard Gomez 1681920730 -0400 reset: moving to HEAD~
6 | 2e1db472eeba53f06c4026ae4566ea022e36598e 53cd7a3c6eb4937f413e3c25e4a9f39289afa69e Richard Gomez 1681920759 -0400 commit: add .gitleaksignore test files
7 |
--------------------------------------------------------------------------------
/USERS.md:
--------------------------------------------------------------------------------
1 | ## Who uses Gitleaks?
2 |
3 | As the Gitleaks Community grows, we'd like to keep a list of our users.
4 |
5 | Here's a running list of some organizations using Gitleaks[^1]:
6 |
7 | 1. [GitLab](https://docs.gitlab.com/ee/user/application_security/secret_detection/)
8 | 1. [Gitleaks](https://gitleaks.io)
9 | 1. [GoReleaser](https://goreleaser.com)
10 | 2. [Trendyol](https://trendyol.com)
11 |
12 | Feel free to [add yours](https://github.com/zricethezav/gitleaks/edit/master/USERS.md)!
13 |
14 |
20 |
21 | [^1]: Entries were either added by the companies themselves or by the maintainers after seeing it in the wild.
22 | You can see all public repositories using Gitleaks or Gitleaks-Action by [searching on GitHub](https://github.com/search?q=gitleaks).
23 |
24 |
27 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/teams.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "regexp"
5 |
6 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
7 | "github.com/zricethezav/gitleaks/v8/config"
8 | )
9 |
10 | func TeamsWebhook() *config.Rule {
11 | // define rule
12 | r := config.Rule{
13 | Description: "Microsoft Teams Webhook",
14 | RuleID: "microsoft-teams-webhook",
15 | Regex: regexp.MustCompile(
16 | `https:\/\/[a-z0-9]+\.webhook\.office\.com\/webhookb2\/[a-z0-9]{8}-([a-z0-9]{4}-){3}[a-z0-9]{12}@[a-z0-9]{8}-([a-z0-9]{4}-){3}[a-z0-9]{12}\/IncomingWebhook\/[a-z0-9]{32}\/[a-z0-9]{8}-([a-z0-9]{4}-){3}[a-z0-9]{12}`),
17 | Keywords: []string{
18 | "webhook.office.com",
19 | "webhookb2",
20 | "IncomingWebhook",
21 | },
22 | }
23 |
24 | // validate
25 | tps := []string{
26 | "https://mycompany.webhook.office.com/webhookb2/" + secrets.NewSecret(`[a-z0-9]{8}-([a-z0-9]{4}-){3}[a-z0-9]{12}@[a-z0-9]{8}-([a-z0-9]{4}-){3}[a-z0-9]{12}\/IncomingWebhook\/[a-z0-9]{32}\/[a-z0-9]{8}-([a-z0-9]{4}-){3}[a-z0-9]{12}`), // gitleaks:allow
27 | }
28 | return validate(r, tps, nil)
29 | }
30 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/definednetworking.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func DefinedNetworkingAPIToken() *config.Rule {
9 | // Define Rule
10 | r := config.Rule{
11 | // Human redable description of the rule
12 | Description: "Defined Networking API token",
13 |
14 | // Unique ID for the rule
15 | RuleID: "defined-networking-api-token",
16 |
17 | // Regex capture group for the actual secret
18 | SecretGroup: 1,
19 |
20 | // Regex used for detecting secrets. See regex section below for more details
21 | Regex: generateSemiGenericRegex([]string{"dnkey"}, `dnkey-[a-z0-9=_\-]{26}-[a-z0-9=_\-]{52}`),
22 |
23 | // Keywords used for string matching on fragments (think of this as a prefilter)
24 | Keywords: []string{"dnkey"},
25 | }
26 |
27 | // validate
28 | tps := []string{
29 | generateSampleSecret("dnkey", "dnkey-"+secrets.NewSecret(alphaNumericExtended("26"))+"-"+secrets.NewSecret(alphaNumericExtended("52"))),
30 | }
31 | return validate(r, tps, nil)
32 | }
33 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/adobe.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func AdobeClientID() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | Description: "Adobe Client ID (OAuth Web)",
12 | RuleID: "adobe-client-id",
13 | Regex: generateSemiGenericRegex([]string{"adobe"}, hex("32")),
14 | SecretGroup: 1,
15 | Keywords: []string{"adobe"},
16 | }
17 |
18 | // validate
19 | tps := []string{
20 | generateSampleSecret("adobe", secrets.NewSecret(hex("32"))),
21 | }
22 | return validate(r, tps, nil)
23 | }
24 |
25 | func AdobeClientSecret() *config.Rule {
26 | // define rule
27 | r := config.Rule{
28 | Description: "Adobe Client Secret",
29 | RuleID: "adobe-client-secret",
30 | Regex: generateUniqueTokenRegex(`(p8e-)(?i)[a-z0-9]{32}`),
31 | Keywords: []string{"p8e-"},
32 | }
33 |
34 | // validate
35 | tps := []string{
36 | "adobeClient := \"p8e-" + secrets.NewSecret(hex("32")) + "\"",
37 | }
38 | return validate(r, tps, nil)
39 | }
40 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/easypost.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "regexp"
5 |
6 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
7 | "github.com/zricethezav/gitleaks/v8/config"
8 | )
9 |
10 | func EasyPost() *config.Rule {
11 | // define rule
12 | r := config.Rule{
13 | Description: "EasyPost API token",
14 | RuleID: "easypost-api-token",
15 | Regex: regexp.MustCompile(`\bEZAK(?i)[a-z0-9]{54}`),
16 | Keywords: []string{"EZAK"},
17 | }
18 |
19 | // validate
20 | tps := []string{
21 | generateSampleSecret("EZAK", "EZAK"+secrets.NewSecret(alphaNumeric("54"))),
22 | }
23 | return validate(r, tps, nil)
24 | }
25 |
26 | func EasyPostTestAPI() *config.Rule {
27 | // define rule
28 | r := config.Rule{
29 | Description: "EasyPost test API token",
30 | RuleID: "easypost-test-api-token",
31 | Regex: regexp.MustCompile(`\bEZTK(?i)[a-z0-9]{54}`),
32 | Keywords: []string{"EZTK"},
33 | }
34 |
35 | // validate
36 | tps := []string{
37 | generateSampleSecret("EZTK", "EZTK"+secrets.NewSecret(alphaNumeric("54"))),
38 | }
39 | return validate(r, tps, nil)
40 | }
41 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/square.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func SquareAccessToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "square-access-token",
12 | Description: "Square Access Token",
13 | Regex: generateUniqueTokenRegex(`sq0atp-[0-9A-Za-z\-_]{22}`),
14 | Keywords: []string{"sq0atp-"},
15 | }
16 |
17 | // validate
18 | tps := []string{
19 | generateSampleSecret("square", secrets.NewSecret(`sq0atp-[0-9A-Za-z\-_]{22}`)),
20 | }
21 | return validate(r, tps, nil)
22 | }
23 |
24 | func SquareSecret() *config.Rule {
25 | // define rule
26 | r := config.Rule{
27 | RuleID: "square-secret",
28 | Description: "Square Secret",
29 | Regex: generateUniqueTokenRegex(`sq0csp-[0-9A-Za-z\\-_]{43}`),
30 | Keywords: []string{"sq0csp-"},
31 | }
32 |
33 | // validate
34 | tps := []string{
35 | generateSampleSecret("square", secrets.NewSecret(`sq0csp-[0-9A-Za-z\\-_]{43}`)),
36 | }
37 | return validate(r, tps, nil)
38 | }
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Zachary Rice
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/vault.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func VaultServiceToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | Description: "Vault Service Token",
12 | RuleID: "vault-service-token",
13 | Regex: generateUniqueTokenRegex(`hvs\.[a-z0-9_-]{90,100}`),
14 | Keywords: []string{"hvs"},
15 | }
16 |
17 | // validate
18 | tps := []string{
19 | generateSampleSecret("vault", "hvs."+secrets.NewSecret(alphaNumericExtendedShort("90"))),
20 | }
21 | return validate(r, tps, nil)
22 | }
23 |
24 | func VaultBatchToken() *config.Rule {
25 | // define rule
26 | r := config.Rule{
27 | Description: "Vault Batch Token",
28 | RuleID: "vault-batch-token",
29 | Regex: generateUniqueTokenRegex(`hvb\.[a-z0-9_-]{138,212}`),
30 | Keywords: []string{"hvb"},
31 | }
32 |
33 | // validate
34 | tps := []string{
35 | generateSampleSecret("vault", "hvb."+secrets.NewSecret(alphaNumericExtendedShort("138"))),
36 | }
37 | return validate(r, tps, nil)
38 | }
39 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/linear.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "regexp"
5 |
6 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
7 | "github.com/zricethezav/gitleaks/v8/config"
8 | )
9 |
10 | func LinearAPIToken() *config.Rule {
11 | // define rule
12 | r := config.Rule{
13 | Description: "Linear API Token",
14 | RuleID: "linear-api-key",
15 | Regex: regexp.MustCompile(`lin_api_(?i)[a-z0-9]{40}`),
16 | Keywords: []string{"lin_api_"},
17 | }
18 |
19 | // validate
20 | tps := []string{
21 | generateSampleSecret("linear", "lin_api_"+secrets.NewSecret(alphaNumeric("40"))),
22 | }
23 | return validate(r, tps, nil)
24 | }
25 |
26 | func LinearClientSecret() *config.Rule {
27 | // define rule
28 | r := config.Rule{
29 | Description: "Linear Client Secret",
30 | RuleID: "linear-client-secret",
31 | Regex: generateSemiGenericRegex([]string{"linear"}, hex("32")),
32 | Keywords: []string{"linear"},
33 | SecretGroup: 1,
34 | }
35 |
36 | // validate
37 | tps := []string{
38 | generateSampleSecret("linear", secrets.NewSecret(hex("32"))),
39 | }
40 | return validate(r, tps, nil)
41 | }
42 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/alibaba.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func AlibabaAccessKey() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | Description: "Alibaba AccessKey ID",
12 | RuleID: "alibaba-access-key-id",
13 | Regex: generateUniqueTokenRegex(`(LTAI)(?i)[a-z0-9]{20}`),
14 | Keywords: []string{"LTAI"},
15 | }
16 |
17 | // validate
18 | tps := []string{
19 | "alibabaKey := \"LTAI" + secrets.NewSecret(hex("20")) + "\"",
20 | }
21 | return validate(r, tps, nil)
22 | }
23 |
24 | // TODO
25 | func AlibabaSecretKey() *config.Rule {
26 | // define rule
27 | r := config.Rule{
28 | Description: "Alibaba Secret Key",
29 | RuleID: "alibaba-secret-key",
30 | Regex: generateSemiGenericRegex([]string{"alibaba"},
31 | alphaNumeric("30")),
32 | SecretGroup: 1,
33 | Keywords: []string{"alibaba"},
34 | }
35 |
36 | // validate
37 | tps := []string{
38 | generateSampleSecret("alibaba", secrets.NewSecret(alphaNumeric("30"))),
39 | }
40 | return validate(r, tps, nil)
41 | }
42 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/asana.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func AsanaClientID() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | Description: "Asana Client ID",
12 | RuleID: "asana-client-id",
13 | Regex: generateSemiGenericRegex([]string{"asana"}, numeric("16")),
14 | SecretGroup: 1,
15 | Keywords: []string{"asana"},
16 | }
17 |
18 | // validate
19 | tps := []string{
20 | generateSampleSecret("asana", secrets.NewSecret(numeric("16"))),
21 | }
22 | return validate(r, tps, nil)
23 | }
24 |
25 | func AsanaClientSecret() *config.Rule {
26 | // define rule
27 | r := config.Rule{
28 | Description: "Asana Client Secret",
29 | RuleID: "asana-client-secret",
30 | Regex: generateSemiGenericRegex([]string{"asana"}, alphaNumeric("32")),
31 | SecretGroup: 1,
32 | Keywords: []string{"asana"},
33 | }
34 |
35 | // validate
36 | tps := []string{
37 | generateSampleSecret("asana", secrets.NewSecret(alphaNumeric("32"))),
38 | }
39 | return validate(r, tps, nil)
40 | }
41 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/bittrex.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func BittrexAccessKey() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | Description: "Bittrex Access Key",
12 | RuleID: "bittrex-access-key",
13 | Regex: generateSemiGenericRegex([]string{"bittrex"}, alphaNumeric("32")),
14 | SecretGroup: 1,
15 | Keywords: []string{"bittrex"},
16 | }
17 |
18 | // validate
19 | tps := []string{
20 | generateSampleSecret("bittrex", secrets.NewSecret(alphaNumeric("32"))),
21 | }
22 | return validate(r, tps, nil)
23 | }
24 |
25 | func BittrexSecretKey() *config.Rule {
26 | // define rule
27 | r := config.Rule{
28 | Description: "Bittrex Secret Key",
29 | RuleID: "bittrex-secret-key",
30 | Regex: generateSemiGenericRegex([]string{"bittrex"}, alphaNumeric("32")),
31 | SecretGroup: 1,
32 | Keywords: []string{"bittrex"},
33 | }
34 |
35 | // validate
36 | tps := []string{
37 | generateSampleSecret("bittrex", secrets.NewSecret(alphaNumeric("32"))),
38 | }
39 | return validate(r, tps, nil)
40 | }
41 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/finicity.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func FinicityClientSecret() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | Description: "Finicity Client Secret",
12 | RuleID: "finicity-client-secret",
13 | Regex: generateSemiGenericRegex([]string{"finicity"}, alphaNumeric("20")),
14 | SecretGroup: 1,
15 | Keywords: []string{"finicity"},
16 | }
17 |
18 | // validate
19 | tps := []string{
20 | generateSampleSecret("finicity", secrets.NewSecret(alphaNumeric("20"))),
21 | }
22 | return validate(r, tps, nil)
23 | }
24 |
25 | func FinicityAPIToken() *config.Rule {
26 | // define rule
27 | r := config.Rule{
28 | Description: "Finicity API token",
29 | RuleID: "finicity-api-token",
30 | Regex: generateSemiGenericRegex([]string{"finicity"}, hex("32")),
31 | SecretGroup: 1,
32 | Keywords: []string{"finicity"},
33 | }
34 |
35 | // validate
36 | tps := []string{
37 | generateSampleSecret("finicity", secrets.NewSecret(hex("32"))),
38 | }
39 | return validate(r, tps, nil)
40 | }
41 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/gcp.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "regexp"
5 |
6 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
7 | "github.com/zricethezav/gitleaks/v8/config"
8 | )
9 |
10 | // TODO this one could probably use some work
11 | func GCPServiceAccount() *config.Rule {
12 | // define rule
13 | r := config.Rule{
14 | Description: "Google (GCP) Service-account",
15 | RuleID: "gcp-service-account",
16 | Regex: regexp.MustCompile(`\"type\": \"service_account\"`),
17 | Keywords: []string{`\"type\": \"service_account\"`},
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | `"type": "service_account"`,
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
27 | func GCPAPIKey() *config.Rule {
28 | // define rule
29 | r := config.Rule{
30 | RuleID: "gcp-api-key",
31 | Description: "GCP API key",
32 | Regex: generateUniqueTokenRegex(`AIza[0-9A-Za-z\\-_]{35}`),
33 | SecretGroup: 1,
34 | Keywords: []string{
35 | "AIza",
36 | },
37 | }
38 |
39 | // validate
40 | tps := []string{
41 | generateSampleSecret("gcp", secrets.NewSecret(`AIza[0-9A-Za-z\\-_]{35}`)),
42 | }
43 | return validate(r, tps, nil)
44 | }
45 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/kucoin.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func KucoinAccessToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "kucoin-access-token",
12 | Description: "Kucoin Access Token",
13 | Regex: generateSemiGenericRegex([]string{"kucoin"}, hex("24")),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "kucoin",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("kucoin", secrets.NewSecret(hex("24"))),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
27 | func KucoinSecretKey() *config.Rule {
28 | // define rule
29 | r := config.Rule{
30 | RuleID: "kucoin-secret-key",
31 | Description: "Kucoin Secret Key",
32 | Regex: generateSemiGenericRegex([]string{"kucoin"}, hex8_4_4_4_12()),
33 | SecretGroup: 1,
34 | Keywords: []string{
35 | "kucoin",
36 | },
37 | }
38 |
39 | // validate
40 | tps := []string{
41 | generateSampleSecret("kucoin", secrets.NewSecret(hex8_4_4_4_12())),
42 | }
43 | return validate(r, tps, nil)
44 | }
45 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/snyk.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/config"
5 | )
6 |
7 | func Snyk() *config.Rule {
8 | // define rule
9 | r := config.Rule{
10 | Description: "Snyk API token",
11 | RuleID: "snyk-api-token",
12 | SecretGroup: 1,
13 | Regex: generateSemiGenericRegex([]string{"snyk"}, hex8_4_4_4_12()),
14 | Keywords: []string{"snyk"},
15 | }
16 |
17 | // validate
18 | tps := []string{
19 | `const SNYK_TOKEN = "12345678-ABCD-ABCD-ABCD-1234567890AB"`, // gitleaks:allow
20 | `const SNYK_KEY = "12345678-ABCD-ABCD-ABCD-1234567890AB"`, // gitleaks:allow
21 | `const SNYK = "12345678-ABCD-ABCD-ABCD-1234567890AB"`, // gitleaks:allow
22 | `SNYK = "12345678-ABCD-ABCD-ABCD-1234567890AB"`, // gitleaks:allow
23 | `SNYK_TOKEN := "12345678-ABCD-ABCD-ABCD-1234567890AB"`, // gitleaks:allow
24 | `SNYK_TOKEN ::= "12345678-ABCD-ABCD-ABCD-1234567890AB"`, // gitleaks:allow
25 | `SNYK_TOKEN :::= "12345678-ABCD-ABCD-ABCD-1234567890AB"`, // gitleaks:allow
26 | `SNYK_TOKEN ?= "12345678-ABCD-ABCD-ABCD-1234567890AB"`, // gitleaks:allow
27 | }
28 | return validate(r, tps, nil)
29 | }
30 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/authress.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
7 | "github.com/zricethezav/gitleaks/v8/config"
8 | )
9 |
10 | func Authress() *config.Rule {
11 | // define rule
12 | r := config.Rule{
13 | Description: "Authress Service Client Access Key",
14 | RuleID: "authress-service-client-access-key",
15 | SecretGroup: 1,
16 | Regex: generateUniqueTokenRegex(`(?: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}`),
17 | Keywords: []string{"sc_", "ext_", "scauth_", "authress_"},
18 | }
19 |
20 | // validate
21 | // https://authress.io/knowledge-base/docs/authorization/service-clients/secrets-scanning/#1-detection
22 | service_client_id := "sc_" + alphaNumeric("10")
23 | access_key_id := alphaNumeric("4")
24 | account_id := "acc_" + alphaNumeric("10")
25 | signature_key := alphaNumericExtendedShort("40")
26 |
27 | tps := []string{
28 | generateSampleSecret("authress", secrets.NewSecret(fmt.Sprintf(`%s\.%s\.%s\.%s`, service_client_id, access_key_id, account_id, signature_key))),
29 | }
30 | return validate(r, tps, nil)
31 | }
32 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/sendbird.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func SendbirdAccessToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "sendbird-access-token",
12 | Description: "Sendbird Access Token",
13 | Regex: generateSemiGenericRegex([]string{"sendbird"}, hex("40")),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "sendbird",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("sendbird", secrets.NewSecret(hex("40"))),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
27 | func SendbirdAccessID() *config.Rule {
28 | // define rule
29 | r := config.Rule{
30 | RuleID: "sendbird-access-id",
31 | Description: "Sendbird Access ID",
32 | Regex: generateSemiGenericRegex([]string{"sendbird"}, hex8_4_4_4_12()),
33 | SecretGroup: 1,
34 | Keywords: []string{
35 | "sendbird",
36 | },
37 | }
38 |
39 | // validate
40 | tps := []string{
41 | generateSampleSecret("sendbird", secrets.NewSecret(hex8_4_4_4_12())),
42 | }
43 | return validate(r, tps, nil)
44 | }
45 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/sumologic.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func SumoLogicAccessID() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "sumologic-access-id",
12 | Description: "SumoLogic Access ID",
13 | Regex: generateSemiGenericRegex([]string{"sumo"},
14 | alphaNumeric("14")),
15 | SecretGroup: 1,
16 | Keywords: []string{
17 | "sumo",
18 | },
19 | }
20 |
21 | // validate
22 | tps := []string{
23 | generateSampleSecret("sumo", secrets.NewSecret(alphaNumeric("14"))),
24 | }
25 | return validate(r, tps, nil)
26 | }
27 |
28 | func SumoLogicAccessToken() *config.Rule {
29 | // define rule
30 | r := config.Rule{
31 | RuleID: "sumologic-access-token",
32 | Description: "SumoLogic Access Token",
33 | Regex: generateSemiGenericRegex([]string{"sumo"},
34 | alphaNumeric("64")),
35 | SecretGroup: 1,
36 | Keywords: []string{
37 | "sumo",
38 | },
39 | }
40 |
41 | // validate
42 | tps := []string{
43 | generateSampleSecret("sumo", secrets.NewSecret(alphaNumeric("64"))),
44 | }
45 | return validate(r, tps, nil)
46 | }
47 |
--------------------------------------------------------------------------------
/report/finding.go:
--------------------------------------------------------------------------------
1 | package report
2 |
3 | import (
4 | "strings"
5 | )
6 |
7 | // Finding contains information about strings that
8 | // have been captured by a tree-sitter query.
9 | type Finding struct {
10 | Description string
11 | StartLine int
12 | EndLine int
13 | StartColumn int
14 | EndColumn int
15 |
16 | Line string `json:"-"`
17 |
18 | Match string
19 |
20 | // Secret contains the full content of what is matched in
21 | // the tree-sitter query.
22 | Secret string
23 |
24 | // File is the name of the file containing the finding
25 | File string
26 | SymlinkFile string
27 | Commit string
28 |
29 | // Entropy is the shannon entropy of Value
30 | Entropy float32
31 |
32 | Author string
33 | Email string
34 | Date string
35 | Message string
36 | Tags []string
37 |
38 | // Rule is the name of the rule that was matched
39 | RuleID string
40 |
41 | // unique identifier
42 | Fingerprint string
43 | }
44 |
45 | // Redact removes sensitive information from a finding.
46 | func (f *Finding) Redact() {
47 | f.Line = strings.Replace(f.Line, f.Secret, "REDACTED", -1)
48 | f.Match = strings.Replace(f.Match, f.Secret, "REDACTED", -1)
49 | f.Secret = "REDACTED"
50 | }
51 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/bitbucket.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func BitBucketClientID() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | Description: "Bitbucket Client ID",
12 | RuleID: "bitbucket-client-id",
13 | Regex: generateSemiGenericRegex([]string{"bitbucket"}, alphaNumeric("32")),
14 | SecretGroup: 1,
15 | Keywords: []string{"bitbucket"},
16 | }
17 |
18 | // validate
19 | tps := []string{
20 | generateSampleSecret("bitbucket", secrets.NewSecret(alphaNumeric("32"))),
21 | }
22 | return validate(r, tps, nil)
23 | }
24 |
25 | func BitBucketClientSecret() *config.Rule {
26 | // define rule
27 | r := config.Rule{
28 | Description: "Bitbucket Client Secret",
29 | RuleID: "bitbucket-client-secret",
30 | Regex: generateSemiGenericRegex([]string{"bitbucket"}, alphaNumericExtended("64")),
31 | SecretGroup: 1,
32 | Keywords: []string{"bitbucket"},
33 | }
34 |
35 | // validate
36 | tps := []string{
37 | generateSampleSecret("bitbucket", secrets.NewSecret(alphaNumeric("64"))),
38 | }
39 | return validate(r, tps, nil)
40 | }
41 |
--------------------------------------------------------------------------------
/report/csv.go:
--------------------------------------------------------------------------------
1 | package report
2 |
3 | import (
4 | "encoding/csv"
5 | "io"
6 | "strconv"
7 | "strings"
8 | )
9 |
10 | // writeCsv writes the list of findings to a writeCloser.
11 | func writeCsv(f []Finding, w io.WriteCloser) error {
12 | if len(f) == 0 {
13 | return nil
14 | }
15 | defer w.Close()
16 | cw := csv.NewWriter(w)
17 | err := cw.Write([]string{"RuleID",
18 | "Commit",
19 | "File",
20 | "SymlinkFile",
21 | "Secret",
22 | "Match",
23 | "StartLine",
24 | "EndLine",
25 | "StartColumn",
26 | "EndColumn",
27 | "Author",
28 | "Message",
29 | "Date",
30 | "Email",
31 | "Fingerprint",
32 | "Tags",
33 | })
34 | if err != nil {
35 | return err
36 | }
37 | for _, f := range f {
38 | err = cw.Write([]string{f.RuleID,
39 | f.Commit,
40 | f.File,
41 | f.SymlinkFile,
42 | f.Secret,
43 | f.Match,
44 | strconv.Itoa(f.StartLine),
45 | strconv.Itoa(f.EndLine),
46 | strconv.Itoa(f.StartColumn),
47 | strconv.Itoa(f.EndColumn),
48 | f.Author,
49 | f.Message,
50 | f.Date,
51 | f.Email,
52 | f.Fingerprint,
53 | strings.Join(f.Tags, " "),
54 | })
55 | if err != nil {
56 | return err
57 | }
58 | }
59 |
60 | cw.Flush()
61 | return cw.Error()
62 | }
63 |
--------------------------------------------------------------------------------
/testdata/expected/git/small.txt:
--------------------------------------------------------------------------------
1 | import (
2 | "fmt"
3 | "os"
4 | )
5 | // seems safer
6 | aws_token := os.Getenv("AWS_TOKEN")
7 | package foo
8 |
9 | import "fmt"
10 |
11 | func Foo() {
12 | fmt.Println("foo")
13 |
14 | // seems safe
15 | aws_token := "AKIALALEMEL33243OLIA"
16 | fmt.Println(aws_token)
17 | }
18 | package api
19 |
20 | import "fmt"
21 |
22 | func PrintHello() {
23 | fmt.Println("hello")
24 | }
25 | import (
26 | "fmt"
27 | "os"
28 | )
29 | var a = "initial"
30 | fmt.Println(a)
31 | var b, c int = 1, 2
32 | fmt.Println(b, c)
33 | var d = true
34 | fmt.Println(d)
35 | var e int
36 | fmt.Println(e)
37 | // load secret via env
38 | awsToken := os.Getenv("AWS_TOKEN")
39 |
40 | f := "apple"
41 | fmt.Println(f)
42 |
43 | // opps I added a secret at line 20
44 | awsToken := "AKIALALEMEL33243OLIA"
45 | package main
46 |
47 | import "fmt"
48 |
49 | func main() {
50 |
51 | var a = "initial"
52 | fmt.Println(a)
53 |
54 | var b, c int = 1, 2
55 | fmt.Println(b, c)
56 |
57 | var d = true
58 | fmt.Println(d)
59 |
60 | var e int
61 | fmt.Println(e)
62 |
63 | f := "apple"
64 | fmt.Println(f)
65 | }
66 | # test
67 | This is a repo used for testing gitleaks
68 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/confluent.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func ConfluentSecretKey() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "confluent-secret-key",
12 | Description: "Confluent Secret Key",
13 | Regex: generateSemiGenericRegex([]string{"confluent"}, alphaNumeric("64")),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "confluent",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("confluent", secrets.NewSecret(alphaNumeric("64"))),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
27 | func ConfluentAccessToken() *config.Rule {
28 | // define rule
29 | r := config.Rule{
30 | RuleID: "confluent-access-token",
31 | Description: "Confluent Access Token",
32 | Regex: generateSemiGenericRegex([]string{"confluent"}, alphaNumeric("16")),
33 | SecretGroup: 1,
34 | Keywords: []string{
35 | "confluent",
36 | },
37 | }
38 |
39 | // validate
40 | tps := []string{
41 | generateSampleSecret("confluent", secrets.NewSecret(alphaNumeric("16"))),
42 | }
43 | return validate(r, tps, nil)
44 | }
45 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/lob.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func LobPubAPIToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | Description: "Lob Publishable API Key",
12 | RuleID: "lob-pub-api-key",
13 | Regex: generateSemiGenericRegex([]string{"lob"}, `(test|live)_pub_[a-f0-9]{31}`),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "test_pub",
17 | "live_pub",
18 | "_pub",
19 | },
20 | }
21 |
22 | // validate
23 | tps := []string{
24 | generateSampleSecret("lob", "test_pub_"+secrets.NewSecret(hex("31"))),
25 | }
26 | return validate(r, tps, nil)
27 | }
28 |
29 | func LobAPIToken() *config.Rule {
30 | // define rule
31 | r := config.Rule{
32 | Description: "Lob API Key",
33 | RuleID: "lob-api-key",
34 | Regex: generateSemiGenericRegex([]string{"lob"}, `(live|test)_[a-f0-9]{35}`),
35 | Keywords: []string{
36 | "test_",
37 | "live_",
38 | },
39 | SecretGroup: 1,
40 | }
41 |
42 | // validate
43 | tps := []string{
44 | generateSampleSecret("lob", "test_"+secrets.NewSecret(hex("35"))),
45 | }
46 | return validate(r, tps, nil)
47 | }
48 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/linkedin.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func LinkedinClientSecret() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "linkedin-client-secret",
12 | Description: "LinkedIn Client secret",
13 | Regex: generateSemiGenericRegex([]string{
14 | "linkedin",
15 | "linked-in",
16 | }, alphaNumeric("16")),
17 | SecretGroup: 1,
18 | Keywords: []string{
19 | "linkedin",
20 | "linked-in",
21 | },
22 | }
23 |
24 | // validate
25 | tps := []string{
26 | generateSampleSecret("linkedin", secrets.NewSecret(alphaNumeric("16"))),
27 | }
28 | return validate(r, tps, nil)
29 | }
30 |
31 | func LinkedinClientID() *config.Rule {
32 | // define rule
33 | r := config.Rule{
34 | RuleID: "linkedin-client-id",
35 | Description: "LinkedIn Client ID",
36 | Regex: generateSemiGenericRegex([]string{
37 | "linkedin",
38 | "linked-in",
39 | }, alphaNumeric("14")),
40 | SecretGroup: 1,
41 | Keywords: []string{
42 | "linkedin",
43 | "linked-in",
44 | },
45 | }
46 |
47 | // validate
48 | tps := []string{
49 | generateSampleSecret("linkedin", secrets.NewSecret(alphaNumeric("14"))),
50 | }
51 | return validate(r, tps, nil)
52 | }
53 |
--------------------------------------------------------------------------------
/config/rule.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "regexp"
5 | )
6 |
7 | // Rules contain information that define details on how to detect secrets
8 | type Rule struct {
9 | // Description is the description of the rule.
10 | Description string
11 |
12 | // RuleID is a unique identifier for this rule
13 | RuleID string
14 |
15 | // Entropy is a float representing the minimum shannon
16 | // entropy a regex group must have to be considered a secret.
17 | Entropy float64
18 |
19 | // SecretGroup is an int used to extract secret from regex
20 | // match and used as the group that will have its entropy
21 | // checked if `entropy` is set.
22 | SecretGroup int
23 |
24 | // Regex is a golang regular expression used to detect secrets.
25 | Regex *regexp.Regexp
26 |
27 | // Path is a golang regular expression used to
28 | // filter secrets by path
29 | Path *regexp.Regexp
30 |
31 | // Tags is an array of strings used for metadata
32 | // and reporting purposes.
33 | Tags []string
34 |
35 | // Keywords are used for pre-regex check filtering. Rules that contain
36 | // keywords will perform a quick string compare check to make sure the
37 | // keyword(s) are in the content being scanned.
38 | Keywords []string
39 |
40 | // Allowlist allows a rule to be ignored for specific
41 | // regexes, paths, and/or commits
42 | Allowlist Allowlist
43 | }
44 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/jwt.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/config"
5 | )
6 |
7 | func JWT() *config.Rule {
8 | // define rule
9 | r := config.Rule{
10 | Description: "JSON Web Token",
11 | RuleID: "jwt",
12 | Regex: generateUniqueTokenRegex(`ey[0-9a-z]{30,34}\.ey[0-9a-z-\/_]{30,500}\.[0-9a-zA-Z-\/_]{10,200}={0,2}`),
13 | Keywords: []string{"ey"},
14 | }
15 |
16 | // validate
17 | tps := []string{`eyJhbGciOieeeiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwic3ViZSI6IjEyMzQ1Njc4OTAiLCJuYW1lZWEiOiJKb2huIERvZSIsInN1ZmV3YWZiIjoiMTIzNDU2Nzg5MCIsIm5hbWVmZWF3ZnciOiJKb2huIERvZSIsIm5hbWVhZmV3ZmEiOiJKb2huIERvZSIsInN1ZndhZndlYWIiOiIxMjM0NTY3ODkwIiwibmFtZWZ3YWYiOiJKb2huIERvZSIsInN1YmZ3YWYiOiIxMjM0NTY3ODkwIiwibmFtZndhZSI6IkpvaG4gRG9lIiwiaWZ3YWZhYXQiOjE1MTYyMzkwMjJ9.a_5icKBDo-8EjUlrfvz2k2k-FYaindQ0DEYNrlsnRG0==`, // gitleaks:allow
18 | `JWT := eyJhbGciOieeeiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwic3ViZSI6IjEyMzQ1Njc4OTAiLCJuYW1lZWEiOiJKb2huIERvZSIsInN1ZmV3YWZiIjoiMTIzNDU2Nzg5MCIsIm5hbWVmZWF3ZnciOiJKb2huIERvZSIsIm5hbWVhZmV3ZmEiOiJKb2huIERvZSIsInN1ZndhZndlYWIiOiIxMjM0NTY3ODkwIiwibmFtZWZ3YWYiOiJKb2huIERvZSIsInN1YmZ3YWYiOiIxMjM0NTY3ODkwIiwibmFtZndhZSI6IkpvaG4gRG9lIiwiaWZ3YWZhYXQiOjE1MTYyMzkwMjJ9.a_5icKBDo-8EjUlrfvz2k2k-FYaindQ0DEYNrlsnRG0`, // gitleaks:allow
19 | }
20 | return validate(r, tps, nil)
21 | }
22 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/generic.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/config"
5 | )
6 |
7 | func GenericCredential() *config.Rule {
8 | // define rule
9 | r := config.Rule{
10 | RuleID: "generic-api-key",
11 | Description: "Generic API Key",
12 | Regex: generateSemiGenericRegex([]string{
13 | "key",
14 | "api",
15 | "token",
16 | "secret",
17 | "client",
18 | "passwd",
19 | "password",
20 | "auth",
21 | "access",
22 | }, `[0-9a-z\-_.=]{10,150}`),
23 | SecretGroup: 1,
24 | Keywords: []string{
25 | "key",
26 | "api",
27 | "token",
28 | "secret",
29 | "client",
30 | "passwd",
31 | "password",
32 | "auth",
33 | "access",
34 | },
35 | Entropy: 3.5,
36 | Allowlist: config.Allowlist{
37 | StopWords: DefaultStopWords,
38 | },
39 | }
40 |
41 | // validate
42 | tps := []string{
43 | generateSampleSecret("generic", "CLOJARS_34bf0e88955ff5a1c328d6a7491acc4f48e865a7b8dd4d70a70749037443"),
44 | generateSampleSecret("generic", "Zf3D0LXCM3EIMbgJpUNnkRtOfOueHznB"),
45 | `"client_id" : "0afae57f3ccfd9d7f5767067bc48b30f719e271ba470488056e37ab35d4b6506"`,
46 | `"client_secret" : "6da89121079f83b2eb6acccf8219ea982c3d79bccc3e9c6a85856480661f8fde",`,
47 | }
48 | fps := []string{
49 | `client_vpn_endpoint_id = aws_ec2_client_vpn_endpoint.client-vpn-endpoint.id`,
50 | `password combination.
51 |
52 | R5: Regulatory--21`,
53 | }
54 | return validate(r, tps, fps)
55 | }
56 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/dropbox.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func DropBoxAPISecret() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | Description: "Dropbox API secret",
12 | RuleID: "dropbox-api-token",
13 | Regex: generateSemiGenericRegex([]string{"dropbox"}, alphaNumeric("15")),
14 | SecretGroup: 1,
15 | Keywords: []string{"dropbox"},
16 | }
17 |
18 | // validate
19 | tps := []string{
20 | generateSampleSecret("dropbox", secrets.NewSecret(alphaNumeric("15"))),
21 | }
22 | return validate(r, tps, nil)
23 | }
24 |
25 | func DropBoxShortLivedAPIToken() *config.Rule {
26 | // define rule
27 | r := config.Rule{
28 | RuleID: "dropbox-short-lived-api-token",
29 | Description: "Dropbox short lived API token",
30 | Regex: generateSemiGenericRegex([]string{"dropbox"}, `sl\.[a-z0-9\-=_]{135}`),
31 | Keywords: []string{"dropbox"},
32 | }
33 |
34 | // validate TODO
35 | return &r
36 | }
37 |
38 | func DropBoxLongLivedAPIToken() *config.Rule {
39 | // define rule
40 | r := config.Rule{
41 | RuleID: "dropbox-long-lived-api-token",
42 | Description: "Dropbox long lived API token",
43 | Regex: generateSemiGenericRegex([]string{"dropbox"}, `[a-z0-9]{11}(AAAAAAAAAA)[a-z0-9\-_=]{43}`),
44 | Keywords: []string{"dropbox"},
45 | }
46 |
47 | // validate TODO
48 | return &r
49 | }
50 |
--------------------------------------------------------------------------------
/detect/location_test.go:
--------------------------------------------------------------------------------
1 | package detect
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | // TestGetLocation tests the getLocation function.
8 | func TestGetLocation(t *testing.T) {
9 | tests := []struct {
10 | linePairs [][]int
11 | start int
12 | end int
13 | wantLocation Location
14 | }{
15 | {
16 | linePairs: [][]int{
17 | {0, 39},
18 | {40, 55},
19 | {56, 57},
20 | },
21 | start: 35,
22 | end: 38,
23 | wantLocation: Location{
24 | startLine: 1,
25 | startColumn: 36,
26 | endLine: 1,
27 | endColumn: 38,
28 | startLineIndex: 0,
29 | endLineIndex: 40,
30 | },
31 | },
32 | {
33 | linePairs: [][]int{
34 | {0, 39},
35 | {40, 55},
36 | {56, 57},
37 | },
38 | start: 40,
39 | end: 44,
40 | wantLocation: Location{
41 | startLine: 2,
42 | startColumn: 1,
43 | endLine: 2,
44 | endColumn: 4,
45 | startLineIndex: 40,
46 | endLineIndex: 56,
47 | },
48 | },
49 | }
50 |
51 | for _, test := range tests {
52 | loc := location(Fragment{newlineIndices: test.linePairs}, []int{test.start, test.end})
53 | if loc != test.wantLocation {
54 | t.Errorf("\nstartLine %d\nstartColumn: %d\nendLine: %d\nendColumn: %d\nstartLineIndex: %d\nendlineIndex %d",
55 | loc.startLine, loc.startColumn, loc.endLine, loc.endColumn, loc.startLineIndex, loc.endLineIndex)
56 |
57 | t.Error("got", loc, "want", test.wantLocation)
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/testdata/baseline/baseline.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "Description": "PyPI upload token",
4 | "StartLine": 32,
5 | "EndLine": 32,
6 | "StartColumn": 21,
7 | "EndColumn": 106,
8 | "Match": "************************",
9 | "Secret": "************************",
10 | "File": "detect/detect_test.go",
11 | "Commit": "9326f35380636bcbe61e94b0584d1618c4b5c2c2",
12 | "Entropy": 1.9606875,
13 | "Author": "****",
14 | "Email": "****",
15 | "Date": "2022-03-07T14:33:06Z",
16 | "Message": "Escape - character in regex character groups (#802)\n\n* fix char escape\n\n* add test\n\n* fix verbosity in make test",
17 | "Tags": [],
18 | "RuleID": "pypi-upload-token",
19 | "Fingerprint": "9326f35380636bcbe61e94b0584d1618c4b5c2c2:detect/detect_test.go:pypi-upload-token:32"
20 | },
21 | {
22 | "Description": "PyPI upload token",
23 | "StartLine": 33,
24 | "EndLine": 33,
25 | "StartColumn": 21,
26 | "EndColumn": 106,
27 | "Match": "************************",
28 | "Secret": "************************",
29 | "File": "detect/detect_test.go",
30 | "Commit": "9326f35380636bcbe61e94b0584d1618c4b5c2c2",
31 | "Entropy": 1.9606875,
32 | "Author": "****",
33 | "Email": "****",
34 | "Date": "2022-03-07T14:33:06Z",
35 | "Message": "Escape - character in regex character groups (#802)\n\n* fix char escape\n\n* add test\n\n* fix verbosity in make test",
36 | "Tags": [],
37 | "RuleID": "pypi-upload-token",
38 | "Fingerprint": "9326f35380636bcbe61e94b0584d1618c4b5c2c2:detect/detect_test.go:pypi-upload-token:33"
39 | }
40 | ]
41 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/digitalocean.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func DigitalOceanPAT() *config.Rule {
9 | r := config.Rule{
10 | Description: "DigitalOcean Personal Access Token",
11 | RuleID: "digitalocean-pat",
12 | SecretGroup: 1,
13 | Regex: generateUniqueTokenRegex(`dop_v1_[a-f0-9]{64}`),
14 | Keywords: []string{"dop_v1_"},
15 | }
16 |
17 | tps := []string{
18 | generateSampleSecret("do", "dop_v1_"+secrets.NewSecret(hex("64"))),
19 | }
20 | return validate(r, tps, nil)
21 | }
22 |
23 | func DigitalOceanOAuthToken() *config.Rule {
24 | r := config.Rule{
25 | Description: "DigitalOcean OAuth Access Token",
26 | RuleID: "digitalocean-access-token",
27 | SecretGroup: 1,
28 | Regex: generateUniqueTokenRegex(`doo_v1_[a-f0-9]{64}`),
29 | Keywords: []string{"doo_v1_"},
30 | }
31 |
32 | tps := []string{
33 | generateSampleSecret("do", "doo_v1_"+secrets.NewSecret(hex("64"))),
34 | }
35 | return validate(r, tps, nil)
36 | }
37 |
38 | func DigitalOceanRefreshToken() *config.Rule {
39 | r := config.Rule{
40 | Description: "DigitalOcean OAuth Refresh Token",
41 | RuleID: "digitalocean-refresh-token",
42 | SecretGroup: 1,
43 | Regex: generateUniqueTokenRegex(`dor_v1_[a-f0-9]{64}`),
44 | Keywords: []string{"dor_v1_"},
45 | }
46 |
47 | tps := []string{
48 | generateSampleSecret("do", "dor_v1_"+secrets.NewSecret(hex("64"))),
49 | }
50 | return validate(r, tps, nil)
51 | }
52 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/gitlab.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "regexp"
5 |
6 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
7 | "github.com/zricethezav/gitleaks/v8/config"
8 | )
9 |
10 | func GitlabPat() *config.Rule {
11 | // define rule
12 | r := config.Rule{
13 | Description: "GitLab Personal Access Token",
14 | RuleID: "gitlab-pat",
15 | Regex: regexp.MustCompile(`glpat-[0-9a-zA-Z\-\_]{20}`),
16 | Keywords: []string{"glpat-"},
17 | }
18 |
19 | // validate
20 | tps := []string{
21 | generateSampleSecret("gitlab", "glpat-"+secrets.NewSecret(alphaNumeric("20"))),
22 | }
23 | return validate(r, tps, nil)
24 | }
25 |
26 | func GitlabPipelineTriggerToken() *config.Rule {
27 | // define rule
28 | r := config.Rule{
29 | Description: "GitLab Pipeline Trigger Token",
30 | RuleID: "gitlab-ptt",
31 | Regex: regexp.MustCompile(`glptt-[0-9a-f]{40}`),
32 | Keywords: []string{"glptt-"},
33 | }
34 |
35 | // validate
36 | tps := []string{
37 | generateSampleSecret("gitlab", "glptt-"+secrets.NewSecret(hex("40"))),
38 | }
39 | return validate(r, tps, nil)
40 | }
41 |
42 | func GitlabRunnerRegistrationToken() *config.Rule {
43 | // define rule
44 | r := config.Rule{
45 | Description: "GitLab Runner Registration Token",
46 | RuleID: "gitlab-rrt",
47 | Regex: regexp.MustCompile(`GR1348941[0-9a-zA-Z\-\_]{20}`),
48 | Keywords: []string{"GR1348941"},
49 | }
50 |
51 | // validate
52 | tps := []string{
53 | generateSampleSecret("gitlab", "GR1348941"+secrets.NewSecret(alphaNumeric("20"))),
54 | }
55 | return validate(r, tps, nil)
56 | }
57 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/messagebird.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func MessageBirdAPIToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | Description: "MessageBird API token",
12 | RuleID: "messagebird-api-token",
13 | Regex: generateSemiGenericRegex([]string{
14 | "messagebird",
15 | "message-bird",
16 | "message_bird",
17 | }, alphaNumeric("25")),
18 | SecretGroup: 1,
19 | Keywords: []string{
20 | "messagebird",
21 | "message-bird",
22 | "message_bird",
23 | },
24 | }
25 |
26 | // validate
27 | tps := []string{
28 | generateSampleSecret("messagebird", secrets.NewSecret(alphaNumeric("25"))),
29 | generateSampleSecret("message-bird", secrets.NewSecret(alphaNumeric("25"))),
30 | generateSampleSecret("message_bird", secrets.NewSecret(alphaNumeric("25"))),
31 | }
32 | return validate(r, tps, nil)
33 | }
34 |
35 | func MessageBirdClientID() *config.Rule {
36 | // define rule
37 | r := config.Rule{
38 | Description: "MessageBird client ID",
39 | RuleID: "messagebird-client-id",
40 | Regex: generateSemiGenericRegex([]string{
41 | "messagebird",
42 | "message-bird",
43 | "message_bird",
44 | }, hex8_4_4_4_12()),
45 | SecretGroup: 1,
46 | Keywords: []string{
47 | "messagebird",
48 | "message-bird",
49 | "message_bird",
50 | },
51 | }
52 |
53 | // validate
54 | tps := []string{
55 | `const MessageBirdClientID = "12345678-ABCD-ABCD-ABCD-1234567890AB"`, // gitleaks:allow
56 | }
57 | return validate(r, tps, nil)
58 | }
59 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/discord.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func DiscordAPIToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | Description: "Discord API key",
12 | RuleID: "discord-api-token",
13 | Regex: generateSemiGenericRegex([]string{"discord"}, hex("64")),
14 | SecretGroup: 1,
15 | Keywords: []string{"discord"},
16 | }
17 |
18 | // validate
19 | tps := []string{
20 | generateSampleSecret("discord", secrets.NewSecret(hex("64"))),
21 | }
22 | return validate(r, tps, nil)
23 | }
24 |
25 | func DiscordClientID() *config.Rule {
26 | // define rule
27 | r := config.Rule{
28 | Description: "Discord client ID",
29 | RuleID: "discord-client-id",
30 | Regex: generateSemiGenericRegex([]string{"discord"}, numeric("18")),
31 | SecretGroup: 1,
32 | Keywords: []string{"discord"},
33 | }
34 |
35 | // validate
36 | tps := []string{
37 | generateSampleSecret("discord", secrets.NewSecret(numeric("18"))),
38 | }
39 | return validate(r, tps, nil)
40 | }
41 |
42 | func DiscordClientSecret() *config.Rule {
43 | // define rule
44 | r := config.Rule{
45 | Description: "Discord client secret",
46 | RuleID: "discord-client-secret",
47 | Regex: generateSemiGenericRegex([]string{"discord"}, alphaNumericExtended("32")),
48 | SecretGroup: 1,
49 | Keywords: []string{"discord"},
50 | }
51 |
52 | // validate
53 | tps := []string{
54 | generateSampleSecret("discord", secrets.NewSecret(numeric("32"))),
55 | }
56 | return validate(r, tps, nil)
57 | }
58 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/flutterwave.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "regexp"
5 |
6 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
7 | "github.com/zricethezav/gitleaks/v8/config"
8 | )
9 |
10 | func FlutterwavePublicKey() *config.Rule {
11 | // define rule
12 | r := config.Rule{
13 | Description: "Finicity Public Key",
14 | RuleID: "flutterwave-public-key",
15 | Regex: regexp.MustCompile(`FLWPUBK_TEST-(?i)[a-h0-9]{32}-X`),
16 | Keywords: []string{"FLWPUBK_TEST"},
17 | }
18 |
19 | // validate
20 | tps := []string{
21 | generateSampleSecret("flutterwavePubKey", "FLWPUBK_TEST-"+secrets.NewSecret(hex("32"))+"-X"),
22 | }
23 | return validate(r, tps, nil)
24 | }
25 |
26 | func FlutterwaveSecretKey() *config.Rule {
27 | // define rule
28 | r := config.Rule{
29 | Description: "Flutterwave Secret Key",
30 | RuleID: "flutterwave-secret-key",
31 | Regex: regexp.MustCompile(`FLWSECK_TEST-(?i)[a-h0-9]{32}-X`),
32 | Keywords: []string{"FLWSECK_TEST"},
33 | }
34 |
35 | // validate
36 | tps := []string{
37 | generateSampleSecret("flutterwavePubKey", "FLWSECK_TEST-"+secrets.NewSecret(hex("32"))+"-X"),
38 | }
39 | return validate(r, tps, nil)
40 | }
41 |
42 | func FlutterwaveEncKey() *config.Rule {
43 | // define rule
44 | r := config.Rule{
45 | Description: "Flutterwave Encryption Key",
46 | RuleID: "flutterwave-encryption-key",
47 | Regex: regexp.MustCompile(`FLWSECK_TEST-(?i)[a-h0-9]{12}`),
48 | Keywords: []string{"FLWSECK_TEST"},
49 | }
50 |
51 | // validate
52 | tps := []string{
53 | generateSampleSecret("flutterwavePubKey", "FLWSECK_TEST-"+secrets.NewSecret(hex("12"))),
54 | }
55 | return validate(r, tps, nil)
56 | }
57 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/mailgun.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func MailGunPrivateAPIToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "mailgun-private-api-token",
12 | Description: "Mailgun private API token",
13 | Regex: generateSemiGenericRegex([]string{"mailgun"}, `key-[a-f0-9]{32}`),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "mailgun",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("mailgun", "key-"+secrets.NewSecret(hex("32"))),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
27 | func MailGunPubAPIToken() *config.Rule {
28 | // define rule
29 | r := config.Rule{
30 | RuleID: "mailgun-pub-key",
31 | Description: "Mailgun public validation key",
32 | Regex: generateSemiGenericRegex([]string{"mailgun"}, `pubkey-[a-f0-9]{32}`),
33 | SecretGroup: 1,
34 | Keywords: []string{
35 | "mailgun",
36 | },
37 | }
38 |
39 | // validate
40 | tps := []string{
41 | generateSampleSecret("mailgun", "pubkey-"+secrets.NewSecret(hex("32"))),
42 | }
43 | return validate(r, tps, nil)
44 | }
45 |
46 | func MailGunSigningKey() *config.Rule {
47 | // define rule
48 | r := config.Rule{
49 | RuleID: "mailgun-signing-key",
50 | Description: "Mailgun webhook signing key",
51 | Regex: generateSemiGenericRegex([]string{"mailgun"}, `[a-h0-9]{32}-[a-h0-9]{8}-[a-h0-9]{8}`),
52 | SecretGroup: 1,
53 | Keywords: []string{
54 | "mailgun",
55 | },
56 | }
57 |
58 | // validate
59 | tps := []string{
60 | generateSampleSecret("mailgun", secrets.NewSecret(hex("32"))+"-00001111-22223333"),
61 | }
62 | return validate(r, tps, nil)
63 | }
64 |
--------------------------------------------------------------------------------
/config/allowlist.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "regexp"
5 | "strings"
6 | )
7 |
8 | // Allowlist allows a rule to be ignored for specific
9 | // regexes, paths, and/or commits
10 | type Allowlist struct {
11 | // Short human readable description of the allowlist.
12 | Description string
13 |
14 | // Regexes is slice of content regular expressions that are allowed to be ignored.
15 | Regexes []*regexp.Regexp
16 |
17 | // RegexTarget
18 | RegexTarget string
19 |
20 | // Paths is a slice of path regular expressions that are allowed to be ignored.
21 | Paths []*regexp.Regexp
22 |
23 | // Commits is a slice of commit SHAs that are allowed to be ignored.
24 | Commits []string
25 |
26 | // StopWords is a slice of stop words that are allowed to be ignored.
27 | // This targets the _secret_, not the content of the regex match like the
28 | // Regexes slice.
29 | StopWords []string
30 | }
31 |
32 | // CommitAllowed returns true if the commit is allowed to be ignored.
33 | func (a *Allowlist) CommitAllowed(c string) bool {
34 | if c == "" {
35 | return false
36 | }
37 | for _, commit := range a.Commits {
38 | if commit == c {
39 | return true
40 | }
41 | }
42 | return false
43 | }
44 |
45 | // PathAllowed returns true if the path is allowed to be ignored.
46 | func (a *Allowlist) PathAllowed(path string) bool {
47 | return anyRegexMatch(path, a.Paths)
48 | }
49 |
50 | // RegexAllowed returns true if the regex is allowed to be ignored.
51 | func (a *Allowlist) RegexAllowed(s string) bool {
52 | return anyRegexMatch(s, a.Regexes)
53 | }
54 |
55 | func (a *Allowlist) ContainsStopWord(s string) bool {
56 | s = strings.ToLower(s)
57 | for _, stopWord := range a.StopWords {
58 | if strings.Contains(s, strings.ToLower(stopWord)) {
59 | return true
60 | }
61 | }
62 | return false
63 | }
64 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/plaid.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
7 | "github.com/zricethezav/gitleaks/v8/config"
8 | )
9 |
10 | func PlaidAccessID() *config.Rule {
11 | // define rule
12 | r := config.Rule{
13 | RuleID: "plaid-client-id",
14 | Description: "Plaid Client ID",
15 | Regex: generateSemiGenericRegex([]string{"plaid"}, alphaNumeric("24")),
16 | SecretGroup: 1,
17 | Keywords: []string{
18 | "plaid",
19 | },
20 | }
21 |
22 | // validate
23 | tps := []string{
24 | generateSampleSecret("plaid", secrets.NewSecret(alphaNumeric("24"))),
25 | }
26 | return validate(r, tps, nil)
27 | }
28 |
29 | func PlaidSecretKey() *config.Rule {
30 | // define rule
31 | r := config.Rule{
32 | RuleID: "plaid-secret-key",
33 | Description: "Plaid Secret key",
34 | Regex: generateSemiGenericRegex([]string{"plaid"}, alphaNumeric("30")),
35 | SecretGroup: 1,
36 | Keywords: []string{
37 | "plaid",
38 | },
39 | }
40 |
41 | // validate
42 | tps := []string{
43 | generateSampleSecret("plaid", secrets.NewSecret(alphaNumeric("30"))),
44 | }
45 | return validate(r, tps, nil)
46 | }
47 |
48 | func PlaidAccessToken() *config.Rule {
49 | // define rule
50 | r := config.Rule{
51 | RuleID: "plaid-api-token",
52 | Description: "Plaid API Token",
53 | Regex: generateSemiGenericRegex([]string{"plaid"},
54 | fmt.Sprintf("access-(?:sandbox|development|production)-%s", hex8_4_4_4_12())),
55 | SecretGroup: 1,
56 | Keywords: []string{
57 | "plaid",
58 | },
59 | }
60 |
61 | // validate
62 | tps := []string{
63 | generateSampleSecret("plaid", secrets.NewSecret(fmt.Sprintf("access-(?:sandbox|development|production)-%s", hex8_4_4_4_12()))),
64 | }
65 | return validate(r, tps, nil)
66 | }
67 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/yandex.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func YandexAWSAccessToken() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "yandex-aws-access-token",
12 | Description: "Yandex AWS Access Token",
13 | Regex: generateSemiGenericRegex([]string{"yandex"},
14 | `YC[a-zA-Z0-9_\-]{38}`),
15 | SecretGroup: 1,
16 | Keywords: []string{
17 | "yandex",
18 | },
19 | }
20 |
21 | // validate
22 | tps := []string{
23 | generateSampleSecret("yandex",
24 | secrets.NewSecret(`YC[a-zA-Z0-9_\-]{38}`)),
25 | }
26 | return validate(r, tps, nil)
27 | }
28 |
29 | func YandexAPIKey() *config.Rule {
30 | // define rule
31 | r := config.Rule{
32 | RuleID: "yandex-api-key",
33 | Description: "Yandex API Key",
34 | Regex: generateSemiGenericRegex([]string{"yandex"},
35 | `AQVN[A-Za-z0-9_\-]{35,38}`),
36 | SecretGroup: 1,
37 | Keywords: []string{
38 | "yandex",
39 | },
40 | }
41 |
42 | // validate
43 | tps := []string{
44 | generateSampleSecret("yandex",
45 | secrets.NewSecret(`AQVN[A-Za-z0-9_\-]{35,38}`)),
46 | }
47 | return validate(r, tps, nil)
48 | }
49 |
50 | func YandexAccessToken() *config.Rule {
51 | // define rule
52 | r := config.Rule{
53 | RuleID: "yandex-access-token",
54 | Description: "Yandex Access Token",
55 | Regex: generateSemiGenericRegex([]string{"yandex"},
56 | `t1\.[A-Z0-9a-z_-]+[=]{0,2}\.[A-Z0-9a-z_-]{86}[=]{0,2}`),
57 | SecretGroup: 1,
58 | Keywords: []string{
59 | "yandex",
60 | },
61 | }
62 |
63 | // validate
64 | tps := []string{
65 | generateSampleSecret("yandex",
66 | secrets.NewSecret(`t1\.[A-Z0-9a-z_-]+[=]{0,2}\.[A-Z0-9a-z_-]{86}[=]{0,2}`)),
67 | }
68 | return validate(r, tps, nil)
69 | }
70 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/grafana.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func GrafanaApiKey() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | Description: "Grafana api key (or Grafana cloud api key)",
12 | RuleID: "grafana-api-key",
13 | SecretGroup: 1,
14 | Regex: generateUniqueTokenRegex(`eyJrIjoi[A-Za-z0-9]{70,400}={0,2}`),
15 | Keywords: []string{"eyJrIjoi"},
16 | }
17 |
18 | // validate
19 | tps := []string{
20 | generateSampleSecret("grafana-api-key",
21 | "eyJrIjoi"+
22 | secrets.NewSecret(alphaNumeric("70"))),
23 | }
24 | return validate(r, tps, nil)
25 | }
26 |
27 | func GrafanaCloudApiToken() *config.Rule {
28 | // define rule
29 | r := config.Rule{
30 | Description: "Grafana cloud api token",
31 | RuleID: "grafana-cloud-api-token",
32 | SecretGroup: 1,
33 | Regex: generateUniqueTokenRegex(`glc_[A-Za-z0-9+/]{32,400}={0,2}`),
34 | Keywords: []string{"glc_"},
35 | }
36 |
37 | // validate
38 | tps := []string{
39 | generateSampleSecret("grafana-cloud-api-token",
40 | "glc_"+
41 | secrets.NewSecret(alphaNumeric("32"))),
42 | }
43 | return validate(r, tps, nil)
44 | }
45 |
46 | func GrafanaServiceAccountToken() *config.Rule {
47 | // define rule
48 | r := config.Rule{
49 | Description: "Grafana service account token",
50 | RuleID: "grafana-service-account-token",
51 | SecretGroup: 1,
52 | Regex: generateUniqueTokenRegex(`glsa_[A-Za-z0-9]{32}_[A-Fa-f0-9]{8}`),
53 | Keywords: []string{"glsa_"},
54 | }
55 |
56 | // validate
57 | tps := []string{
58 | generateSampleSecret("grafana-service-account-token",
59 | "glsa_"+
60 | secrets.NewSecret(alphaNumeric("32"))+
61 | "_"+
62 | secrets.NewSecret((hex("8")))),
63 | }
64 | return validate(r, tps, nil)
65 | }
66 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Create and publish a Docker image
2 |
3 | on:
4 | release:
5 | types: [published]
6 |
7 | env:
8 | REGISTRY: ghcr.io
9 | IMAGE_NAME: ${{ github.repository }}
10 |
11 | jobs:
12 | build-and-push-image:
13 | runs-on: ubuntu-latest
14 | permissions:
15 | contents: read
16 | packages: write
17 |
18 | steps:
19 | - name: Checkout repository
20 | uses: actions/checkout@v2
21 |
22 | - name: Set up QEMU
23 | uses: docker/setup-qemu-action@8b122486cedac8393e77aa9734c3528886e4a1a8
24 |
25 | - name: Set up Docker Buildx
26 | id: buildx
27 | uses: docker/setup-buildx-action@dc7b9719a96d48369863986a06765841d7ea23f6
28 |
29 | - name: Log in to Docker Hub
30 | uses: docker/login-action@49ed152c8eca782a232dede0303416e8f356c37b
31 | with:
32 | username: ${{ github.actor }}
33 | password: ${{ secrets.DOCKER_PASSWORD }}
34 |
35 | - name: Log in to the Container registry
36 | uses: docker/login-action@49ed152c8eca782a232dede0303416e8f356c37b
37 | with:
38 | registry: ${{ env.REGISTRY }}
39 | username: ${{ github.actor }}
40 | password: ${{ secrets.GITHUB_TOKEN }}
41 |
42 | - name: Extract metadata (tags, labels) for Docker
43 | id: meta
44 | uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
45 | with:
46 | images: |
47 | zricethezav/gitleaks
48 | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
49 |
50 | - name: Build and push Docker image
51 | uses: docker/build-push-action@e551b19e49efd4e98792db7592c17c09b89db8d8
52 | with:
53 | platforms: linux/amd64,linux/arm64
54 | context: .
55 | push: true
56 | tags: ${{ steps.meta.outputs.tags }}
57 | labels: ${{ steps.meta.outputs.labels }}
58 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/telegram.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "regexp"
5 |
6 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
7 | "github.com/zricethezav/gitleaks/v8/config"
8 | )
9 |
10 | func TelegramBotToken() *config.Rule {
11 | // define rule
12 | r := config.Rule{
13 | Description: "Telegram Bot API Token",
14 | RuleID: "telegram-bot-api-token",
15 | SecretGroup: 1,
16 | Regex: regexp.MustCompile(`(?i)(?:^|[^0-9])([0-9]{5,16}:A[a-zA-Z0-9_\-]{34})(?:$|[^a-zA-Z0-9_\-])`),
17 | Keywords: []string{
18 | "telegram",
19 | "api",
20 | "bot",
21 | "token",
22 | "url",
23 | },
24 | }
25 |
26 | // validate
27 | validToken := secrets.NewSecret(numeric("8") + ":A" + alphaNumericExtendedShort("34"))
28 | minToken := secrets.NewSecret(numeric("5") + ":A" + alphaNumericExtendedShort("34"))
29 | maxToken := secrets.NewSecret(numeric("16") + ":A" + alphaNumericExtendedShort("34"))
30 | tps := []string{
31 | // variable assignment
32 | generateSampleSecret("telegram", validToken),
33 | // URL containing token
34 | generateSampleSecret("url", "https://api.telegram.org/bot"+validToken+"/sendMessage"),
35 | // object constructor
36 | `const bot = new Telegraf("` + validToken + `")`,
37 | // .env
38 | `API_TOKEN = ` + validToken,
39 | // YAML
40 | `bot: ` + validToken,
41 | // Token with min bot_id
42 | generateSampleSecret("telegram", minToken),
43 | // Token with max bot_id
44 | generateSampleSecret("telegram", maxToken),
45 | }
46 |
47 | tooSmallToken := secrets.NewSecret(numeric("4") + ":A" + alphaNumericExtendedShort("34"))
48 | tooBigToken := secrets.NewSecret(numeric("17") + ":A" + alphaNumericExtendedShort("34"))
49 | fps := []string{
50 | // Token with too small bot_id
51 | generateSampleSecret("telegram", tooSmallToken),
52 | // Token with too big bot_id
53 | generateSampleSecret("telegram", tooBigToken),
54 | }
55 |
56 | return validate(r, tps, fps)
57 | }
58 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/newrelic.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func NewRelicUserID() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "new-relic-user-api-key",
12 | Description: "New Relic user API Key",
13 | Regex: generateSemiGenericRegex([]string{
14 | "new-relic",
15 | "newrelic",
16 | "new_relic",
17 | }, `NRAK-[a-z0-9]{27}`),
18 | SecretGroup: 1,
19 | Keywords: []string{
20 | "NRAK",
21 | },
22 | }
23 |
24 | // validate
25 | tps := []string{
26 | generateSampleSecret("new-relic", "NRAK-"+secrets.NewSecret(alphaNumeric("27"))),
27 | }
28 | return validate(r, tps, nil)
29 | }
30 |
31 | func NewRelicUserKey() *config.Rule {
32 | // define rule
33 | r := config.Rule{
34 | RuleID: "new-relic-user-api-id",
35 | Description: "New Relic user API ID",
36 | Regex: generateSemiGenericRegex([]string{
37 | "new-relic",
38 | "newrelic",
39 | "new_relic",
40 | }, alphaNumeric("64")),
41 | SecretGroup: 1,
42 | Keywords: []string{
43 | "new-relic",
44 | "newrelic",
45 | "new_relic",
46 | },
47 | }
48 |
49 | // validate
50 | tps := []string{
51 | generateSampleSecret("new-relic", secrets.NewSecret(alphaNumeric("64"))),
52 | }
53 | return validate(r, tps, nil)
54 | }
55 |
56 | func NewRelicBrowserAPIKey() *config.Rule {
57 | // define rule
58 | r := config.Rule{
59 | RuleID: "new-relic-browser-api-token",
60 | Description: "New Relic ingest browser API token",
61 | Regex: generateSemiGenericRegex([]string{
62 | "new-relic",
63 | "newrelic",
64 | "new_relic",
65 | }, `NRJS-[a-f0-9]{19}`),
66 | SecretGroup: 1,
67 | Keywords: []string{
68 | "NRJS-",
69 | },
70 | }
71 |
72 | // validate
73 | tps := []string{
74 | generateSampleSecret("new-relic", "NRJS-"+secrets.NewSecret(hex("19"))),
75 | }
76 | return validate(r, tps, nil)
77 | }
78 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/zricethezav/gitleaks/v8
2 |
3 | go 1.19
4 |
5 | require (
6 | github.com/charmbracelet/lipgloss v0.5.0
7 | github.com/fatih/semgroup v1.2.0
8 | github.com/gitleaks/go-gitdiff v0.8.0
9 | github.com/h2non/filetype v1.1.3
10 | github.com/rs/zerolog v1.26.1
11 | github.com/spf13/cobra v1.2.1
12 | github.com/spf13/viper v1.8.1
13 | github.com/stretchr/testify v1.7.0
14 | )
15 |
16 | require (
17 | github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
18 | github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
19 | github.com/mattn/go-isatty v0.0.17 // indirect
20 | github.com/mattn/go-runewidth v0.0.14 // indirect
21 | github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68 // indirect
22 | github.com/muesli/termenv v0.15.1 // indirect
23 | github.com/rivo/uniseg v0.2.0 // indirect
24 | )
25 |
26 | require (
27 | github.com/davecgh/go-spew v1.1.1 // indirect
28 | github.com/fsnotify/fsnotify v1.4.9 // indirect
29 | github.com/hashicorp/hcl v1.0.0 // indirect
30 | github.com/inconshreveable/mousetrap v1.0.0 // indirect
31 | github.com/lucasjones/reggen v0.0.0-20200904144131-37ba4fa293bb
32 | github.com/magiconair/properties v1.8.5 // indirect
33 | github.com/mitchellh/mapstructure v1.4.1 // indirect
34 | github.com/pelletier/go-toml v1.9.3 // indirect
35 | github.com/petar-dambovaliev/aho-corasick v0.0.0-20211021192214-5ab2d9280aa9
36 | github.com/pmezard/go-difflib v1.0.0 // indirect
37 | github.com/spf13/afero v1.6.0 // indirect
38 | github.com/spf13/cast v1.3.1 // indirect
39 | github.com/spf13/jwalterweatherman v1.1.0 // indirect
40 | github.com/spf13/pflag v1.0.5 // indirect
41 | github.com/subosito/gotenv v1.2.0 // indirect
42 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
43 | golang.org/x/sys v0.6.0 // indirect
44 | golang.org/x/text v0.3.6 // indirect
45 | gopkg.in/ini.v1 v1.62.0 // indirect
46 | gopkg.in/yaml.v2 v2.4.0 // indirect
47 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
48 | )
49 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/shopify.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "regexp"
5 |
6 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
7 | "github.com/zricethezav/gitleaks/v8/config"
8 | )
9 |
10 | func ShopifySharedSecret() *config.Rule {
11 | // define rule
12 | r := config.Rule{
13 | Description: "Shopify shared secret",
14 | RuleID: "shopify-shared-secret",
15 | Regex: regexp.MustCompile(`shpss_[a-fA-F0-9]{32}`),
16 | Keywords: []string{"shpss_"},
17 | }
18 |
19 | // validate
20 | tps := []string{"shopifySecret := \"shpss_" + secrets.NewSecret(hex("32")) + "\""}
21 | return validate(r, tps, nil)
22 | }
23 |
24 | func ShopifyAccessToken() *config.Rule {
25 | // define rule
26 | r := config.Rule{
27 | Description: "Shopify access token",
28 | RuleID: "shopify-access-token",
29 | Regex: regexp.MustCompile(`shpat_[a-fA-F0-9]{32}`),
30 | Keywords: []string{"shpat_"},
31 | }
32 |
33 | // validate
34 | tps := []string{"shopifyToken := \"shpat_" + secrets.NewSecret(hex("32")) + "\""}
35 | return validate(r, tps, nil)
36 | }
37 |
38 | func ShopifyCustomAccessToken() *config.Rule {
39 | // define rule
40 | r := config.Rule{
41 | Description: "Shopify custom access token",
42 | RuleID: "shopify-custom-access-token",
43 | Regex: regexp.MustCompile(`shpca_[a-fA-F0-9]{32}`),
44 | Keywords: []string{"shpca_"},
45 | }
46 |
47 | // validate
48 | tps := []string{"shopifyToken := \"shpca_" + secrets.NewSecret(hex("32")) + "\""}
49 | return validate(r, tps, nil)
50 | }
51 |
52 | func ShopifyPrivateAppAccessToken() *config.Rule {
53 | // define rule
54 | r := config.Rule{
55 | Description: "Shopify private app access token",
56 | RuleID: "shopify-private-app-access-token",
57 | Regex: regexp.MustCompile(`shppa_[a-fA-F0-9]{32}`),
58 | Keywords: []string{"shppa_"},
59 | }
60 |
61 | // validate
62 | tps := []string{"shopifyToken := \"shppa_" + secrets.NewSecret(hex("32")) + "\""}
63 | return validate(r, tps, nil)
64 | }
65 |
--------------------------------------------------------------------------------
/detect/baseline.go:
--------------------------------------------------------------------------------
1 | package detect
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "io"
7 | "os"
8 |
9 | "github.com/rs/zerolog/log"
10 |
11 | "github.com/zricethezav/gitleaks/v8/report"
12 | )
13 |
14 | func IsNew(finding report.Finding, baseline []report.Finding) bool {
15 | // Explicitly testing each property as it gives significantly better performance in comparison to cmp.Equal(). Drawback is that
16 | // the code requires maintenance if/when the Finding struct changes
17 | for _, b := range baseline {
18 |
19 | if finding.Author == b.Author &&
20 | finding.Commit == b.Commit &&
21 | finding.Date == b.Date &&
22 | finding.Description == b.Description &&
23 | finding.Email == b.Email &&
24 | finding.EndColumn == b.EndColumn &&
25 | finding.EndLine == b.EndLine &&
26 | finding.Entropy == b.Entropy &&
27 | finding.File == b.File &&
28 | // Omit checking finding.Fingerprint - if the format of the fingerprint changes, the users will see unexpected behaviour
29 | finding.Match == b.Match &&
30 | finding.Message == b.Message &&
31 | finding.RuleID == b.RuleID &&
32 | finding.Secret == b.Secret &&
33 | finding.StartColumn == b.StartColumn &&
34 | finding.StartLine == b.StartLine {
35 | return false
36 | }
37 | }
38 | return true
39 | }
40 |
41 | func LoadBaseline(baselinePath string) ([]report.Finding, error) {
42 | var previousFindings []report.Finding
43 | jsonFile, err := os.Open(baselinePath)
44 | if err != nil {
45 | return nil, fmt.Errorf("could not open %s", baselinePath)
46 | }
47 |
48 | defer func() {
49 | if cerr := jsonFile.Close(); cerr != nil {
50 | log.Warn().Err(cerr).Msg("problem closing jsonFile handle")
51 | }
52 | }()
53 |
54 | bytes, err := io.ReadAll(jsonFile)
55 | if err != nil {
56 | return nil, fmt.Errorf("could not read data from the file %s", baselinePath)
57 | }
58 |
59 | err = json.Unmarshal(bytes, &previousFindings)
60 | if err != nil {
61 | return nil, fmt.Errorf("the format of the file %s is not supported", baselinePath)
62 | }
63 |
64 | return previousFindings, nil
65 | }
66 |
--------------------------------------------------------------------------------
/report/json_test.go:
--------------------------------------------------------------------------------
1 | package report
2 |
3 | import (
4 | "bytes"
5 | "os"
6 | "path/filepath"
7 | "strings"
8 | "testing"
9 | )
10 |
11 | func TestWriteJSON(t *testing.T) {
12 | tests := []struct {
13 | findings []Finding
14 | testReportName string
15 | expected string
16 | wantEmpty bool
17 | }{
18 | {
19 | testReportName: "simple",
20 | expected: filepath.Join(expectPath, "report", "json_simple.json"),
21 | findings: []Finding{
22 | {
23 |
24 | Description: "",
25 | RuleID: "test-rule",
26 | Match: "line containing secret",
27 | Secret: "a secret",
28 | StartLine: 1,
29 | EndLine: 2,
30 | StartColumn: 1,
31 | EndColumn: 2,
32 | Message: "opps",
33 | File: "auth.py",
34 | SymlinkFile: "",
35 | Commit: "0000000000000000",
36 | Author: "John Doe",
37 | Email: "johndoe@gmail.com",
38 | Date: "10-19-2003",
39 | Tags: []string{},
40 | },
41 | }},
42 | {
43 |
44 | testReportName: "empty",
45 | expected: filepath.Join(expectPath, "report", "empty.json"),
46 | findings: []Finding{}},
47 | }
48 |
49 | for _, test := range tests {
50 | tmpfile, err := os.Create(filepath.Join(t.TempDir(), test.testReportName+".json"))
51 | if err != nil {
52 | t.Error(err)
53 | }
54 | err = writeJson(test.findings, tmpfile)
55 | if err != nil {
56 | t.Error(err)
57 | }
58 | got, err := os.ReadFile(tmpfile.Name())
59 | if err != nil {
60 | t.Error(err)
61 | }
62 | if test.wantEmpty {
63 | if len(got) > 0 {
64 | t.Errorf("Expected empty file, got %s", got)
65 | }
66 | continue
67 | }
68 | want, err := os.ReadFile(test.expected)
69 | if err != nil {
70 | t.Error(err)
71 | }
72 |
73 | if !bytes.Equal(got, want) {
74 | err = os.WriteFile(strings.Replace(test.expected, ".json", ".got.json", 1), got, 0644)
75 | if err != nil {
76 | t.Error(err)
77 | }
78 | t.Errorf("got %s, want %s", string(got), string(want))
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/report/csv_test.go:
--------------------------------------------------------------------------------
1 | package report
2 |
3 | import (
4 | "bytes"
5 | "os"
6 | "path/filepath"
7 | "strings"
8 | "testing"
9 | )
10 |
11 | func TestWriteCSV(t *testing.T) {
12 | tests := []struct {
13 | findings []Finding
14 | testReportName string
15 | expected string
16 | wantEmpty bool
17 | }{
18 | {
19 | testReportName: "simple",
20 | expected: filepath.Join(expectPath, "report", "csv_simple.csv"),
21 | findings: []Finding{
22 | {
23 | RuleID: "test-rule",
24 | Match: "line containing secret",
25 | Secret: "a secret",
26 | StartLine: 1,
27 | EndLine: 2,
28 | StartColumn: 1,
29 | EndColumn: 2,
30 | Message: "opps",
31 | File: "auth.py",
32 | SymlinkFile: "",
33 | Commit: "0000000000000000",
34 | Author: "John Doe",
35 | Email: "johndoe@gmail.com",
36 | Date: "10-19-2003",
37 | Fingerprint: "fingerprint",
38 | Tags: []string{"tag1", "tag2", "tag3"},
39 | },
40 | }},
41 | {
42 |
43 | wantEmpty: true,
44 | testReportName: "empty",
45 | expected: filepath.Join(expectPath, "report", "this_should_not_exist.csv"),
46 | findings: []Finding{}},
47 | }
48 |
49 | for _, test := range tests {
50 | tmpfile, err := os.Create(filepath.Join(t.TempDir(), test.testReportName+".csv"))
51 | if err != nil {
52 | t.Error(err)
53 | }
54 | err = writeCsv(test.findings, tmpfile)
55 | if err != nil {
56 | t.Error(err)
57 | }
58 | got, err := os.ReadFile(tmpfile.Name())
59 | if err != nil {
60 | t.Error(err)
61 | }
62 | if test.wantEmpty {
63 | if len(got) > 0 {
64 | t.Errorf("Expected empty file, got %s", got)
65 | }
66 | continue
67 | }
68 | want, err := os.ReadFile(test.expected)
69 | if err != nil {
70 | t.Error(err)
71 | }
72 |
73 | if !bytes.Equal(got, want) {
74 | err = os.WriteFile(strings.Replace(test.expected, ".csv", ".got.csv", 1), got, 0644)
75 | if err != nil {
76 | t.Error(err)
77 | }
78 | t.Errorf("got %s, want %s", string(got), string(want))
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/config/allowlist_test.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "regexp"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestCommitAllowed(t *testing.T) {
11 | tests := []struct {
12 | allowlist Allowlist
13 | commit string
14 | commitAllowed bool
15 | }{
16 | {
17 | allowlist: Allowlist{
18 | Commits: []string{"commitA"},
19 | },
20 | commit: "commitA",
21 | commitAllowed: true,
22 | },
23 | {
24 | allowlist: Allowlist{
25 | Commits: []string{"commitB"},
26 | },
27 | commit: "commitA",
28 | commitAllowed: false,
29 | },
30 | {
31 | allowlist: Allowlist{
32 | Commits: []string{"commitB"},
33 | },
34 | commit: "",
35 | commitAllowed: false,
36 | },
37 | }
38 | for _, tt := range tests {
39 | assert.Equal(t, tt.commitAllowed, tt.allowlist.CommitAllowed(tt.commit))
40 | }
41 | }
42 |
43 | func TestRegexAllowed(t *testing.T) {
44 | tests := []struct {
45 | allowlist Allowlist
46 | secret string
47 | regexAllowed bool
48 | }{
49 | {
50 | allowlist: Allowlist{
51 | Regexes: []*regexp.Regexp{regexp.MustCompile("matchthis")},
52 | },
53 | secret: "a secret: matchthis, done",
54 | regexAllowed: true,
55 | },
56 | {
57 | allowlist: Allowlist{
58 | Regexes: []*regexp.Regexp{regexp.MustCompile("matchthis")},
59 | },
60 | secret: "a secret",
61 | regexAllowed: false,
62 | },
63 | }
64 | for _, tt := range tests {
65 | assert.Equal(t, tt.regexAllowed, tt.allowlist.RegexAllowed(tt.secret))
66 | }
67 | }
68 |
69 | func TestPathAllowed(t *testing.T) {
70 | tests := []struct {
71 | allowlist Allowlist
72 | path string
73 | pathAllowed bool
74 | }{
75 | {
76 | allowlist: Allowlist{
77 | Paths: []*regexp.Regexp{regexp.MustCompile("path")},
78 | },
79 | path: "a path",
80 | pathAllowed: true,
81 | },
82 | {
83 | allowlist: Allowlist{
84 | Paths: []*regexp.Regexp{regexp.MustCompile("path")},
85 | },
86 | path: "a ???",
87 | pathAllowed: false,
88 | },
89 | }
90 | for _, tt := range tests {
91 | assert.Equal(t, tt.pathAllowed, tt.allowlist.PathAllowed(tt.path))
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/testdata/expected/report/junit_simple.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {
"Description": "Test Rule",
"StartLine": 1,
"EndLine": 2,
"StartColumn": 1,
"EndColumn": 2,
"Match": "line containing secret",
"Secret": "a secret",
"File": "auth.py",
"SymlinkFile": "",
"Commit": "0000000000000000",
"Entropy": 0,
"Author": "John Doe",
"Email": "johndoe@gmail.com",
"Date": "10-19-2003",
"Message": "opps",
"Tags": [],
"RuleID": "test-rule",
"Fingerprint": ""
}
6 |
7 |
8 | {
"Description": "Test Rule",
"StartLine": 2,
"EndLine": 3,
"StartColumn": 1,
"EndColumn": 2,
"Match": "line containing secret",
"Secret": "a secret",
"File": "auth.py",
"SymlinkFile": "",
"Commit": "",
"Entropy": 0,
"Author": "",
"Email": "",
"Date": "",
"Message": "",
"Tags": [],
"RuleID": "test-rule",
"Fingerprint": ""
}
9 |
10 |
11 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/config.tmpl:
--------------------------------------------------------------------------------
1 | # This file has been auto-generated. Do not edit manually.
2 | # If you would like to contribute new rules, please use
3 | # cmd/generate/config/main.go and follow the contributing guidelines
4 | # at https://github.com/zricethezav/gitleaks/blob/master/CONTRIBUTING.md
5 |
6 | # This is the default gitleaks configuration file.
7 | # Rules and allowlists are defined within this file.
8 | # Rules instruct gitleaks on what should be considered a secret.
9 | # Allowlists instruct gitleaks on what is allowed, i.e. not a secret.
10 |
11 | title = "gitleaks config"
12 |
13 | [allowlist]
14 | description = "global allow lists"
15 | paths = [
16 | '''gitleaks.toml''',
17 | '''(.*?)(jpg|gif|doc|docx|zip|xls|pdf|bin|svg|socket|vsidx|v2|suo|wsuo|.dll|pdb|exe)$''',
18 | '''(go.mod|go.sum)$''',
19 | '''gradle.lockfile''',
20 | '''node_modules''',
21 | '''package-lock.json''',
22 | '''pnpm-lock.yaml''',
23 | '''Database.refactorlog''',
24 | '''vendor''',
25 | ]
26 |
27 | {{ range $i, $rule := .Rules }}[[rules]]
28 | {{ if and $rule.SecretGroup $rule.Entropy $rule.Allowlist.StopWords }}description = "{{$rule.Description}}"
29 | id = "{{$rule.RuleID}}"
30 | regex = '''{{$rule.Regex}}'''
31 | secretGroup = {{ $rule.SecretGroup }}
32 | entropy = {{ $rule.Entropy}}
33 | keywords = [
34 | {{ range $j, $keyword := $rule.Keywords }}"{{$keyword}}",{{end}}
35 | ]
36 | [rules.allowlist]
37 | stopwords= [{{ range $j, $stopword := $rule.Allowlist.StopWords }}
38 | "{{$stopword}}",{{end}}
39 | ]
40 | {{ else if and $rule.SecretGroup $rule.Entropy }}description = "{{$rule.Description}}"
41 | id = "{{$rule.RuleID}}"
42 | regex = '''{{$rule.Regex}}'''
43 | secretGroup = {{ $rule.SecretGroup }}
44 | entropy = {{ $rule.Entropy}}
45 | keywords = [
46 | {{ range $j, $keyword := $rule.Keywords }}"{{$keyword}}",{{end}}
47 | ]
48 |
49 | {{ else if $rule.SecretGroup }}description = "{{$rule.Description}}"
50 | id = "{{$rule.RuleID}}"
51 | regex = '''{{$rule.Regex}}'''
52 | secretGroup = {{ $rule.SecretGroup }}
53 | keywords = [
54 | {{ range $j, $keyword := $rule.Keywords }}"{{$keyword}}",{{end}}
55 | ]
56 |
57 | {{ else }}description = "{{$rule.Description}}"
58 | id = "{{$rule.RuleID}}"
59 | regex = '''{{$rule.Regex}}'''
60 | keywords = [
61 | {{ range $j, $keyword := $rule.Keywords }}"{{$keyword}}",{{end}}
62 | ]
63 |
64 | {{end}}{{end}}
65 |
--------------------------------------------------------------------------------
/testdata/repos/staged/dotGit/logs/HEAD:
--------------------------------------------------------------------------------
1 | 0000000000000000000000000000000000000000 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 Zach Rice 1635896329 -0500 clone: from github.com:gitleaks/test.git
2 | 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 Zach Rice 1635896362 -0500 checkout: moving from main to remove-secrets
3 | 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 906335481df9a4b48906c90318b4fac76b67fe73 Zach Rice 1635896426 -0500 commit: load token via env var
4 | 906335481df9a4b48906c90318b4fac76b67fe73 a122b33c6bad3ee54724f52f2caad385ab1982ab Zach Rice 1635896518 -0500 commit: add api package
5 | a122b33c6bad3ee54724f52f2caad385ab1982ab a122b33c6bad3ee54724f52f2caad385ab1982ab Zach Rice 1635896543 -0500 checkout: moving from remove-secrets to api-pkg
6 | a122b33c6bad3ee54724f52f2caad385ab1982ab 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 Zach Rice 1635896644 -0500 checkout: moving from api-pkg to main
7 | 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 2e1db472eeba53f06c4026ae4566ea022e36598e Zach Rice 1635896648 -0500 pull origin main: Fast-forward
8 | 2e1db472eeba53f06c4026ae4566ea022e36598e 2e1db472eeba53f06c4026ae4566ea022e36598e Zach Rice 1635896716 -0500 checkout: moving from main to foo
9 | 2e1db472eeba53f06c4026ae4566ea022e36598e 491504d5a31946ce75e22554cc34203d8e5ff3ca Zach Rice 1635896886 -0500 commit: adding foo package with secret
10 | 491504d5a31946ce75e22554cc34203d8e5ff3ca f1b58b97808f8e744f6a23c693859df5b5968901 Zach Rice 1635896931 -0500 commit: removing secret from foo package
11 | f1b58b97808f8e744f6a23c693859df5b5968901 2e1db472eeba53f06c4026ae4566ea022e36598e Zach Rice 1635897009 -0500 checkout: moving from foo to main
12 | 2e1db472eeba53f06c4026ae4566ea022e36598e f1b58b97808f8e744f6a23c693859df5b5968901 Zach Rice 1635897062 -0500 checkout: moving from main to foo
13 | f1b58b97808f8e744f6a23c693859df5b5968901 2e1db472eeba53f06c4026ae4566ea022e36598e Zach Rice 1635897508 -0500 checkout: moving from foo to main
14 | 2e1db472eeba53f06c4026ae4566ea022e36598e bf3f24164d7256b4021575cbdb2f97b98e6f057e Rafael Figueiredo 1679239434 -0300 commit: add .gitleaksignore file
15 |
--------------------------------------------------------------------------------
/detect/location.go:
--------------------------------------------------------------------------------
1 | package detect
2 |
3 | // Location represents a location in a file
4 | type Location struct {
5 | startLine int
6 | endLine int
7 | startColumn int
8 | endColumn int
9 | startLineIndex int
10 | endLineIndex int
11 | }
12 |
13 | func location(fragment Fragment, matchIndex []int) Location {
14 | var (
15 | prevNewLine int
16 | location Location
17 | lineSet bool
18 | _lineNum int
19 | )
20 |
21 | start := matchIndex[0]
22 | end := matchIndex[1]
23 |
24 | // default startLineIndex to 0
25 | location.startLineIndex = 0
26 |
27 | // Fixes: https://github.com/zricethezav/gitleaks/issues/1037
28 | // When a fragment does NOT have any newlines, a default "newline"
29 | // will be counted to make the subsequent location calculation logic work
30 | // for fragments will no newlines.
31 | if len(fragment.newlineIndices) == 0 {
32 | fragment.newlineIndices = [][]int{
33 | {len(fragment.Raw), len(fragment.Raw) + 1},
34 | }
35 | }
36 |
37 | for lineNum, pair := range fragment.newlineIndices {
38 | _lineNum = lineNum
39 | newLineByteIndex := pair[0]
40 | if prevNewLine <= start && start < newLineByteIndex {
41 | lineSet = true
42 | location.startLine = lineNum
43 | location.endLine = lineNum
44 | location.startColumn = (start - prevNewLine) + 1 // +1 because counting starts at 1
45 | location.startLineIndex = prevNewLine
46 | location.endLineIndex = newLineByteIndex
47 | }
48 | if prevNewLine < end && end <= newLineByteIndex {
49 | location.endLine = lineNum
50 | location.endColumn = (end - prevNewLine)
51 | location.endLineIndex = newLineByteIndex
52 | }
53 | prevNewLine = pair[0]
54 | }
55 |
56 | if !lineSet {
57 | // if lines never get set then that means the secret is most likely
58 | // on the last line of the diff output and the diff output does not have
59 | // a newline
60 | location.startColumn = (start - prevNewLine) + 1 // +1 because counting starts at 1
61 | location.endColumn = (end - prevNewLine)
62 | location.startLine = _lineNum + 1
63 | location.endLine = _lineNum + 1
64 |
65 | // search for new line byte index
66 | i := 0
67 | for end+i < len(fragment.Raw) {
68 | if fragment.Raw[end+i] == '\n' {
69 | break
70 | }
71 | if fragment.Raw[end+i] == '\r' {
72 | break
73 | }
74 | i++
75 | }
76 | location.endLineIndex = end + i
77 | }
78 | return location
79 | }
80 |
--------------------------------------------------------------------------------
/report/report_test.go:
--------------------------------------------------------------------------------
1 | package report
2 |
3 | import (
4 | "os"
5 | "path/filepath"
6 | "strconv"
7 | "testing"
8 |
9 | "github.com/zricethezav/gitleaks/v8/config"
10 | )
11 |
12 | const (
13 | expectPath = "../testdata/expected/"
14 | )
15 |
16 | func TestReport(t *testing.T) {
17 | tests := []struct {
18 | findings []Finding
19 | ext string
20 | wantEmpty bool
21 | }{
22 | {
23 | ext: "json",
24 | findings: []Finding{
25 | {
26 | RuleID: "test-rule",
27 | },
28 | },
29 | },
30 | {
31 | ext: ".json",
32 | findings: []Finding{
33 | {
34 | RuleID: "test-rule",
35 | },
36 | },
37 | },
38 | {
39 | ext: ".jsonj",
40 | findings: []Finding{
41 | {
42 | RuleID: "test-rule",
43 | },
44 | },
45 | wantEmpty: true,
46 | },
47 | {
48 | ext: ".csv",
49 | findings: []Finding{
50 | {
51 | RuleID: "test-rule",
52 | },
53 | },
54 | },
55 | {
56 | ext: "csv",
57 | findings: []Finding{
58 | {
59 | RuleID: "test-rule",
60 | },
61 | },
62 | },
63 | {
64 | ext: "CSV",
65 | findings: []Finding{
66 | {
67 | RuleID: "test-rule",
68 | },
69 | },
70 | },
71 | {
72 | ext: ".xml",
73 | findings: []Finding{
74 | {
75 | RuleID: "test-rule",
76 | },
77 | },
78 | },
79 | {
80 | ext: "junit",
81 | findings: []Finding{
82 | {
83 | RuleID: "test-rule",
84 | },
85 | },
86 | },
87 | // {
88 | // ext: "SARIF",
89 | // findings: []Finding{
90 | // {
91 | // RuleID: "test-rule",
92 | // },
93 | // },
94 | // },
95 | }
96 |
97 | for i, test := range tests {
98 | tmpfile, err := os.Create(filepath.Join(t.TempDir(), strconv.Itoa(i)+test.ext))
99 | if err != nil {
100 | t.Error(err)
101 | }
102 | err = Write(test.findings, config.Config{}, test.ext, tmpfile.Name())
103 | if err != nil {
104 | t.Error(err)
105 | }
106 | got, err := os.ReadFile(tmpfile.Name())
107 | if err != nil {
108 | t.Error(err)
109 | }
110 |
111 | if len(got) == 0 && !test.wantEmpty {
112 | t.Errorf("got empty file with extension " + test.ext)
113 | }
114 |
115 | if test.wantEmpty {
116 | if len(got) > 0 {
117 | t.Errorf("Expected empty file, got %s", got)
118 | }
119 | continue
120 | }
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/planetscale.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func PlanetScalePassword() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | RuleID: "planetscale-password",
12 | Description: "PlanetScale password",
13 | Regex: generateUniqueTokenRegex(`pscale_pw_(?i)[a-z0-9=\-_\.]{32,64}`),
14 | SecretGroup: 1,
15 | Keywords: []string{
16 | "pscale_pw_",
17 | },
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | generateSampleSecret("planetScalePassword", "pscale_pw_"+secrets.NewSecret(alphaNumericExtended("32"))),
23 | generateSampleSecret("planetScalePassword", "pscale_pw_"+secrets.NewSecret(alphaNumericExtended("43"))),
24 | generateSampleSecret("planetScalePassword", "pscale_pw_"+secrets.NewSecret(alphaNumericExtended("64"))),
25 | }
26 | return validate(r, tps, nil)
27 | }
28 |
29 | func PlanetScaleAPIToken() *config.Rule {
30 | // define rule
31 | r := config.Rule{
32 | RuleID: "planetscale-api-token",
33 | Description: "PlanetScale API token",
34 | Regex: generateUniqueTokenRegex(`pscale_tkn_(?i)[a-z0-9=\-_\.]{32,64}`),
35 | SecretGroup: 1,
36 | Keywords: []string{
37 | "pscale_tkn_",
38 | },
39 | }
40 |
41 | // validate
42 | tps := []string{
43 | generateSampleSecret("planetScalePassword", "pscale_tkn_"+secrets.NewSecret(alphaNumericExtended("32"))),
44 | generateSampleSecret("planetScalePassword", "pscale_tkn_"+secrets.NewSecret(alphaNumericExtended("43"))),
45 | generateSampleSecret("planetScalePassword", "pscale_tkn_"+secrets.NewSecret(alphaNumericExtended("64"))),
46 | }
47 | return validate(r, tps, nil)
48 | }
49 |
50 | func PlanetScaleOAuthToken() *config.Rule {
51 | // define rule
52 | r := config.Rule{
53 | RuleID: "planetscale-oauth-token",
54 | Description: "PlanetScale OAuth token",
55 | Regex: generateUniqueTokenRegex(`pscale_oauth_(?i)[a-z0-9=\-_\.]{32,64}`),
56 | SecretGroup: 1,
57 | Keywords: []string{
58 | "pscale_oauth_",
59 | },
60 | }
61 |
62 | // validate
63 | tps := []string{
64 | generateSampleSecret("planetScalePassword", "pscale_oauth_"+secrets.NewSecret(alphaNumericExtended("32"))),
65 | generateSampleSecret("planetScalePassword", "pscale_oauth_"+secrets.NewSecret(alphaNumericExtended("43"))),
66 | generateSampleSecret("planetScalePassword", "pscale_oauth_"+secrets.NewSecret(alphaNumericExtended("64"))),
67 | }
68 | return validate(r, tps, nil)
69 | }
70 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/sidekiq.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "regexp"
5 |
6 | "github.com/zricethezav/gitleaks/v8/config"
7 | )
8 |
9 | func SidekiqSecret() *config.Rule {
10 | // define rule
11 | r := config.Rule{
12 | Description: "Sidekiq Secret",
13 | RuleID: "sidekiq-secret",
14 | SecretGroup: 1,
15 | Regex: generateSemiGenericRegex([]string{"BUNDLE_ENTERPRISE__CONTRIBSYS__COM", "BUNDLE_GEMS__CONTRIBSYS__COM"},
16 | `[a-f0-9]{8}:[a-f0-9]{8}`),
17 | Keywords: []string{"BUNDLE_ENTERPRISE__CONTRIBSYS__COM", "BUNDLE_GEMS__CONTRIBSYS__COM"},
18 | }
19 |
20 | // validate
21 | tps := []string{
22 | "BUNDLE_ENTERPRISE__CONTRIBSYS__COM: cafebabe:deadbeef",
23 | "export BUNDLE_ENTERPRISE__CONTRIBSYS__COM=cafebabe:deadbeef",
24 | "export BUNDLE_ENTERPRISE__CONTRIBSYS__COM = cafebabe:deadbeef",
25 | "BUNDLE_GEMS__CONTRIBSYS__COM: \"cafebabe:deadbeef\"",
26 | "export BUNDLE_GEMS__CONTRIBSYS__COM=\"cafebabe:deadbeef\"",
27 | "export BUNDLE_GEMS__CONTRIBSYS__COM = \"cafebabe:deadbeef\"",
28 | "export BUNDLE_ENTERPRISE__CONTRIBSYS__COM=cafebabe:deadbeef;",
29 | "export BUNDLE_ENTERPRISE__CONTRIBSYS__COM=cafebabe:deadbeef && echo 'hello world'",
30 | }
31 | return validate(r, tps, nil)
32 | }
33 |
34 | func SidekiqSensitiveUrl() *config.Rule {
35 | // define rule
36 | r := config.Rule{
37 | Description: "Sidekiq Sensitive URL",
38 | RuleID: "sidekiq-sensitive-url",
39 | SecretGroup: 2,
40 | Regex: regexp.MustCompile(`(?i)\b(http(?:s??):\/\/)([a-f0-9]{8}:[a-f0-9]{8})@(?:gems.contribsys.com|enterprise.contribsys.com)(?:[\/|\#|\?|:]|$)`),
41 | Keywords: []string{"gems.contribsys.com", "enterprise.contribsys.com"},
42 | }
43 |
44 | // validate
45 | tps := []string{
46 | "https://cafebabe:deadbeef@gems.contribsys.com/",
47 | "https://cafebabe:deadbeef@gems.contribsys.com",
48 | "https://cafeb4b3:d3adb33f@enterprise.contribsys.com/",
49 | "https://cafeb4b3:d3adb33f@enterprise.contribsys.com",
50 | "http://cafebabe:deadbeef@gems.contribsys.com/",
51 | "http://cafebabe:deadbeef@gems.contribsys.com",
52 | "http://cafeb4b3:d3adb33f@enterprise.contribsys.com/",
53 | "http://cafeb4b3:d3adb33f@enterprise.contribsys.com",
54 | "http://cafeb4b3:d3adb33f@enterprise.contribsys.com#heading1",
55 | "http://cafeb4b3:d3adb33f@enterprise.contribsys.com?param1=true¶m2=false",
56 | "http://cafeb4b3:d3adb33f@enterprise.contribsys.com:80",
57 | "http://cafeb4b3:d3adb33f@enterprise.contribsys.com:80/path?param1=true¶m2=false#heading1",
58 | }
59 | return validate(r, tps, nil)
60 | }
61 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/github.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "regexp"
5 |
6 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
7 | "github.com/zricethezav/gitleaks/v8/config"
8 | )
9 |
10 | func GitHubPat() *config.Rule {
11 | // define rule
12 | r := config.Rule{
13 | Description: "GitHub Personal Access Token",
14 | RuleID: "github-pat",
15 | Regex: regexp.MustCompile(`ghp_[0-9a-zA-Z]{36}`),
16 | Keywords: []string{"ghp_"},
17 | }
18 |
19 | // validate
20 | tps := []string{
21 | generateSampleSecret("github", "ghp_"+secrets.NewSecret(alphaNumeric("36"))),
22 | }
23 | return validate(r, tps, nil)
24 | }
25 |
26 | func GitHubFineGrainedPat() *config.Rule {
27 | // define rule
28 | r := config.Rule{
29 | Description: "GitHub Fine-Grained Personal Access Token",
30 | RuleID: "github-fine-grained-pat",
31 | Regex: regexp.MustCompile(`github_pat_[0-9a-zA-Z_]{82}`),
32 | Keywords: []string{"github_pat_"},
33 | }
34 |
35 | // validate
36 | tps := []string{
37 | generateSampleSecret("github", "github_pat_"+secrets.NewSecret(alphaNumeric("82"))),
38 | }
39 | return validate(r, tps, nil)
40 | }
41 |
42 | func GitHubOauth() *config.Rule {
43 | // define rule
44 | r := config.Rule{
45 | Description: "GitHub OAuth Access Token",
46 | RuleID: "github-oauth",
47 | Regex: regexp.MustCompile(`gho_[0-9a-zA-Z]{36}`),
48 | Keywords: []string{"gho_"},
49 | }
50 |
51 | // validate
52 | tps := []string{
53 | generateSampleSecret("github", "gho_"+secrets.NewSecret(alphaNumeric("36"))),
54 | }
55 | return validate(r, tps, nil)
56 | }
57 |
58 | func GitHubApp() *config.Rule {
59 | // define rule
60 | r := config.Rule{
61 | Description: "GitHub App Token",
62 | RuleID: "github-app-token",
63 | Regex: regexp.MustCompile(`(ghu|ghs)_[0-9a-zA-Z]{36}`),
64 | Keywords: []string{"ghu_", "ghs_"},
65 | }
66 |
67 | // validate
68 | tps := []string{
69 | generateSampleSecret("github", "ghu_"+secrets.NewSecret(alphaNumeric("36"))),
70 | generateSampleSecret("github", "ghs_"+secrets.NewSecret(alphaNumeric("36"))),
71 | }
72 | return validate(r, tps, nil)
73 | }
74 |
75 | func GitHubRefresh() *config.Rule {
76 | // define rule
77 | r := config.Rule{
78 | Description: "GitHub Refresh Token",
79 | RuleID: "github-refresh-token",
80 | Regex: regexp.MustCompile(`ghr_[0-9a-zA-Z]{36}`),
81 | Keywords: []string{"ghr_"},
82 | }
83 |
84 | // validate
85 | tps := []string{
86 | generateSampleSecret("github", "ghr_"+secrets.NewSecret(alphaNumeric("36"))),
87 | }
88 | return validate(r, tps, nil)
89 | }
90 |
--------------------------------------------------------------------------------
/report/sarif_test.go:
--------------------------------------------------------------------------------
1 | package report
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | "os"
7 | "path/filepath"
8 | "strings"
9 | "testing"
10 |
11 | "github.com/spf13/viper"
12 | "github.com/zricethezav/gitleaks/v8/config"
13 | )
14 |
15 | const configPath = "../testdata/config/"
16 |
17 | func TestWriteSarif(t *testing.T) {
18 | tests := []struct {
19 | findings []Finding
20 | testReportName string
21 | expected string
22 | wantEmpty bool
23 | cfgName string
24 | }{
25 | {
26 | cfgName: "simple",
27 | testReportName: "simple",
28 | expected: filepath.Join(expectPath, "report", "sarif_simple.sarif"),
29 | findings: []Finding{
30 | {
31 |
32 | Description: "A test rule",
33 | RuleID: "test-rule",
34 | Match: "line containing secret",
35 | Secret: "a secret",
36 | StartLine: 1,
37 | EndLine: 2,
38 | StartColumn: 1,
39 | EndColumn: 2,
40 | Message: "opps",
41 | File: "auth.py",
42 | Commit: "0000000000000000",
43 | Author: "John Doe",
44 | Email: "johndoe@gmail.com",
45 | Date: "10-19-2003",
46 | Tags: []string{"tag1", "tag2", "tag3"},
47 | },
48 | }},
49 | }
50 |
51 | for _, test := range tests {
52 | tmpfile, err := os.Create(filepath.Join(t.TempDir(), test.testReportName+".json"))
53 | if err != nil {
54 | t.Error(err)
55 | }
56 | viper.Reset()
57 | viper.AddConfigPath(configPath)
58 | viper.SetConfigName(test.cfgName)
59 | viper.SetConfigType("toml")
60 | err = viper.ReadInConfig()
61 | if err != nil {
62 | t.Error(err)
63 | }
64 |
65 | var vc config.ViperConfig
66 | err = viper.Unmarshal(&vc)
67 | if err != nil {
68 | t.Error(err)
69 | }
70 |
71 | cfg, err := vc.Translate()
72 | if err != nil {
73 | t.Error(err)
74 | }
75 | err = writeSarif(cfg, test.findings, tmpfile)
76 | fmt.Println(cfg)
77 | if err != nil {
78 | t.Error(err)
79 | }
80 | got, err := os.ReadFile(tmpfile.Name())
81 | if err != nil {
82 | t.Error(err)
83 | }
84 | if test.wantEmpty {
85 | if len(got) > 0 {
86 | t.Errorf("Expected empty file, got %s", got)
87 | }
88 | continue
89 | }
90 | want, err := os.ReadFile(test.expected)
91 | if err != nil {
92 | t.Error(err)
93 | }
94 |
95 | if !bytes.Equal(got, want) {
96 | err = os.WriteFile(strings.Replace(test.expected, ".sarif", ".got.sarif", 1), got, 0644)
97 | if err != nil {
98 | t.Error(err)
99 | }
100 | t.Errorf("got %s, want %s", string(got), string(want))
101 | }
102 |
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/cmd/generate/config/rules/twitter.go:
--------------------------------------------------------------------------------
1 | package rules
2 |
3 | import (
4 | "github.com/zricethezav/gitleaks/v8/cmd/generate/secrets"
5 | "github.com/zricethezav/gitleaks/v8/config"
6 | )
7 |
8 | func TwitterAPIKey() *config.Rule {
9 | // define rule
10 | r := config.Rule{
11 | Description: "Twitter API Key",
12 | RuleID: "twitter-api-key",
13 | Regex: generateSemiGenericRegex([]string{"twitter"}, alphaNumeric("25")),
14 | SecretGroup: 1,
15 | Keywords: []string{"twitter"},
16 | }
17 |
18 | // validate
19 | tps := []string{
20 | generateSampleSecret("twitter", secrets.NewSecret(alphaNumeric("25"))),
21 | }
22 | return validate(r, tps, nil)
23 | }
24 |
25 | func TwitterAPISecret() *config.Rule {
26 | // define rule
27 | r := config.Rule{
28 | Description: "Twitter API Secret",
29 | RuleID: "twitter-api-secret",
30 | Regex: generateSemiGenericRegex([]string{"twitter"}, alphaNumeric("50")),
31 | SecretGroup: 1,
32 | Keywords: []string{"twitter"},
33 | }
34 |
35 | // validate
36 | tps := []string{
37 | generateSampleSecret("twitter", secrets.NewSecret(alphaNumeric("50"))),
38 | }
39 | return validate(r, tps, nil)
40 | }
41 |
42 | func TwitterBearerToken() *config.Rule {
43 | // define rule
44 | r := config.Rule{
45 | Description: "Twitter Bearer Token",
46 | RuleID: "twitter-bearer-token",
47 | Regex: generateSemiGenericRegex([]string{"twitter"}, "A{22}[a-zA-Z0-9%]{80,100}"),
48 | SecretGroup: 1,
49 | Keywords: []string{"twitter"},
50 | }
51 |
52 | // validate
53 | tps := []string{
54 | generateSampleSecret("twitter", secrets.NewSecret("A{22}[a-zA-Z0-9%]{80,100}")),
55 | }
56 | return validate(r, tps, nil)
57 | }
58 |
59 | func TwitterAccessToken() *config.Rule {
60 | // define rule
61 | r := config.Rule{
62 | Description: "Twitter Access Token",
63 | RuleID: "twitter-access-token",
64 | Regex: generateSemiGenericRegex([]string{"twitter"}, "[0-9]{15,25}-[a-zA-Z0-9]{20,40}"),
65 | SecretGroup: 1,
66 | Keywords: []string{"twitter"},
67 | }
68 |
69 | // validate
70 | tps := []string{
71 | generateSampleSecret("twitter", secrets.NewSecret("[0-9]{15,25}-[a-zA-Z0-9]{20,40}")),
72 | }
73 | return validate(r, tps, nil)
74 | }
75 |
76 | func TwitterAccessSecret() *config.Rule {
77 | // define rule
78 | r := config.Rule{
79 | Description: "Twitter Access Secret",
80 | RuleID: "twitter-access-secret",
81 | Regex: generateSemiGenericRegex([]string{"twitter"}, alphaNumeric("45")),
82 | SecretGroup: 1,
83 | Keywords: []string{"twitter"},
84 | }
85 |
86 | // validate
87 | tps := []string{
88 | generateSampleSecret("twitter", secrets.NewSecret(alphaNumeric("45"))),
89 | }
90 | return validate(r, tps, nil)
91 | }
92 |
--------------------------------------------------------------------------------
/report/junit.go:
--------------------------------------------------------------------------------
1 | package report
2 |
3 | import (
4 | "encoding/json"
5 | "encoding/xml"
6 | "fmt"
7 | "io"
8 | "strconv"
9 | )
10 |
11 | func writeJunit(findings []Finding, w io.WriteCloser) error {
12 | testSuites := TestSuites{
13 | TestSuites: getTestSuites(findings),
14 | }
15 |
16 | io.WriteString(w, xml.Header)
17 | encoder := xml.NewEncoder(w)
18 | encoder.Indent("", "\t")
19 | return encoder.Encode(testSuites)
20 | }
21 |
22 | func getTestSuites(findings []Finding) []TestSuite {
23 | return []TestSuite{
24 | {
25 | Failures: strconv.Itoa(len(findings)),
26 | Name: "gitleaks",
27 | Tests: strconv.Itoa(len(findings)),
28 | TestCases: getTestCases(findings),
29 | Time: "",
30 | },
31 | }
32 | }
33 |
34 | func getTestCases(findings []Finding) []TestCase {
35 | testCases := []TestCase{}
36 | for _, f := range findings {
37 | testCase := TestCase{
38 | Classname: f.Description,
39 | Failure: getFailure(f),
40 | File: f.File,
41 | Name: getMessage(f),
42 | Time: "",
43 | }
44 | testCases = append(testCases, testCase)
45 | }
46 | return testCases
47 | }
48 |
49 | func getFailure(f Finding) Failure {
50 | return Failure{
51 | Data: getData(f),
52 | Message: getMessage(f),
53 | Type: f.Description,
54 | }
55 | }
56 |
57 | func getData(f Finding) string {
58 | data, err := json.MarshalIndent(f, "", "\t")
59 | if err != nil {
60 | fmt.Println(err)
61 | return ""
62 | }
63 | return string(data)
64 | }
65 |
66 | func getMessage(f Finding) string {
67 | if f.Commit == "" {
68 | return fmt.Sprintf("%s has detected a secret in file %s, line %s.", f.RuleID, f.File, strconv.Itoa(f.StartLine))
69 | }
70 |
71 | return fmt.Sprintf("%s has detected a secret in file %s, line %s, at commit %s.", f.RuleID, f.File, strconv.Itoa(f.StartLine), f.Commit)
72 | }
73 |
74 | type TestSuites struct {
75 | XMLName xml.Name `xml:"testsuites"`
76 | TestSuites []TestSuite
77 | }
78 |
79 | type TestSuite struct {
80 | XMLName xml.Name `xml:"testsuite"`
81 | Failures string `xml:"failures,attr"`
82 | Name string `xml:"name,attr"`
83 | Tests string `xml:"tests,attr"`
84 | TestCases []TestCase `xml:"testcase"`
85 | Time string `xml:"time,attr"`
86 | }
87 |
88 | type TestCase struct {
89 | XMLName xml.Name `xml:"testcase"`
90 | Classname string `xml:"classname,attr"`
91 | Failure Failure `xml:"failure"`
92 | File string `xml:"file,attr"`
93 | Name string `xml:"name,attr"`
94 | Time string `xml:"time,attr"`
95 | }
96 |
97 | type Failure struct {
98 | XMLName xml.Name `xml:"failure"`
99 | Data string `xml:",chardata"`
100 | Message string `xml:"message,attr"`
101 | Type string `xml:"type,attr"`
102 | }
103 |
--------------------------------------------------------------------------------
/testdata/repos/small/dotGit/logs/HEAD:
--------------------------------------------------------------------------------
1 | 0000000000000000000000000000000000000000 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 Zach Rice 1635896329 -0500 clone: from github.com:gitleaks/test.git
2 | 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 Zach Rice 1635896362 -0500 checkout: moving from main to remove-secrets
3 | 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 906335481df9a4b48906c90318b4fac76b67fe73 Zach Rice 1635896426 -0500 commit: load token via env var
4 | 906335481df9a4b48906c90318b4fac76b67fe73 a122b33c6bad3ee54724f52f2caad385ab1982ab Zach Rice 1635896518 -0500 commit: add api package
5 | a122b33c6bad3ee54724f52f2caad385ab1982ab a122b33c6bad3ee54724f52f2caad385ab1982ab Zach Rice 1635896543 -0500 checkout: moving from remove-secrets to api-pkg
6 | a122b33c6bad3ee54724f52f2caad385ab1982ab 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 Zach Rice 1635896644 -0500 checkout: moving from api-pkg to main
7 | 1b6da43b82b22e4eaa10bcf8ee591e91abbfc587 2e1db472eeba53f06c4026ae4566ea022e36598e Zach Rice 1635896648 -0500 pull origin main: Fast-forward
8 | 2e1db472eeba53f06c4026ae4566ea022e36598e 2e1db472eeba53f06c4026ae4566ea022e36598e Zach Rice 1635896716 -0500 checkout: moving from main to foo
9 | 2e1db472eeba53f06c4026ae4566ea022e36598e 491504d5a31946ce75e22554cc34203d8e5ff3ca Zach Rice 1635896886 -0500 commit: adding foo package with secret
10 | 491504d5a31946ce75e22554cc34203d8e5ff3ca f1b58b97808f8e744f6a23c693859df5b5968901 Zach Rice 1635896931 -0500 commit: removing secret from foo package
11 | f1b58b97808f8e744f6a23c693859df5b5968901 2e1db472eeba53f06c4026ae4566ea022e36598e Zach Rice 1635897009 -0500 checkout: moving from foo to main
12 | 2e1db472eeba53f06c4026ae4566ea022e36598e f1b58b97808f8e744f6a23c693859df5b5968901 Zach Rice 1635897062 -0500 checkout: moving from main to foo
13 | f1b58b97808f8e744f6a23c693859df5b5968901 2e1db472eeba53f06c4026ae4566ea022e36598e Zach Rice 1635897508 -0500 checkout: moving from foo to main
14 | 2e1db472eeba53f06c4026ae4566ea022e36598e 4f77f1b3cc39d4b17e4cf4ba0a38f5daed9875b4 Richard Gomez 1681920523 -0400 commit: add .gitleaksignore test
15 | 4f77f1b3cc39d4b17e4cf4ba0a38f5daed9875b4 cada78a9bf157ec05573f19e682d211f811c2e2d Richard Gomez 1681920658 -0400 commit (amend): add .gitleaksignore test
16 | cada78a9bf157ec05573f19e682d211f811c2e2d 2e1db472eeba53f06c4026ae4566ea022e36598e Richard Gomez 1681920730 -0400 reset: moving to HEAD~
17 | 2e1db472eeba53f06c4026ae4566ea022e36598e 53cd7a3c6eb4937f413e3c25e4a9f39289afa69e Richard Gomez 1681920759 -0400 commit: add .gitleaksignore test files
18 |
--------------------------------------------------------------------------------
/report/junit_test.go:
--------------------------------------------------------------------------------
1 | package report
2 |
3 | import (
4 | "os"
5 | "path/filepath"
6 | "strings"
7 | "testing"
8 | )
9 |
10 | func TestWriteJunit(t *testing.T) {
11 | tests := []struct {
12 | findings []Finding
13 | testReportName string
14 | expected string
15 | wantEmpty bool
16 | }{
17 | {
18 | testReportName: "simple",
19 | expected: filepath.Join(expectPath, "report", "junit_simple.xml"),
20 | findings: []Finding{
21 | {
22 |
23 | Description: "Test Rule",
24 | RuleID: "test-rule",
25 | Match: "line containing secret",
26 | Secret: "a secret",
27 | StartLine: 1,
28 | EndLine: 2,
29 | StartColumn: 1,
30 | EndColumn: 2,
31 | Message: "opps",
32 | File: "auth.py",
33 | Commit: "0000000000000000",
34 | Author: "John Doe",
35 | Email: "johndoe@gmail.com",
36 | Date: "10-19-2003",
37 | Tags: []string{},
38 | },
39 | {
40 |
41 | Description: "Test Rule",
42 | RuleID: "test-rule",
43 | Match: "line containing secret",
44 | Secret: "a secret",
45 | StartLine: 2,
46 | EndLine: 3,
47 | StartColumn: 1,
48 | EndColumn: 2,
49 | Message: "",
50 | File: "auth.py",
51 | Commit: "",
52 | Author: "",
53 | Email: "",
54 | Date: "",
55 | Tags: []string{},
56 | },
57 | },
58 | },
59 | {
60 | testReportName: "empty",
61 | expected: filepath.Join(expectPath, "report", "junit_empty.xml"),
62 | findings: []Finding{},
63 | },
64 | }
65 |
66 | for _, test := range tests {
67 | // create tmp file using os.TempDir()
68 | tmpfile, err := os.Create(filepath.Join(t.TempDir(), test.testReportName+".xml"))
69 | if err != nil {
70 | os.Remove(tmpfile.Name())
71 | t.Error(err)
72 | }
73 | err = writeJunit(test.findings, tmpfile)
74 | if err != nil {
75 | os.Remove(tmpfile.Name())
76 | t.Error(err)
77 | }
78 | got, err := os.ReadFile(tmpfile.Name())
79 | if err != nil {
80 | os.Remove(tmpfile.Name())
81 | t.Error(err)
82 | }
83 | if test.wantEmpty {
84 | if len(got) > 0 {
85 | os.Remove(tmpfile.Name())
86 | t.Errorf("Expected empty file, got %s", got)
87 | }
88 | os.Remove(tmpfile.Name())
89 | continue
90 | }
91 | want, err := os.ReadFile(test.expected)
92 | if err != nil {
93 | os.Remove(tmpfile.Name())
94 | t.Error(err)
95 | }
96 |
97 | if string(got) != string(want) {
98 | err = os.WriteFile(strings.Replace(test.expected, ".xml", ".got.xml", 1), got, 0644)
99 | if err != nil {
100 | t.Error(err)
101 | }
102 | t.Errorf("got %s, want %s", string(got), string(want))
103 | }
104 |
105 | os.Remove(tmpfile.Name())
106 | }
107 | }
108 |
--------------------------------------------------------------------------------