Browse Source

feat(config): add curl header rule (#1576)

Richard Gomez 1 year ago
parent
commit
83a57244cd
3 changed files with 104 additions and 0 deletions
  1. 1 0
      cmd/generate/config/main.go
  2. 96 0
      cmd/generate/config/rules/curl.go
  3. 7 0
      config/gitleaks.toml

+ 1 - 0
cmd/generate/config/main.go

@@ -55,6 +55,7 @@ func main() {
 		rules.ConfluentSecretKey(),
 		rules.Contentful(),
 		rules.CurlBasicAuth(),
+		rules.CurlHeaderAuth(),
 		rules.Databricks(),
 		rules.DatadogtokenAccessToken(),
 		rules.DefinedNetworkingAPIToken(),

+ 96 - 0
cmd/generate/config/rules/curl.go

@@ -1,6 +1,7 @@
 package rules
 
 import (
+	"fmt"
 	"github.com/zricethezav/gitleaks/v8/cmd/generate/config/utils"
 	"regexp"
 
@@ -75,3 +76,98 @@ nc -u -l 41234`,
 	}
 	return utils.Validate(r, tps, fps)
 }
+
+// https://curl.se/docs/manpage.html#-H
+func CurlHeaderAuth() *config.Rule {
+	// language=regexp
+	authPat := `(?i)(?:Authorization:[ \t]?(?:Basic[ \t]([a-z0-9+/]{8,}={0,3})|(?:Bearer|Token)[ \t]([\w=@.+/-]{8,})|([\w=.+/-]{8,}))|(?:ApiKey|Token|X-API-KEY):[ \t]?([\w=@.+/-]{8,}))`
+	r := config.Rule{
+		RuleID: "curl-auth-header",
+		// TODO: Description: "",
+		Regex: regexp.MustCompile(
+			fmt.Sprintf(`\bcurl\b(?:.*?|.*?(?:[\r\n]{1,2}.*?){1,5})[ \t\n\r](?:-H|--header)[ =](?:"%s"|'%s')(?:\B|\s|\z)`, authPat, authPat)),
+		Entropy:  2.75,
+		Keywords: []string{"curl"},
+		//Allowlists: []config.Allowlist{
+		//	{
+		//		Regexes: []*regexp.Regexp{},
+		//	},
+		//},
+	}
+
+	tps := []string{
+		// Short flag.
+		`curl -H 'Authorization: Basic YnJvd3Nlcjo=' \`, // same line, single quotes
+		// TODO: Handle short flags combined.
+		//`TOKEN=$(curl -sH "Authorization: Basic $BASIC_TOKEN" "https://$REGISTRY/oauth2/token?service=$REGISTRY&scope=repository:$REPO:pull" | jq -r .access_token)`,
+
+		// Long flag.
+		`curl -k -X POST --header "Authorization: Basic djJlNEpYa0NJUHZ5a2FWT0VRXzRqZmZUdDkwYTp2emNBZGFzZWpmlWZiUDc2VUJjNDNNVDExclVh" "https://api-qa.example.com:8243/token" -d "grant_type=client_credentials"`, // same line, double quotes
+
+		// Basic auth.
+		` curl -X POST -H "Content-Type: application/json" \
+ -H "Authorization: Basic MzUzYjMwMmM0NDU3NGY1NjUwNDU2ODdlNTM0ZTdkNmE6Mjg2OTI0Njk3ZTYxNWE2NzJhNjQ2YTQ5MzU0NTY0NmM=" \
+  -d '{"user":{"emailAddress":"test@example.com"}, "password":"password"}' \
+  'http://localhost:8080/oauth2-provider/v1.0/users'`, // different line, double quotes
+		`#curl -X POST \
+#  https://api.mailgun.net/v3/sandbox7dbcabccd4314c123e8b23599d35f5b6.mailgun.org/messages \
+#  -H 'Authorization: Basic YXBpOmtleS1hN2MzNDJ3MzNhNWQxLTU2M2U3MjlwLTZhYjI3YzYzNzM0Ng==' \
+#  -F from='Excited User <mailgun@sandbox7dbc123bccd4314c0aae8b23599d35f5b6.mailgun.org>' \
+#  -F to='joe@example.com' \
+#  -F subject='Hello' \
+#  -F text='Testing some Mailgun awesomness!'`, // different line, single quotes
+
+		// Bearer auth
+		`# curl -X GET "http://localhost:3000/api/cron/status" -H "Authorization: Bearer cfcabd11c7ed9a41b1a3e063c32d5114"`, // same line, double quotes
+		`curl -X PUT -H 'Authorization: Bearer jC+6TUUjCNHcVtAXpcqBCgxnA8r+qD6MatnYaf/+289y7HWpK0BWPyLHv/K4DMN32fufwmeVVjlo8zjgBh8kx3GfS6IqO70w1DVMSCTwX7fhEpiXaxzv0mhSMHDX9Kw63Q6DkavUWUV+MDNhCF5wGQrcdQNncVRF3YkuDHDT/xw2YWyZ/DX8k+gAYiC8gcD8Ueg0ljBVS1IDwPjuGoFPESJVxYr0MDPF2D8Pn2S5rq692U4D9ZLuluS46VA4DK6ig5P7QM5XVXi4V7vXM8qpN/zqneyz+w4PUh6NIX7QG6JczMhYd9maWRWVat5jDdyII63P6sNAy9QZjw+ClW211Q==' -d 'user={"account":"user@domain.com", "roles":["user"]}' http://127.0.0.1:8443/desks/1/occupy`, // same line, single quotes
+		`curl https://api.openai.com/v1/chat/completions \
+  -H "Content-Type: application/json" \
+  -H "Authorization: Bearer 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" \`, // different line, double quotes
+		`curl -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \
+     -H "Authorization: Bearer _FXNljbSRYMWx3TWrd7lgKhLtVZX6iskC8Wcbb4b" \
+     -H "Content-Type:application/json"`,
+
+		// Token auth
+		`curl -H "Authorization: Token 22cb987851bc5659229114c62e60c79abd0d2c08" --request PUT https://appsecclass.report/api/use/635`, // token
+
+		// Nothing
+		`curl -L -H "Authorization:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb25maWRlbmNlIjowLjh9.kvRPfjAhLhtRTczoRgctVGp7KY1QVH3UBZM-gM0x8ec" service1.local -> correct jwt `, // no prefix
+
+		// Non-authorization headers.
+		`curl -XPOST http://localhost:8080/api/tasks -H "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" -H "Token: 3fea6af1349166ea" -d "content=hello-curl"`, // token
+		`curl -X GET \
+     -H "apikey: c4ed6c21-9dd5-4a05-8e3f-c56d1151cce8" \
+     -H "Accept: application/json" \`, // API Key placeholder
+	}
+	fps := []string{
+		// Placeholders
+		`curl https://example.com/micropub -d h=entry -d "content=Hello World" -H "Authorization: Bearer XXXXXXXXXXXX"`,
+		`curl -X POST https://accounts.spotify.com/api/token -d grant_type=client_credentials --header "Authorization: Basic ..."`,
+		`curl \
+  -H "Authorization: Bearer <Openverse API token>" \
+  "https://api.openverse.org/v1/audio/?q=test"`,
+		`curl -v -v -v -X POST https://domain/api/v1/authentication/sso/login-url/ \
+  -H 'Content-Type: application/json' \
+  -H "Authorization: Token **********" \
+  -d '{"username": "test", "next": "/luna/"}'`,
+
+		// Variables
+		`curl -XPOST http://localhost:8080/api/token -H "Authorization: basic {base64(email:password[\n])}" => token`, // same line, invalid base64
+		`curl -X GET \
+     -H "apikey: $API_KEY" \
+     -H "Accept: $FORMAT" \
+"$API_URL/rest/v1/stats_derniere_labellisation"`, // API Key placeholder
+		`$ curl -X POST "http://localhost:8000/v1/chat/completions" \
+    -H "Content-Type: application/json" \
+    -H "Authorization: Bearer $API_KEY" \
+    -d '{
+        "model": "chatglm3-6b-32k",
+        "messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "Hello!"}]
+    }'`, // different line, placeholder
+		`curl -X GET -H "Content-Type: application/json" -H "Authorization: Bearer $(gcloud auth print-access-token)" https://workflowexecutions.googleapis.com/v1/projects/244283331594/locations/us-central1/workflows/sample-workflow/executions/43c925aa-514a-44c1-a0a4-a9f8f26fd2cb/callbacks/1705791f-d446-4e92-a6d0-a13622422e80_31864a51-8c13-4b03-ad4d-945cdc8d0631`, // script
+
+		// Not valid BASIC
+		`curl -X POST -H "Content-Type: application/json" -H "Authorization: Basic eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb25maWRlbmNlIjowLjh9.kvRPfjAhLhtRTczoRgctVGp7KY1QVH3UBZM-gM0x8ec" \`,
+	}
+	return utils.Validate(r, tps, fps)
+}

+ 7 - 0
config/gitleaks.toml

@@ -251,6 +251,13 @@ description = "Discovered a Contentful delivery API token, posing a risk to cont
 regex = '''(?i)(?:contentful)(?:[0-9a-z\-_\t .]{0,20})(?:[\s|']|[\s|"]){0,3}(?:=|>|:{1,3}=|\|\|:|<=|=>|:|\?=)(?:'|\"|\s|=|\x60){0,5}([a-z0-9=_\-]{43})(?:['|\"|\n|\r|\s|\x60|;]|$)'''
 keywords = ["contentful"]
 
+[[rules]]
+id = "curl-auth-header"
+description = ""
+regex = '''\bcurl\b(?:.*?|.*?(?:[\r\n]{1,2}.*?){1,5})[ \t\n\r](?:-H|--header)[ =](?:"(?i)(?:Authorization:[ \t]?(?:Basic[ \t]([a-z0-9+/]{8,}={0,3})|(?:Bearer|Token)[ \t]([\w=@.+/-]{8,})|([\w=.+/-]{8,}))|(?:ApiKey|Token|X-API-KEY):[ \t]?([\w=@.+/-]{8,}))"|'(?i)(?:Authorization:[ \t]?(?:Basic[ \t]([a-z0-9+/]{8,}={0,3})|(?:Bearer|Token)[ \t]([\w=@.+/-]{8,})|([\w=.+/-]{8,}))|(?:ApiKey|Token|X-API-KEY):[ \t]?([\w=@.+/-]{8,}))')(?:\B|\s|\z)'''
+entropy = 2.75
+keywords = ["curl"]
+
 [[rules]]
 id = "curl-auth-user"
 description = ""