diff --git a/pkg/detectors/github_oauth2/github_oauth2.go b/pkg/detectors/github_oauth2/github_oauth2.go new file mode 100644 index 000000000000..6cd6f27eb18d --- /dev/null +++ b/pkg/detectors/github_oauth2/github_oauth2.go @@ -0,0 +1,81 @@ +package github_oauth2 + +import ( + "context" + "regexp" + "strings" + + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" + "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" + "golang.org/x/oauth2/clientcredentials" + "golang.org/x/oauth2/github" +) + +type Scanner struct{ detectors.EndpointSetter } + +// Ensure the Scanner satisfies the interfaces at compile time. +var _ detectors.Detector = (*Scanner)(nil) + +var ( + // Oauth2 client ID and secret + oauth2ClientIDPat = regexp.MustCompile(detectors.PrefixRegex([]string{"github"}) + `\b([a-f0-9]{20})\b`) + oauth2ClientSecretPat = regexp.MustCompile(detectors.PrefixRegex([]string{"github"}) + `\b([a-f0-9]{40})\b`) +) + +const ( + githubBadVerificationCodeError = "bad_verification_code" +) + +// Keywords are used for efficiently pre-filtering chunks. +// Use identifiers in the secret preferably, or the provider name. +func (s Scanner) Keywords() []string { + return []string{"github"} +} + +// FromData will find and optionally verify GitHub secrets in a given set of bytes. +func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) { + dataStr := string(data) + + // Oauth2 client ID and secret + oauth2ClientIDMatches := oauth2ClientIDPat.FindAllStringSubmatch(dataStr, -1) + oauth2ClientSecretMatches := oauth2ClientSecretPat.FindAllStringSubmatch(dataStr, -1) + + for _, idMatch := range oauth2ClientIDMatches { + if len(idMatch) != 2 { + continue + } + for _, secretMatch := range oauth2ClientSecretMatches { + if len(secretMatch) != 2 { + continue + } + + s1 := detectors.Result{ + DetectorType: detectorspb.DetectorType_GitHubOauth2, + Raw: []byte(idMatch[1]), + RawV2: []byte(idMatch[1] + secretMatch[1]), + } + + config := &clientcredentials.Config{ + ClientID: idMatch[1], + ClientSecret: secretMatch[1], + TokenURL: github.Endpoint.TokenURL, + } + _, err := config.Token(ctx) + if err != nil && strings.Contains(err.Error(), githubBadVerificationCodeError) { + s1.Verified = true + } + + if !s1.Verified && detectors.IsKnownFalsePositive(string(s1.Raw), detectors.DefaultFalsePositives, true) { + continue + } + + results = append(results, s1) + } + } + + return +} + +func (s Scanner) Type() detectorspb.DetectorType { + return detectorspb.DetectorType_GitHubOauth2 +} diff --git a/pkg/engine/defaults.go b/pkg/engine/defaults.go index 6bd24b41149d..89a8f076a212 100644 --- a/pkg/engine/defaults.go +++ b/pkg/engine/defaults.go @@ -556,6 +556,7 @@ import ( "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/satismeterwritekey" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/saucelabs" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/scalewaykey" + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/github_oauth2" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/scalr" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/scrapeowl" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/scraperapi" @@ -1530,6 +1531,7 @@ func DefaultDetectors() []detectors.Detector { dockerhub.Scanner{}, couchbase.Scanner{}, envoyapikey.Scanner{}, + github_oauth2.Scanner{}, } } diff --git a/pkg/pb/detectorspb/detectors.pb.go b/pkg/pb/detectorspb/detectors.pb.go index 04f009281682..c43b0cfdfc79 100644 --- a/pkg/pb/detectorspb/detectors.pb.go +++ b/pkg/pb/detectorspb/detectors.pb.go @@ -995,6 +995,7 @@ const ( DetectorType_Dockerhub DetectorType = 921 DetectorType_TrufflehogEnterprise DetectorType = 922 DetectorType_EnvoyApiKey DetectorType = 923 + DetectorType_GitHubOauth2 DetectorType = 924 ) // Enum value maps for DetectorType. @@ -1920,6 +1921,7 @@ var ( 921: "Dockerhub", 922: "TrufflehogEnterprise", 923: "EnvoyApiKey", + 924: "GitHubOauth2", } DetectorType_value = map[string]int32{ "Alibaba": 0, @@ -2842,6 +2844,7 @@ var ( "Dockerhub": 921, "TrufflehogEnterprise": 922, "EnvoyApiKey": 923, + "GitHubOauth2": 924, } ) @@ -3220,7 +3223,7 @@ var file_detectors_proto_rawDesc = []byte{ 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x4c, 0x41, 0x49, 0x4e, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x42, 0x41, 0x53, 0x45, 0x36, 0x34, 0x10, 0x02, 0x12, - 0x09, 0x0a, 0x05, 0x55, 0x54, 0x46, 0x31, 0x36, 0x10, 0x03, 0x2a, 0xc6, 0x73, 0x0a, 0x0c, 0x44, + 0x09, 0x0a, 0x05, 0x55, 0x54, 0x46, 0x31, 0x36, 0x10, 0x03, 0x2a, 0xd9, 0x73, 0x0a, 0x0c, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x6c, 0x69, 0x62, 0x61, 0x62, 0x61, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x4d, 0x51, 0x50, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x57, 0x53, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x41, @@ -4145,11 +4148,12 @@ var file_detectors_proto_rawDesc = []byte{ 0x68, 0x75, 0x62, 0x10, 0x99, 0x07, 0x12, 0x19, 0x0a, 0x14, 0x54, 0x72, 0x75, 0x66, 0x66, 0x6c, 0x65, 0x68, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x10, 0x9a, 0x07, 0x12, 0x10, 0x0a, 0x0b, 0x45, 0x6e, 0x76, 0x6f, 0x79, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, - 0x10, 0x9b, 0x07, 0x42, 0x3d, 0x5a, 0x3b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x74, 0x72, 0x75, 0x66, 0x66, 0x6c, 0x65, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, - 0x79, 0x2f, 0x74, 0x72, 0x75, 0x66, 0x66, 0x6c, 0x65, 0x68, 0x6f, 0x67, 0x2f, 0x76, 0x33, 0x2f, - 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x62, 0x2f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, - 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x10, 0x9b, 0x07, 0x12, 0x11, 0x0a, 0x0c, 0x47, 0x69, 0x74, 0x48, 0x75, 0x62, 0x4f, 0x61, 0x75, + 0x74, 0x68, 0x32, 0x10, 0x9c, 0x07, 0x42, 0x3d, 0x5a, 0x3b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x72, 0x75, 0x66, 0x66, 0x6c, 0x65, 0x73, 0x65, 0x63, 0x75, + 0x72, 0x69, 0x74, 0x79, 0x2f, 0x74, 0x72, 0x75, 0x66, 0x66, 0x6c, 0x65, 0x68, 0x6f, 0x67, 0x2f, + 0x76, 0x33, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x62, 0x2f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, + 0x6f, 0x72, 0x73, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/proto/detectors.proto b/proto/detectors.proto index 909e5936ce52..a4bc13aaa494 100644 --- a/proto/detectors.proto +++ b/proto/detectors.proto @@ -932,6 +932,7 @@ enum DetectorType { Dockerhub = 921; TrufflehogEnterprise = 922; EnvoyApiKey = 923; + GitHubOauth2 = 924; } message Result {