diff --git a/pkg/fanal/secret/builtin-rules.go b/pkg/fanal/secret/builtin-rules.go index 09bf98fd3da8..8c16bd9ba6fa 100644 --- a/pkg/fanal/secret/builtin-rules.go +++ b/pkg/fanal/secret/builtin-rules.go @@ -59,6 +59,7 @@ var ( CategoryNewRelic = types.SecretRuleCategory("NewRelic") CategoryNpm = types.SecretRuleCategory("Npm") CategoryPlanetscale = types.SecretRuleCategory("Planetscale") + CategoryPrivatePackagist = types.SecretRuleCategory("Private Packagist") CategoryPostman = types.SecretRuleCategory("Postman") CategoryPulumi = types.SecretRuleCategory("Pulumi") CategoryRubyGems = types.SecretRuleCategory("RubyGems") @@ -743,6 +744,24 @@ var builtinRules = []Rule{ Regex: MustCompile(`pscale_tkn_(?i)[a-z0-9\-_\.]{43}`), Keywords: []string{"pscale_tkn_"}, }, + { + ID: "private-packagist-user-token", + Category: CategoryPrivatePackagist, + Title: "Private Packagist user token", + Severity: "HIGH", + // https://packagist.com/docs/composer-authentication#token-format + Regex: MustCompile(`packagist_uut_(?i)[a-z0-9]{68}`), + Keywords: []string{"packagist_uut_"}, + }, + { + ID: "private-packagist-organization-token", + Category: CategoryPrivatePackagist, + Title: "Private Packagist organization token", + Severity: "HIGH", + // https://packagist.com/docs/composer-authentication#token-format + Regex: MustCompile(`packagist_o[ru]t_(?i)[a-z0-9]{68}`), + Keywords: []string{"packagist_ort_", "packagist_out_"}, + }, { ID: "postman-api-token", Category: CategoryPostman, diff --git a/pkg/fanal/secret/scanner_test.go b/pkg/fanal/secret/scanner_test.go index f17b1150dd4a..c06542e70017 100644 --- a/pkg/fanal/secret/scanner_test.go +++ b/pkg/fanal/secret/scanner_test.go @@ -668,6 +668,117 @@ func TestSecretScanner(t *testing.T) { }, }, } + wantFindingPrivatePackagistOrgReadToken := types.SecretFinding{ + RuleID: "private-packagist-organization-token", + Category: secret.CategoryPrivatePackagist, + Title: "Private Packagist organization token", + Severity: "HIGH", + StartLine: 1, + EndLine: 1, + Match: "ORG_READ_TOKEN=**********************************************************************************", + Code: types.Code{ + Lines: []types.Line{ + { + Number: 1, + Content: "ORG_READ_TOKEN=**********************************************************************************", + Highlighted: "ORG_READ_TOKEN=**********************************************************************************", + IsCause: true, + FirstCause: true, + LastCause: true, + }, + { + Number: 2, + Content: "ORG_WRITE_TOKEN=**********************************************************************************", + Highlighted: "ORG_WRITE_TOKEN=**********************************************************************************", + IsCause: false, + FirstCause: false, + LastCause: false, + }, + }, + }, + } + wantFindingPrivatePackagistOrgUpdateToken := types.SecretFinding{ + RuleID: "private-packagist-organization-token", + Category: secret.CategoryPrivatePackagist, + Title: "Private Packagist organization token", + Severity: "HIGH", + StartLine: 2, + EndLine: 2, + Match: "ORG_WRITE_TOKEN=**********************************************************************************", + Code: types.Code{ + Lines: []types.Line{ + { + Number: 1, + Content: "ORG_READ_TOKEN=**********************************************************************************", + Highlighted: "ORG_READ_TOKEN=**********************************************************************************", + IsCause: false, + FirstCause: false, + LastCause: false, + }, + { + Number: 2, + Content: "ORG_WRITE_TOKEN=**********************************************************************************", + Highlighted: "ORG_WRITE_TOKEN=**********************************************************************************", + IsCause: true, + FirstCause: true, + LastCause: true, + }, + { + Number: 3, + Content: "USER_TOKEN=**********************************************************************************", + Highlighted: "USER_TOKEN=**********************************************************************************", + IsCause: false, + FirstCause: false, + LastCause: false, + }, + }, + }, + } + wantFindingPrivatePackagistUserToken := types.SecretFinding{ + RuleID: "private-packagist-user-token", + Category: secret.CategoryPrivatePackagist, + Title: "Private Packagist user token", + Severity: "HIGH", + StartLine: 3, + EndLine: 3, + Match: "USER_TOKEN=**********************************************************************************", + Code: types.Code{ + Lines: []types.Line{ + { + Number: 1, + Content: "ORG_READ_TOKEN=**********************************************************************************", + Highlighted: "ORG_READ_TOKEN=**********************************************************************************", + IsCause: false, + FirstCause: false, + LastCause: false, + }, + { + Number: 2, + Content: "ORG_WRITE_TOKEN=**********************************************************************************", + Highlighted: "ORG_WRITE_TOKEN=**********************************************************************************", + IsCause: false, + FirstCause: false, + LastCause: false, + }, + { + Number: 3, + Content: "USER_TOKEN=**********************************************************************************", + Highlighted: "USER_TOKEN=**********************************************************************************", + IsCause: true, + FirstCause: true, + LastCause: true, + }, + { + Number: 4, + Content: "", + Highlighted: "", + IsCause: false, + FirstCause: false, + LastCause: false, + }, + }, + }, + } wantFindingHuggingFace := types.SecretFinding{ RuleID: "hugging-face-access-token", Category: secret.CategoryHuggingFace, @@ -941,6 +1052,19 @@ func TestSecretScanner(t *testing.T) { Findings: []types.SecretFinding{wantFindingJWT}, }, }, + { + name: "find Private Packagist tokens", + configPath: filepath.Join("testdata", "config.yaml"), + inputFilePath: filepath.Join("testdata", "private-packagist.txt"), + want: types.Secret{ + FilePath: filepath.Join("testdata", "private-packagist.txt"), + Findings: []types.SecretFinding{ + wantFindingPrivatePackagistOrgReadToken, + wantFindingPrivatePackagistOrgUpdateToken, + wantFindingPrivatePackagistUserToken, + }, + }, + }, { name: "include when keyword found", configPath: filepath.Join("testdata", "config-happy-keywords.yaml"), diff --git a/pkg/fanal/secret/testdata/private-packagist.txt b/pkg/fanal/secret/testdata/private-packagist.txt new file mode 100644 index 000000000000..772be80e2f06 --- /dev/null +++ b/pkg/fanal/secret/testdata/private-packagist.txt @@ -0,0 +1,3 @@ +ORG_READ_TOKEN=packagist_ort_6675e11a686c692f3f2e3b6ce528c3d122d22d912ea69a20713cdf51714ba710ad74 +ORG_WRITE_TOKEN=packagist_out_d63bd7be741c67ca810f924225b525fa5d20e6e1b316c8bfc0a1b33c68e4861bd5a4 +USER_TOKEN=packagist_uut_02f17e5917451dcdcc2995157e08cac2976a0373097b95d7021ba7a6844437973421