diff --git a/pkg/detectors/kraken/kraken_test.go b/pkg/detectors/kraken/kraken_test.go index 0c4153815eea..b8c3bbe5f2cb 100644 --- a/pkg/detectors/kraken/kraken_test.go +++ b/pkg/detectors/kraken/kraken_test.go @@ -3,7 +3,6 @@ package kraken import ( "context" "fmt" - "strings" "testing" "github.com/google/go-cmp/cmp" @@ -13,10 +12,15 @@ import ( ) var ( - validKeyPattern = "m=MN/0yYJ/5xqpE15JYDJtCFdDF7RDLuiXtTiSF1FU1H9waiub1kgwI= " - invalidKeyPattern = "m=MN/0yYJ/5xqpE15JYDJtCFdDF7RDLuiXtTiSF1FU1H9waiub1kgwI=" - validPrivKeyPattern = "Oe1xUe+sNT7F5SboHSpfCubMhJlAaghB3SZ=NMmkIHTSzWVoF3uTOnxv32cgI+WuEDXYS+z5MvX+q9IUJ1cYo=+ " - invalidPrivKeyPattern = "Oe1xUe+sNT7F5SboHSpfCubMhJlAaghB3SZ=NMmkIHTSzWVoF3uTOnxv32cgI+WuEDXYS+z5MvX+q9IUJ1cYo=+" + // Valid base64-encoded API key (56 chars) with trailing space for the regex boundary. + // Realistic Kraken API keys are base64-encoded, so padding (=) only appears at the end. + validKeyPattern = "mz86TyFYqxUxjCWKbGAYP0PD5qyVBh03M5QFW50vKYb/Sz5Oa9C75e5p " + // Invalid: contains a character (!) not in the allowed set [0-9A-Za-z/+=]. + invalidKeyPattern = "mz86TyFYqxUxjCWKbGAYP0PD5qyVBh03M5QFW50vKY!/Sz5Oa9C75e5p " + // Valid base64-encoded private key (88 chars) with trailing space. + validPrivKeyPattern = "jsam46Au9OZarsbalvCHJ8uEcIVCxDEe+W5jLoeABWj4wzVnCpJw+9qZk1JLhgwa2m8XeqoGuN/OV1jlcvh+Jw== " + // Invalid: contains a character (!) not in the allowed set. + invalidPrivKeyPattern = "jsam46Au9OZarsbalvCHJ8uEcIVCxDEe+W5jLoeABWj4wzVnCpJw+9qZk1JLhgwa2m8XeqoGuN/OV1jlcvh+!w== " keyword = "kraken" ) @@ -29,19 +33,26 @@ func TestKraken_Pattern(t *testing.T) { want []string }{ { - name: "valid pattern - with keyword kraken", - input: fmt.Sprintf("%s '%s' %s '%s'", keyword, validKeyPattern, keyword, validPrivKeyPattern), - want: []string{strings.TrimSpace(validKeyPattern) + strings.TrimSpace(validPrivKeyPattern)}, + name: "valid pattern - realistic API credentials", + input: fmt.Sprintf(`kraken api_key = "%s" +kraken api_secret = "%s"`, + validKeyPattern, validPrivKeyPattern), + want: []string{"mz86TyFYqxUxjCWKbGAYP0PD5qyVBh03M5QFW50vKYb/Sz5Oa9C75e5p" + + "jsam46Au9OZarsbalvCHJ8uEcIVCxDEe+W5jLoeABWj4wzVnCpJw+9qZk1JLhgwa2m8XeqoGuN/OV1jlcvh+Jw=="}, }, { - name: "valid pattern - key out of prefix range", - input: fmt.Sprintf("%s keyword is not close to the real key in the data\n key = '%s' domain: '%s'", keyword, validKeyPattern, validPrivKeyPattern), - want: []string{}, + name: "valid pattern - key out of prefix range", + input: fmt.Sprintf( + "%s keyword is not close to the real key in the data\n key = '%s' domain: '%s'", + keyword, validKeyPattern, validPrivKeyPattern), + want: []string{}, }, { - name: "invalid pattern", - input: fmt.Sprintf("%s key = '%s' secret = '%s'", keyword, invalidKeyPattern, invalidPrivKeyPattern), - want: []string{}, + name: "invalid pattern - bad characters in key and secret", + input: fmt.Sprintf(`kraken api_key = "%s" +kraken api_secret = "%s"`, + invalidKeyPattern, invalidPrivKeyPattern), + want: []string{}, }, } diff --git a/pkg/detectors/netsuite/netsuite_test.go b/pkg/detectors/netsuite/netsuite_test.go index 62e44d4f0425..39017871ee5c 100644 --- a/pkg/detectors/netsuite/netsuite_test.go +++ b/pkg/detectors/netsuite/netsuite_test.go @@ -12,39 +12,50 @@ import ( ) var ( - validConsumerKey = "3WaMEd0KQtHSU7b24HEd79RZzSpMOfMdMUpIaXjq83DbNHVosCVrEVDxKiEQzT15" + // Realistic NetSuite OAuth 1.0 TBA credentials. + // All credential components are 64-char alphanumeric strings, matching [a-zA-Z0-9]{64}. + validConsumerKey = "3WaMEd0KQtHSU7b24HEd79RZzSpMOfMdMUpIaXjq83DbNHVosCVrEVDxKiEQzT15" + validConsumerSecret = "5BZ70LfNshsJkDya1XaD8bMqtPWlOa2o1yKCk0H2DxnjtoaJKIcAw75GdI6zRaRD" + validTokenKey = "KeYcG56ViFDleXPFJuEQ5CAGSJn7o2WDa5iGvLIvVBqZj5rMkaWFmzkp4bveJa74" + validTokenSecret = "GGQUdyYOGDfDImJWCz4Kufk2GevaIDuVv83kIa9zCRuXIDLB4oh2eVDVPmsaSai2" + // NetSuite account IDs: alphanumeric + underscore/hyphen, 6-15 chars. + // TSTDRV prefix is a common NetSuite sandbox convention. + validAccountID = "TSTDRV_1234" + + // Invalid variants: contain '?' which is not in [a-zA-Z0-9]. invalidConsumerKey = "3Wa?Ed0KQtHSU7b24HEd79RZzSpMOfMdMUpIaXjq83DbNHVosCVrEVDxKiEQzT15" - validConsumerSecret = "5BZ70LfNshsJkDya1XaD8bMqtPWlOa2o1yKCk0H2DxnjtoaJKIcAw75GdI6zRaRD" invalidConsumerSecret = "5BZ70LfNshsJkDya?XaD8bMqtPWlOa2o1yKCk0H2DxnjtoaJKIcAw75GdI6zRaRD" - validTokenKey = "KeYcG56ViFDleXPFJuEQ5CAGSJn7o2WDa5iGvLIvVBqZj5rMkaWFmzkp4bveJa74" invalidTokenKey = "KeYcG56ViFDleXPFJuEQ5CAGSJn7o2WD?5iGvLIvVBqZj5rMkaWFmzkp4bveJa74" - validTokenSecret = "GGQUdyYOGDfDImJWCz4Kufk2GevaIDuVv83kIa9zCRuXIDLB4oh2eVDVPmsaSai2" invalidTokenSecret = "GGQUdyYOGDfDImJWCz4Kufk2Ge?aIDuVv83kIa9zCRuXIDLB4oh2eVDVPmsaSai2" - validAccountID = "x1L2_BXo" invalidAccountID = "x1L2?BXo" - keyword = "netsuite" - inputFormat = `%s id - '%s' + + keyword = "netsuite" + // Format that keeps each credential close to its label keyword, matching + // how PrefixRegex works (keyword within 40 chars of the capture group). + inputFormat = `%s id - '%s' consumer - '%s' consumer - '%s' token - '%s' token - '%s'` - outputPair1 = validConsumerKey + validConsumerSecret - outputPair2 = validConsumerSecret + validConsumerKey ) func TestNetsuite_Pattern(t *testing.T) { d := Scanner{} ahoCorasickCore := ahocorasick.NewAhoCorasickCore([]detectors.Detector{d}) + + outputPair1 := validConsumerKey + validConsumerSecret + outputPair2 := validConsumerSecret + validConsumerKey + tests := []struct { name string input string want []string }{ { - name: "valid pattern - with keyword netsuite", + name: "valid pattern - NetSuite TBA credentials", input: fmt.Sprintf(inputFormat, keyword, validAccountID, validConsumerKey, validConsumerSecret, validTokenKey, validTokenSecret), want: []string{outputPair1, outputPair2, outputPair1, outputPair2}, }, { - name: "invalid pattern", + name: "invalid pattern - bad characters in credentials", input: fmt.Sprintf(inputFormat, keyword, invalidAccountID, invalidConsumerKey, invalidConsumerSecret, invalidTokenKey, invalidTokenSecret), want: []string{}, }, diff --git a/pkg/detectors/viewneo/viewneo_test.go b/pkg/detectors/viewneo/viewneo_test.go index bc0aaacb96ed..dc575797519f 100644 --- a/pkg/detectors/viewneo/viewneo_test.go +++ b/pkg/detectors/viewneo/viewneo_test.go @@ -12,9 +12,19 @@ import ( ) var ( - validPattern = "cZZ32f1UDFCqsSP6uUlFyPLrXnGhgunvxc3jRsTO1mygukFtXxmk3sV0Q4PiGW8TstPPagjg8o3N0Jp25RKDJUOssch6rbSBVPc3R5vsRSa7y00CKKuu6T6N.2oV6hZlvOR7Jm3L6PzRLMbPRburA2FUfRlRLktcCbt2nBX1iyAfdMv8JvCjAhUJHT52PhiAT3ca7FNd5q5ZXAkn87LnuQhc5UHyuwD8gcWstOghUHZ20tcz7SjVuKyWZFgODlW2WczXqHKxaNhWYz4.839QXG7zlPYdYNhfbvQZe1zHr6bbbjIQYUs2q5whTtUWm8tCMWaOtm_DEZ_xKO5RUrajoClRedRiGK0fFAMshDSyAROOa7NXcE4WM_AuURDSif51QmcWY5HRITdd7y639Zc2Sz1kkUz-Ks_Aqe7xy0VUOlA8m4w2A7IfQ2iDtUeAlWIz1vsOihDxWeNqvTj5D5JOQcyRCiCfTfDWptrJCkKsMWMcDNRE773ypzQVn3r6VSVC63UqdT5Et5jpS5C1wFMuJDei5w7t4vPBTbodepVLtEkn4HcuyTEt0m-Rh_LIxMShlL56AeC7bVBNvvRpNMi_YT3wTozsXvAXEDS1bdOcD_MLk7-g8L1FfeBZxTnRfLR81idE4qR7ecTeNgfVvuiddb-IGrIAefADZ_Vzl49E3amY7twA7EqX04lBZiVfZsO1R0BlzsCLqQ10fsleLl-S00R01G1Fn2e2gkEkRkwOfxbA7BdTYJwz3s1m7rC2HmQLyT_-h8qE30fGzWkoq7INPSTmJ0EJOPDRY3TZi7axUSDEjZbF8TwXcD3jFDmaAYD3D4E5NSKnILnacXC-kfGZQcP4bcrPbHa4BoNN3kyt" - invalidPattern = "c?Z32f1UDFCqsSP6uUlFyPLrXnGhgunvxc3jRsTO1mygukFtXxmk3sV0Q4PiGW8TstPPagjg8o3N0Jp25RKDJUOssch6rbSBVPc3R5vsRSa7y00CKKuu6T6N.2oV6hZlvOR7Jm3L6PzRLMbPRburA2FUfRlRLktcCbt2nBX1iyAfdMv8JvCjAhUJHT52PhiAT3ca7FNd5q5ZXAkn87LnuQhc5UHyuwD8gcWstOghUHZ20tcz7SjVuKyWZFgODlW2WczXqHKxaNhWYz4.839QXG7zlPYdYNhfbvQZe1zHr6bbbjIQYUs2q5whTtUWm8tCMWaOtm_DEZ_xKO5RUrajoClRedRiGK0fFAMshDSyAROOa7NXcE4WM_AuURDSif51QmcWY5HRITdd7y639Zc2Sz1kkUz-Ks_Aqe7xy0VUOlA8m4w2A7IfQ2iDtUeAlWIz1vsOihDxWeNqvTj5D5JOQcyRCiCfTfDWptrJCkKsMWMcDNRE773ypzQVn3r6VSVC63UqdT5Et5jpS5C1wFMuJDei5w7t4vPBTbodepVLtEkn4HcuyTEt0m-Rh_LIxMShlL56AeC7bVBNvvRpNMi_YT3wTozsXvAXEDS1bdOcD_MLk7-g8L1FfeBZxTnRfLR81idE4qR7ecTeNgfVvuiddb-IGrIAefADZ_Vzl49E3amY7twA7EqX04lBZiVfZsO1R0BlzsCLqQ10fsleLl-S00R01G1Fn2e2gkEkRkwOfxbA7BdTYJwz3s1m7rC2HmQLyT_-h8qE30fGzWkoq7INPSTmJ0EJOPDRY3TZi7axUSDEjZbF8TwXcD3jFDmaAYD3D4E5NSKnILnacXC-kfGZQcP4bcrPbHa4BoNN3kyt" - keyword = "viewneo" + // Realistic JWT-like viewneo bearer token: header.payload.signature + // Matches the detector pattern: [a-z0-9A-Z]{120,300}.[a-z0-9A-Z]{150,300}.[a-z0-9A-Z-_]{600,800} + validPattern = "NbrnTP3fAbnFbmOHnKYaXRvj7uff0LYTH8xIZM1JRcoreogrNwwmq6OLkTkx9NIQ0Wobtqn62tOy4CqpIqK3yn9FfcgMXAdx9G81aSQHqNgAC72qFl41sNLjVHWGaub52Z" + + ".td26fEeVVhDIq2AnHTmt9OBGhnuKoneNo41eoPni6JDWYlgAACTP9gyv1plBArp5B1Id9Z850kEnydx9qWCA79ISjs8JHUdKF0j7elKPoh3pKMzKG5mSoyPstUeC99enq522wjZRL9OaYsP6ihgIqLSmNqE40fAr" + + ".aXOqVJBae45I1Ljit5Y35npgX4ANj73-Z4bVv7Z3ZrYg32o0DtYobmv39rPz-I8h-l9qgBUuMGyKqTa7IUVQxeQvu2UttAzsiA8R5NtJasBLPDCnE5YkfGOv0WRombpE2eAOmSFpPaWXgBl9Hdp2DZQ_M85NUG1J5VEqpOXHOresruIioSTeAIAnA5LS2WyawW29AVIMooBbvRzkDiNbzKbPiDdynuWyW1qfbI_wPXPW8mbjiQKnSXkMVh09gbtR9zTeSOgX2Mh-YwBxGv20g9O1TBU9rZIEBUr21f4pDNyb2lnZv4Sra8fUFWSPFYfoStLEHBVvSrqhmhIWlnEU-HsgmolaIr-JSi3F3KECld8E0zeOdjKt_hWMYoHCC3_tNNV8nnQkleaCMsoTSDR7YOQ7BIP60ektVKshSS8GFfcBuqf91K8_RrcWEP6lLOFfwvQ2vSs80JDuu-zG_QIAmxWOWnJ7CSh-MpkJJf_6Dh1FTGr1-pJy6G43rYA7G0stL_FjIwJIDumSKoXcVTZyQ0-FcGL33CHDUAPjE-vSP222yuTW3ceO6_VBgO3CS5cYsxjHKYkf3Np6jDqqaZ5RkCwLOBq2myEpKK_s-QrKRVdMF5sZMwONRUQ1O5PtCLUfsVliI-H61q" + + // Invalid: character at position 60 replaced with ? which is not in [a-z0-9A-Z], + // breaking the first segment's {120,300} alphanumeric requirement. + invalidPattern = "NbrnTP3fAbnFbmOHnKYaXRvj7uff0LYTH8xIZM1JRcoreogrNwwmq6OLkT?x9NIQ0Wobtqn62tOy4CqpIqK3yn9FfcgMXAdx9G81aSQHqNgAC72qFl41sNLjVHWGaub52Z" + + ".td26fEeVVhDIq2AnHTmt9OBGhnuKoneNo41eoPni6JDWYlgAACTP9gyv1plBArp5B1Id9Z850kEnydx9qWCA79ISjs8JHUdKF0j7elKPoh3pKMzKG5mSoyPstUeC99enq522wjZRL9OaYsP6ihgIqLSmNqE40fAr" + + ".aXOqVJBae45I1Ljit5Y35npgX4ANj73-Z4bVv7Z3ZrYg32o0DtYobmv39rPz-I8h-l9qgBUuMGyKqTa7IUVQxeQvu2UttAzsiA8R5NtJasBLPDCnE5YkfGOv0WRombpE2eAOmSFpPaWXgBl9Hdp2DZQ_M85NUG1J5VEqpOXHOresruIioSTeAIAnA5LS2WyawW29AVIMooBbvRzkDiNbzKbPiDdynuWyW1qfbI_wPXPW8mbjiQKnSXkMVh09gbtR9zTeSOgX2Mh-YwBxGv20g9O1TBU9rZIEBUr21f4pDNyb2lnZv4Sra8fUFWSPFYfoStLEHBVvSrqhmhIWlnEU-HsgmolaIr-JSi3F3KECld8E0zeOdjKt_hWMYoHCC3_tNNV8nnQkleaCMsoTSDR7YOQ7BIP60ektVKshSS8GFfcBuqf91K8_RrcWEP6lLOFfwvQ2vSs80JDuu-zG_QIAmxWOWnJ7CSh-MpkJJf_6Dh1FTGr1-pJy6G43rYA7G0stL_FjIwJIDumSKoXcVTZyQ0-FcGL33CHDUAPjE-vSP222yuTW3ceO6_VBgO3CS5cYsxjHKYkf3Np6jDqqaZ5RkCwLOBq2myEpKK_s-QrKRVdMF5sZMwONRUQ1O5PtCLUfsVliI-H61q" + + keyword = "viewneo" ) func TestViewneo_Pattern(t *testing.T) { @@ -26,8 +36,8 @@ func TestViewneo_Pattern(t *testing.T) { want []string }{ { - name: "valid pattern - with keyword viewneo", - input: fmt.Sprintf("%s token = '%s'", keyword, validPattern), + name: "valid pattern - realistic bearer token in config", + input: fmt.Sprintf("# %s digital signage config\nVIEWNEO_API_TOKEN=\"%s\"", keyword, validPattern), want: []string{validPattern}, }, { @@ -41,8 +51,8 @@ func TestViewneo_Pattern(t *testing.T) { want: []string{}, }, { - name: "invalid pattern", - input: fmt.Sprintf("%s = '%s'", keyword, invalidPattern), + name: "invalid pattern - bad character in token", + input: fmt.Sprintf("%s token = '%s'", keyword, invalidPattern), want: []string{}, }, }