Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 59 additions & 9 deletions ee/tables/secretscan/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,14 +231,23 @@ func (t *Table) findingsToRows(ctx context.Context, argon2idSalts []string, find

keyNamesInFindings := findingsToKeyNames(findings)

// Just for logging purposes -- we're curious how frequently we detect these
encryptedJwtCount := 0
// Just for logging purposes -- we're curious how frequently we detect false positives
encryptedJwtFalsePositiveCount := 0
emptyVariableFalsePositiveCount := 0
for idx, f := range findings {
// Encrypted data is a false positive -- we should not count these as secrets.
if isEncryptedJWTFamilyValue(f) {
encryptedJwtCount += 1
continue
// We sometimes see false positives under the "generic-api-key" rule.
// Check for these.
if f.RuleID == "generic-api-key" {
if isEncryptedJWTFamilyValue(f) {
encryptedJwtFalsePositiveCount += 1
continue
}
if isEmptyVariable(f) {
emptyVariableFalsePositiveCount += 1
continue
}
}

// Get the hash of this secret. If there's an error, log it, and allow the rest of the data to be returned.
// But note that there's an error, since it's probably a salting issue, and we don't need to log a billion times.
var argon2idHash string
Expand Down Expand Up @@ -271,10 +280,11 @@ func (t *Table) findingsToRows(ctx context.Context, argon2idSalts []string, find
results = append(results, row)
}

if encryptedJwtCount > 0 {
if encryptedJwtFalsePositiveCount > 0 || emptyVariableFalsePositiveCount > 0 {
t.slogger.Log(ctx, slog.LevelInfo,
"detected and skipped encrypted JWT family values",
"jwt_family_count", encryptedJwtCount,
"detected and skipped false positive generic-api-key findings",
"jwt_family_count", encryptedJwtFalsePositiveCount,
"empty_variable", emptyVariableFalsePositiveCount,
)
}

Expand Down Expand Up @@ -323,6 +333,46 @@ func isEncryptedJWTFamilyValue(finding report.Finding) bool {
return false
}

// emptyVariableRegexp matches strings that start with a word char,
// contain only word chars and underscores or hyphens, and end with a
// singular equal sign -- for example, `MY_ENV_VAR=`.
var emptyVariableRegexp = regexp.MustCompile(`^\w[\w-]*=$`)

// isEmptyVariable inspects the given finding to determine if it is actually
// an empty variable name instead.
func isEmptyVariable(finding report.Finding) bool {
// This type of false positive typically has an entropy score around 3,
// so we exclude higher-entropy values right off the bat.
if finding.Entropy >= 4 {
return false
}

// Next, check for our regex match.
if !emptyVariableRegexp.MatchString(finding.Secret) {
return false
}

// We expect that this "secret" would be at the start of a line, with either nothing
// or whitespace in front of it. However, sometimes our finding.Line will contain
// multiple lines -- in this case, it looks like "\nMY_ENV_VAR1=\nMY_ENV_VAR2=".
// So first we isolate the actual line we're looking at, then check to see if there's
Comment on lines +357 to +358
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might be able to use the column start field.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried that and it worked in practice with the examples I'm looking at (restricting to finding.StartColumn == 2), but I wanted to cover the case in the tab before empty variable test too.

// anything besides whitespace in front of it.
lines := strings.Split(strings.ReplaceAll(finding.Line, "\r\n", "\n"), "\n")
var lineWithSecret string
for _, line := range lines {
if strings.Contains(line, finding.Secret) {
lineWithSecret = line
break
}
}
if lineWithSecret == "" {
return false
}
before, _, _ := strings.Cut(lineWithSecret, finding.Secret)
beforeTrimmed := strings.TrimSpace(before)
return beforeTrimmed == ""
}

// findingsToKeyNames attempts to extract the key names (eg: in an .env file) to help understand the context
// of the discovered secret. Because of the multitude of possible ways people can stash secrets, and the myriad of
// secret types, this is very hard to get right. So instead, we aim to solve the simple case, and ignore the rest.
Expand Down
174 changes: 132 additions & 42 deletions ee/tables/secretscan/table_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/zricethezav/gitleaks/v8/detect"
"github.com/zricethezav/gitleaks/v8/report"
"github.com/zricethezav/gitleaks/v8/sources"
)

func TestSecretScan(t *testing.T) {
Expand Down Expand Up @@ -370,6 +372,136 @@ func extractTestData(tb testing.TB) string {
return filepath.Join(tempDir, "test_data")
}

func Test_isEncryptedJWTFamilyValue(t *testing.T) {
t.Parallel()

for _, tt := range []struct {
testCaseName string
encryptedJWT string
expectedIsEncryptedJWT bool
}{
{
testCaseName: "encrypted JWK, Appendix C RFC example", // https://datatracker.ietf.org/doc/html/rfc7517#appendix-C
encryptedJWT: "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJwMnMiOiIyV0NUY0paMVJ2ZF9DSnVKcmlwUTF3IiwicDJjIjo0MDk2LCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiY3R5IjoiandrK2pzb24ifQ.TrqXOwuNUfDV9VPTNbyGvEJ9JMjefAVn-TR1uIxR9p6hsRQh9Tk7BA.Ye9j1qs22DmRSAddIh-VnA.AwhB8lxrlKjFn02LGWEqg27H4Tg9fyZAbFv3p5ZicHpj64QyHC44qqlZ3JEmnZTgQowIqZJ13jbyHB8LgePiqUJ1hf6M2HPLgzw8L-mEeQ0jvDUTrE07NtOerBk8bwBQyZ6g0kQ3DEOIglfYxV8-FJvNBYwbqN1Bck6d_i7OtjSHV-8DIrp-3JcRIe05YKy3Oi34Z_GOiAc1EK21B11c_AE11PII_wvvtRiUiG8YofQXakWd1_O98Kap-UgmyWPfreUJ3lJPnbD4Ve95owEfMGLOPflo2MnjaTDCwQokoJ_xplQ2vNPz8iguLcHBoKllyQFJL2mOWBwqhBo9Oj-O800as5mmLsvQMTflIrIEbbTMzHMBZ8EFW9fWwwFu0DWQJGkMNhmBZQ-3lvqTc-M6-gWA6D8PDhONfP2Oib2HGizwG1iEaX8GRyUpfLuljCLIe1DkGOewhKuKkZh04DKNM5Nbugf2atmU9OP0Ldx5peCUtRG1gMVl7Qup5ZXHTjgPDr5b2N731UooCGAUqHdgGhg0JVJ_ObCTdjsH4CF1SJsdUhrXvYx3HJh2Xd7CwJRzU_3Y1GxYU6-s3GFPbirfqqEipJDBTHpcoCmyrwYjYHFgnlqBZRotRrS95g8F95bRXqsaDY7UgQGwBQBwy665d0zpvTasvfXf_c0MWAl-neFaKOW_Px6g4EUDjG1GWSXV9cLStLw_0ovdApDIFLHYHePyagyHjouQUuGiq7BsYwYrwaF06tgB8hV8omLNfMEmDPJaZUzMuHw6tBDwGkzD-tS_ub9hxrpJ4UsOWnt5rGUyoN2N_c1-TQlXxm5oto14MxnoAyBQBpwIEgSH3Y4ZhwKBhHPjSo0cdwuNdYbGPpb-YUvF-2NZzODiQ1OvWQBRHSbPWYz_xbGkgD504LRtqRwCO7CC_CyyURi1sEssPVsMJRX_U4LFEOc82TiDdqjKOjRUfKK5rqLi8nBE9soQ0DSaOoFQZiGrBrqxDsNYiAYAmxxkos-i3nX4qtByVx85sCE5U_0MqG7COxZWMOPEFrDaepUV-cOyrvoUIng8i8ljKBKxETY2BgPegKBYCxsAUcAkKamSCC9AiBxA0UOHyhTqtlvMksO7AEhNC2-YzPyx1FkhMoS4LLe6E_pFsMlmjA6P1NSge9C5G5tETYXGAn6b1xZbHtmwrPScro9LWhVmAaA7_bxYObnFUxgWtK4vzzQBjZJ36UTk4OTB-JvKWgfVWCFsaw5WCHj6Oo4jpO7d2yN7WMfAj2hTEabz9wumQ0TMhBduZ-QON3pYObSy7TSC1vVme0NJrwF_cJRehKTFmdlXGVldPxZCplr7ZQqRQhF8JP-l4mEQVnCaWGn9ONHlemczGOS-A-wwtnmwjIB1V_vgJRf4FdpV-4hUk4-QLpu3-1lWFxrtZKcggq3tWTduRo5_QebQbUUT_VSCgsFcOmyWKoj56lbxthN19hq1XGWbLGfrrR6MWh23vk01zn8FVwi7uFwEnRYSafsnWLa1Z5TpBj9GvAdl2H9NHwzpB5NqHpZNkQ3NMDj13Fn8fzO0JB83Etbm_tnFQfcb13X3bJ15Cz-Ww1MGhvIpGGnMBT_ADp9xSIyAM9dQ1yeVXk-AIgWBUlN5uyWSGyCxp0cJwx7HxM38z0UIeBu-MytL-eqndM7LxytsVzCbjOTSVRmhYEMIzUAnS1gs7uMQAGRdgRIElTJESGMjb_4bZq9s6Ve1LKkSi0_QDsrABaLe55UY0zF4ZSfOV5PMyPtocwV_dcNPlxLgNAD1BFX_Z9kAdMZQW6fAmsfFle0zAoMe4l9pMESH0JB4sJGdCKtQXj1cXNydDYozF7l8H00BV_Er7zd6VtIw0MxwkFCTatsv_R-GsBCH218RgVPsfYhwVuT8R4HarpzsDBufC4r8_c8fc9Z278sQ081jFjOja6L2x0N_ImzFNXU6xwO-Ska-QeuvYZ3X_L31ZOX4Llp-7QSfgDoHnOxFv1Xws-D5mDHD3zxOup2b2TppdKTZb9eW2vxUVviM8OI9atBfPKMGAOv9omA-6vv5IxUH0-lWMiHLQ_g8vnswp-Jav0c4t6URVUzujNOoNd_CBGGVnHiJTCHl88LQxsqLHHIu4Fz-U2SGnlxGTj0-ihit2ELGRv4vO8E1BosTmf0cx3qgG0Pq0eOLBDIHsrdZ_CCAiTc0HVkMbyq1M6qEhM-q5P6y1QCIrwg.0HFmhOzsQ98nNWJjIHkR7A",
expectedIsEncryptedJWT: true,
},
{
testCaseName: "JWE, Appendix A.1 example", // https://datatracker.ietf.org/doc/html/rfc7516#appendix-A.1
encryptedJWT: "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGeipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDbSv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaVmqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je81860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi6UklfCpIMfIjf7iGdXKHzg.48V1_ALb6US04U3b.5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiSdiwkIr3ajwQzaBtQD_A.XFBoMYUZodetZdvTiFvSkQ",
expectedIsEncryptedJWT: true,
},
{
testCaseName: "JWE, Appendix A.2 example", // https://datatracker.ietf.org/doc/html/rfc7516#appendix-A.2
encryptedJWT: "eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.UGhIOguC7IuEvf_NPVaXsGMoLOmwvc1GyqlIKOK1nN94nHPoltGRhWhw7Zx0-kFm1NJn8LE9XShH59_i8J0PH5ZZyNfGy2xGdULU7sHNF6Gp2vPLgNZ__deLKxGHZ7PcHALUzoOegEI-8E66jX2E4zyJKx-YxzZIItRzC5hlRirb6Y5Cl_p-ko3YvkkysZIFNPccxRU7qve1WYPxqbb2Yw8kZqa2rMWI5ng8OtvzlV7elprCbuPhcCdZ6XDP0_F8rkXds2vE4X-ncOIM8hAYHHi29NX0mcKiRaD0-D-ljQTP-cFPgwCp6X-nZZd9OHBv-B3oWh2TbqmScqXMR4gp_A.AxY8DCtDaGlsbGljb3RoZQ.KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY.9hH0vgRfYgPnAHOd8stkvw",
expectedIsEncryptedJWT: true,
},
{
testCaseName: "JWE, Appendix A.3 example", // https://datatracker.ietf.org/doc/html/rfc7516#appendix-A.3
encryptedJWT: "eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.6KB707dM9YTIgHtLvtgWQ8mKwboJW3of9locizkDTHzBC2IlrT1oOQ.AxY8DCtDaGlsbGljb3RoZQ.KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY.U0m_YmjN04DJvceFICbCVQ",
expectedIsEncryptedJWT: true,
},
{
testCaseName: "unencrypted JWT",
encryptedJWT: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyfQ.gog41qgIIHkH2h-83gwRq5-NYOciZ4DgN4ulHFSkh6k",
expectedIsEncryptedJWT: false,
},
} {
t.Run(tt.testCaseName, func(t *testing.T) {
t.Parallel()

require.Equal(t, tt.expectedIsEncryptedJWT, isEncryptedJWTFamilyValue(report.Finding{Secret: tt.encryptedJWT}))
})
}
}

func Test_isEmptyVariable(t *testing.T) {
t.Parallel()

// Set up one table for use for all test cases
tbl := &Table{
slogger: multislogger.NewNopLogger(),
}
cfg, err := newDefaultConfig()
require.NoError(t, err)
tbl.defaultConfig = &cfg

for _, tt := range []struct {
testCaseName string
rawData string
expectedReturn bool
}{
{
testCaseName: "underscore",
rawData: `
123_S3_CREDS=
123_S3_IP_REGION=
`,
expectedReturn: true,
},
{
testCaseName: "hyphen",
rawData: `
123-S3-CREDS=
123-S3-IP-REGION=
`,
expectedReturn: true,
},
{
testCaseName: "alphanumeric",
rawData: `
123S3CREDS=
123S3IPREGION=
`,
expectedReturn: true,
},
{
testCaseName: "tab before empty variable",
rawData: `
123_S3_CREDS=
123_S3_IP_REGION=
`,
expectedReturn: true,
},
{
testCaseName: "non-empty",
rawData: `
123_S3_CREDS=9b065cc5-cf2e-4b3f-9a20-3422e060807a
123_S3_IP_REGION=52b22b1e-2178-4a1e-bbba-50d0160ffab3
`,
expectedReturn: false,
},
{
testCaseName: "high entropy", // 4.19 entropy
rawData: `
375E6860-39D4-11F1-B4AC-0800200C9A66-375E6861-39D4-11F1-B4AC-0800200C9A66_123_S3_CREDS=
4DE613D1-39D4-11F1-B4AC-0800200C9A66_123_S3_IP_REGION_4DE613D0-39D4-11F1-B4AC-0800200C9A66=
`,
expectedReturn: false,
},
} {
t.Run(tt.testCaseName, func(t *testing.T) {
t.Parallel()

detector := detect.NewDetector(*tbl.defaultConfig)
fileSource := &sources.File{
Content: strings.NewReader(tt.rawData),
Config: &detector.Config,
}

findings, err := detector.DetectSource(t.Context(), fileSource)
require.NoError(t, err)
require.Greater(t, len(findings), 0)

for _, finding := range findings {
// Make sure the test finding we generated is the type we expected
require.Equal(t, "generic-api-key", finding.RuleID)
// Confirm that isEmptyVariable classifies the finding appropriately
require.Equal(t, tt.expectedReturn, isEmptyVariable(finding))
}
})
}
}

// Benchmarks

func BenchmarkSecretScanDirectory(b *testing.B) {
Expand Down Expand Up @@ -417,48 +549,6 @@ func BenchmarkSecretScanFile(b *testing.B) {
ci.ReportNonGolangMemoryUsage(b, baselineStats)
}

func Test_isEncryptedJWTFamilyValue(t *testing.T) {
t.Parallel()

for _, tt := range []struct {
testCaseName string
encryptedJWT string
expectedIsEncryptedJWT bool
}{
{
testCaseName: "encrypted JWK, Appendix C RFC example", // https://datatracker.ietf.org/doc/html/rfc7517#appendix-C
encryptedJWT: "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJwMnMiOiIyV0NUY0paMVJ2ZF9DSnVKcmlwUTF3IiwicDJjIjo0MDk2LCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiY3R5IjoiandrK2pzb24ifQ.TrqXOwuNUfDV9VPTNbyGvEJ9JMjefAVn-TR1uIxR9p6hsRQh9Tk7BA.Ye9j1qs22DmRSAddIh-VnA.AwhB8lxrlKjFn02LGWEqg27H4Tg9fyZAbFv3p5ZicHpj64QyHC44qqlZ3JEmnZTgQowIqZJ13jbyHB8LgePiqUJ1hf6M2HPLgzw8L-mEeQ0jvDUTrE07NtOerBk8bwBQyZ6g0kQ3DEOIglfYxV8-FJvNBYwbqN1Bck6d_i7OtjSHV-8DIrp-3JcRIe05YKy3Oi34Z_GOiAc1EK21B11c_AE11PII_wvvtRiUiG8YofQXakWd1_O98Kap-UgmyWPfreUJ3lJPnbD4Ve95owEfMGLOPflo2MnjaTDCwQokoJ_xplQ2vNPz8iguLcHBoKllyQFJL2mOWBwqhBo9Oj-O800as5mmLsvQMTflIrIEbbTMzHMBZ8EFW9fWwwFu0DWQJGkMNhmBZQ-3lvqTc-M6-gWA6D8PDhONfP2Oib2HGizwG1iEaX8GRyUpfLuljCLIe1DkGOewhKuKkZh04DKNM5Nbugf2atmU9OP0Ldx5peCUtRG1gMVl7Qup5ZXHTjgPDr5b2N731UooCGAUqHdgGhg0JVJ_ObCTdjsH4CF1SJsdUhrXvYx3HJh2Xd7CwJRzU_3Y1GxYU6-s3GFPbirfqqEipJDBTHpcoCmyrwYjYHFgnlqBZRotRrS95g8F95bRXqsaDY7UgQGwBQBwy665d0zpvTasvfXf_c0MWAl-neFaKOW_Px6g4EUDjG1GWSXV9cLStLw_0ovdApDIFLHYHePyagyHjouQUuGiq7BsYwYrwaF06tgB8hV8omLNfMEmDPJaZUzMuHw6tBDwGkzD-tS_ub9hxrpJ4UsOWnt5rGUyoN2N_c1-TQlXxm5oto14MxnoAyBQBpwIEgSH3Y4ZhwKBhHPjSo0cdwuNdYbGPpb-YUvF-2NZzODiQ1OvWQBRHSbPWYz_xbGkgD504LRtqRwCO7CC_CyyURi1sEssPVsMJRX_U4LFEOc82TiDdqjKOjRUfKK5rqLi8nBE9soQ0DSaOoFQZiGrBrqxDsNYiAYAmxxkos-i3nX4qtByVx85sCE5U_0MqG7COxZWMOPEFrDaepUV-cOyrvoUIng8i8ljKBKxETY2BgPegKBYCxsAUcAkKamSCC9AiBxA0UOHyhTqtlvMksO7AEhNC2-YzPyx1FkhMoS4LLe6E_pFsMlmjA6P1NSge9C5G5tETYXGAn6b1xZbHtmwrPScro9LWhVmAaA7_bxYObnFUxgWtK4vzzQBjZJ36UTk4OTB-JvKWgfVWCFsaw5WCHj6Oo4jpO7d2yN7WMfAj2hTEabz9wumQ0TMhBduZ-QON3pYObSy7TSC1vVme0NJrwF_cJRehKTFmdlXGVldPxZCplr7ZQqRQhF8JP-l4mEQVnCaWGn9ONHlemczGOS-A-wwtnmwjIB1V_vgJRf4FdpV-4hUk4-QLpu3-1lWFxrtZKcggq3tWTduRo5_QebQbUUT_VSCgsFcOmyWKoj56lbxthN19hq1XGWbLGfrrR6MWh23vk01zn8FVwi7uFwEnRYSafsnWLa1Z5TpBj9GvAdl2H9NHwzpB5NqHpZNkQ3NMDj13Fn8fzO0JB83Etbm_tnFQfcb13X3bJ15Cz-Ww1MGhvIpGGnMBT_ADp9xSIyAM9dQ1yeVXk-AIgWBUlN5uyWSGyCxp0cJwx7HxM38z0UIeBu-MytL-eqndM7LxytsVzCbjOTSVRmhYEMIzUAnS1gs7uMQAGRdgRIElTJESGMjb_4bZq9s6Ve1LKkSi0_QDsrABaLe55UY0zF4ZSfOV5PMyPtocwV_dcNPlxLgNAD1BFX_Z9kAdMZQW6fAmsfFle0zAoMe4l9pMESH0JB4sJGdCKtQXj1cXNydDYozF7l8H00BV_Er7zd6VtIw0MxwkFCTatsv_R-GsBCH218RgVPsfYhwVuT8R4HarpzsDBufC4r8_c8fc9Z278sQ081jFjOja6L2x0N_ImzFNXU6xwO-Ska-QeuvYZ3X_L31ZOX4Llp-7QSfgDoHnOxFv1Xws-D5mDHD3zxOup2b2TppdKTZb9eW2vxUVviM8OI9atBfPKMGAOv9omA-6vv5IxUH0-lWMiHLQ_g8vnswp-Jav0c4t6URVUzujNOoNd_CBGGVnHiJTCHl88LQxsqLHHIu4Fz-U2SGnlxGTj0-ihit2ELGRv4vO8E1BosTmf0cx3qgG0Pq0eOLBDIHsrdZ_CCAiTc0HVkMbyq1M6qEhM-q5P6y1QCIrwg.0HFmhOzsQ98nNWJjIHkR7A",
expectedIsEncryptedJWT: true,
},
{
testCaseName: "JWE, Appendix A.1 example", // https://datatracker.ietf.org/doc/html/rfc7516#appendix-A.1
encryptedJWT: "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGeipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDbSv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaVmqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je81860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi6UklfCpIMfIjf7iGdXKHzg.48V1_ALb6US04U3b.5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiSdiwkIr3ajwQzaBtQD_A.XFBoMYUZodetZdvTiFvSkQ",
expectedIsEncryptedJWT: true,
},
{
testCaseName: "JWE, Appendix A.2 example", // https://datatracker.ietf.org/doc/html/rfc7516#appendix-A.2
encryptedJWT: "eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.UGhIOguC7IuEvf_NPVaXsGMoLOmwvc1GyqlIKOK1nN94nHPoltGRhWhw7Zx0-kFm1NJn8LE9XShH59_i8J0PH5ZZyNfGy2xGdULU7sHNF6Gp2vPLgNZ__deLKxGHZ7PcHALUzoOegEI-8E66jX2E4zyJKx-YxzZIItRzC5hlRirb6Y5Cl_p-ko3YvkkysZIFNPccxRU7qve1WYPxqbb2Yw8kZqa2rMWI5ng8OtvzlV7elprCbuPhcCdZ6XDP0_F8rkXds2vE4X-ncOIM8hAYHHi29NX0mcKiRaD0-D-ljQTP-cFPgwCp6X-nZZd9OHBv-B3oWh2TbqmScqXMR4gp_A.AxY8DCtDaGlsbGljb3RoZQ.KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY.9hH0vgRfYgPnAHOd8stkvw",
expectedIsEncryptedJWT: true,
},
{
testCaseName: "JWE, Appendix A.3 example", // https://datatracker.ietf.org/doc/html/rfc7516#appendix-A.3
encryptedJWT: "eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.6KB707dM9YTIgHtLvtgWQ8mKwboJW3of9locizkDTHzBC2IlrT1oOQ.AxY8DCtDaGlsbGljb3RoZQ.KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY.U0m_YmjN04DJvceFICbCVQ",
expectedIsEncryptedJWT: true,
},
{
testCaseName: "unencrypted JWT",
encryptedJWT: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyfQ.gog41qgIIHkH2h-83gwRq5-NYOciZ4DgN4ulHFSkh6k",
expectedIsEncryptedJWT: false,
},
} {
t.Run(tt.testCaseName, func(t *testing.T) {
t.Parallel()

require.Equal(t, tt.expectedIsEncryptedJWT, isEncryptedJWTFamilyValue(report.Finding{Secret: tt.encryptedJWT}))
})
}
}

func BenchmarkSecretScanRawData(b *testing.B) {
// Use single-line data to avoid JSON escaping issues in the request builder
rawData := `slack_bot_token: xoxb-9876543210-9876543210-zyxwvutsrqponmlk`
Expand Down
Loading