Skip to content

Commit 7c0734f

Browse files
optimize the regex pattern in the artifactory access token detector (#4685)
1 parent cbdff3f commit 7c0734f

3 files changed

Lines changed: 52 additions & 49 deletions

File tree

pkg/detectors/artifactory/artifactory.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ var (
2929
defaultClient = detectors.DetectorHttpClientWithNoLocalAddresses
3030

3131
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
32-
keyPat = regexp.MustCompile(`\b([a-zA-Z0-9]{64,73})\b`)
32+
keyPat = regexp.MustCompile(`\b(AKCp[a-zA-Z0-9]{69})\b`)
3333
URLPat = regexp.MustCompile(`\b([A-Za-z0-9][A-Za-z0-9\-]{0,61}[A-Za-z0-9]\.jfrog\.io)`)
3434

3535
invalidHosts = simple.NewCache[struct{}]()
@@ -42,7 +42,7 @@ func (Scanner) CloudEndpoint() string { return "" }
4242
// Keywords are used for efficiently pre-filtering chunks.
4343
// Use identifiers in the secret preferably, or the provider name.
4444
func (s Scanner) Keywords() []string {
45-
return []string{"artifactory", "jfrog.io"}
45+
return []string{"artifactory", "jfrog.io", "AKCp"}
4646
}
4747

4848
func (s Scanner) getClient() *http.Client {

pkg/detectors/artifactory/artifactory_integration_test.go

Lines changed: 9 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,21 @@ import (
77
"context"
88
"fmt"
99
"testing"
10-
"time"
1110

1211
"github.com/google/go-cmp/cmp"
1312
"github.com/google/go-cmp/cmp/cmpopts"
1413
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
1514

16-
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
1715
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
1816
)
1917

2018
func TestArtifactory_FromChunk(t *testing.T) {
21-
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
22-
defer cancel()
23-
testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5")
24-
if err != nil {
25-
t.Fatalf("could not get test secrets from GCP: %s", err)
26-
}
27-
secret := testSecrets.MustGetField("ARTIFACTORY_TOKEN")
28-
inactiveSecret := testSecrets.MustGetField("ARTIFACTORY_INACTIVE")
29-
appURL := testSecrets.MustGetField("ARTIFACTORY_URL")
19+
// NOTE: Using mock secrets because JFrog deprecated AKCp API keys (disabled creation end of Q3 2024).
20+
// Real AKCp keys can no longer be generated, so we cannot test actual verification scenarios.
21+
// These mock keys follow the correct format: AKCp + 69 alphanumeric characters = 73 total
22+
// Reference: https://jfrog.com/help/r/jfrog-release-information/artifactory-7.47.10-cloud-self-hosted
23+
mockSecret := "AKCp5bueTFpfypEqQbGJPp7eHFi28fBivfWczrjbPb9erDff9LbXZbj6UsRExVXA8asWGc9fM"
24+
appURL := "trufflehog.jfrog.io"
3025

3126
type args struct {
3227
ctx context.Context
@@ -41,28 +36,12 @@ func TestArtifactory_FromChunk(t *testing.T) {
4136
wantErr bool
4237
}{
4338
{
44-
name: "found, verified",
39+
name: "found, unverified - mock key (cannot verify deprecated AKCp format)",
4540
s: Scanner{},
4641
args: args{
4742
ctx: context.Background(),
48-
data: []byte(fmt.Sprintf("You can find a artifactory secret %s and domain %s", secret, appURL)),
49-
verify: true,
50-
},
51-
want: []detectors.Result{
52-
{
53-
DetectorType: detectorspb.DetectorType_ArtifactoryAccessToken,
54-
Verified: true,
55-
},
56-
},
57-
wantErr: false,
58-
},
59-
{
60-
name: "found, unverified",
61-
s: Scanner{},
62-
args: args{
63-
ctx: context.Background(),
64-
data: []byte(fmt.Sprintf("You can find a artifactory secret %s but not valid on endpoint %s", inactiveSecret, appURL)), // the secret would satisfy the regex but not pass validation
65-
verify: true,
43+
data: []byte(fmt.Sprintf("You can find a artifactory secret %s and domain %s", mockSecret, appURL)),
44+
verify: false, // Cannot verify - AKCp API keys are deprecated and no valid keys available
6645
},
6746
want: []detectors.Result{
6847
{

pkg/detectors/artifactory/artifactory_test.go

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,24 @@ func TestArtifactory_Pattern(t *testing.T) {
2727
name: "valid pattern",
2828
input: `
2929
[INFO] Sending request to the artifactory API
30-
[DEBUG] Using Key=cmVmdGtuOjAxOjE3ODA1NTFAKEM6S2J2MGswemNzZzhaRnFlVUFAKEk3amlLcGZg
30+
[DEBUG] Using Key=AKCp5e2gMx8TtJNDtrsuPq7Jz24Rqjkjf1d1iiy1GuEjmdsY8ghxFGgehZcK3UGNgy5TxHWdE
3131
[INFO] rwxtOp.jfrog.io
3232
[INFO] Response received: 200 OK
3333
`,
3434
useCloudEndpoint: false,
3535
useFoundEndpoint: true,
36-
want: []string{"cmVmdGtuOjAxOjE3ODA1NTFAKEM6S2J2MGswemNzZzhaRnFlVUFAKEk3amlLcGZgrwxtOp.jfrog.io"},
36+
want: []string{
37+
"AKCp5e2gMx8TtJNDtrsuPq7Jz24Rqjkjf1d1iiy1GuEjmdsY8ghxFGgehZcK3UGNgy5TxHWdE" +
38+
"rwxtOp.jfrog.io",
39+
},
3740
},
3841
{
3942
name: "valid pattern - xml",
4043
input: `
4144
<com.cloudbees.plugins.credentials.impl.StringCredentialsImpl>
4245
<scope>GLOBAL</scope>
4346
<id>{artifactory}</id>
44-
<secret>{AQAAABAAA KUd8GOVfcXnIv1nJ5qmnNzrqkLvseoPRMuwsdDVr9QthonFogtMaoJ3pgtO4eHXC}</secret>
47+
<secret>AKCp8budTFpbypBqQbGJPp7eHFi28fBivfWczrjbPb9erDff9LbXZbj6UsRExVXA8asWGc9fM</secret>
4548
<domain>{HTTPnGQZ79vjWXze.jfrog.io}</domain>
4649
<description>configuration for production</description>
4750
<creationDate>2023-05-18T14:32:10Z</creationDate>
@@ -50,70 +53,91 @@ func TestArtifactory_Pattern(t *testing.T) {
5053
`,
5154
useCloudEndpoint: false,
5255
useFoundEndpoint: true,
53-
want: []string{"KUd8GOVfcXnIv1nJ5qmnNzrqkLvseoPRMuwsdDVr9QthonFogtMaoJ3pgtO4eHXCHTTPnGQZ79vjWXze.jfrog.io"},
56+
want: []string{
57+
"AKCp8budTFpbypBqQbGJPp7eHFi28fBivfWczrjbPb9erDff9LbXZbj6UsRExVXA8asWGc9fM" +
58+
"HTTPnGQZ79vjWXze.jfrog.io",
59+
},
5460
},
5561
{
5662
name: "valid pattern - with cloud endpoints",
5763
input: `
5864
[INFO] Sending request to the artifactory API
59-
[DEBUG] Using Key=cmVmdGtuOjAxOjE3ODA1NTFAKEM6S2J2MGswemNzZzhaRnFlVUFAKEk3amlLcGZg
65+
[DEBUG] Using Key=AKCp5e2gMx8TtJNDtrsuPq7Jz24Rqjkjf1d1iiy1GuEjmdsY8ghxFGgehZcK3UGNgy5TxHWdE
6066
[INFO] Response received: 200 OK
6167
`,
6268
cloudEndpoint: "cloudendpoint.jfrog.io",
6369
useCloudEndpoint: true,
6470
useFoundEndpoint: false,
65-
want: []string{"cmVmdGtuOjAxOjE3ODA1NTFAKEM6S2J2MGswemNzZzhaRnFlVUFAKEk3amlLcGZgcloudendpoint.jfrog.io"},
71+
want: []string{
72+
"AKCp5e2gMx8TtJNDtrsuPq7Jz24Rqjkjf1d1iiy1GuEjmdsY8ghxFGgehZcK3UGNgy5TxHWdE" +
73+
"cloudendpoint.jfrog.io",
74+
},
6675
},
6776
{
6877
name: "valid pattern - with cloud and found endpoints",
6978
input: `
7079
[INFO] Sending request to the artifactory API
71-
[DEBUG] Using Key=cmVmdGtuOjAxOjE3ODA1NTFAKEM6S2J2MGswemNzZzhaRnFlVUFAKEk3amlLcGZg
80+
[DEBUG] Using Key=AKCp5e2gMx8TtJNDtrsuPq7Jz24Rqjkjf1d1iiy1GuEjmdsY8ghxFGgehZcK3UGNgy5TxHWdE
7281
[INFO] rwxtOp.jfrog.io
7382
[INFO] Response received: 200 OK
7483
`,
7584
cloudEndpoint: "cloudendpoint.jfrog.io",
7685
useCloudEndpoint: true,
7786
useFoundEndpoint: true,
7887
want: []string{
79-
"cmVmdGtuOjAxOjE3ODA1NTFAKEM6S2J2MGswemNzZzhaRnFlVUFAKEk3amlLcGZgcloudendpoint.jfrog.io",
80-
"cmVmdGtuOjAxOjE3ODA1NTFAKEM6S2J2MGswemNzZzhaRnFlVUFAKEk3amlLcGZgrwxtOp.jfrog.io",
88+
"AKCp5e2gMx8TtJNDtrsuPq7Jz24Rqjkjf1d1iiy1GuEjmdsY8ghxFGgehZcK3UGNgy5TxHWdE" +
89+
"cloudendpoint.jfrog.io",
90+
"AKCp5e2gMx8TtJNDtrsuPq7Jz24Rqjkjf1d1iiy1GuEjmdsY8ghxFGgehZcK3UGNgy5TxHWdE" +
91+
"rwxtOp.jfrog.io",
8192
},
8293
},
8394
{
8495
name: "valid pattern - with disabled found endpoints",
8596
input: `
8697
[INFO] Sending request to the artifactory API
87-
[DEBUG] Using Key=cmVmdGtuOjAxOjE3ODA1NTFAKEM6S2J2MGswemNzZzhaRnFlVUFAKEk3amlLcGZg
98+
[DEBUG] Using Key=AKCp5e2gMx8TtJNDtrsuPq7Jz24Rqjkjf1d1iiy1GuEjmdsY8ghxFGgehZcK3UGNgy5TxHWdE
8899
[INFO] rwxtOp.jfrog.io
89100
[INFO] Response received: 200 OK
90101
`,
91102
cloudEndpoint: "cloudendpoint.jfrog.io",
92103
useCloudEndpoint: true,
93104
useFoundEndpoint: false,
94105
want: []string{
95-
"cmVmdGtuOjAxOjE3ODA1NTFAKEM6S2J2MGswemNzZzhaRnFlVUFAKEk3amlLcGZgcloudendpoint.jfrog.io",
106+
"AKCp5e2gMx8TtJNDtrsuPq7Jz24Rqjkjf1d1iiy1GuEjmdsY8ghxFGgehZcK3UGNgy5TxHWdE" +
107+
"cloudendpoint.jfrog.io",
96108
},
97109
},
98110
{
99111
name: "valid pattern - with https in configured endpoint",
100112
input: `
101113
[INFO] Sending request to the artifactory API
102-
[DEBUG] Using Key=cmVmdGtuOjAxOjE3ODA1NTFAKEM6S2J2MGswemNzZzhaRnFlVUFAKEk3amlLcGZg
114+
[DEBUG] Using Key=AKCp5e2gMx8TtJNDtrsuPq7Jz24Rqjkjf1d1iiy1GuEjmdsY8ghxFGgehZcK3UGNgy5TxHWdE
103115
[INFO] Response received: 200 OK
104116
`,
105117
cloudEndpoint: "https://cloudendpoint.jfrog.io",
106118
useCloudEndpoint: true,
107119
useFoundEndpoint: false,
108120
want: []string{
109-
"cmVmdGtuOjAxOjE3ODA1NTFAKEM6S2J2MGswemNzZzhaRnFlVUFAKEk3amlLcGZgcloudendpoint.jfrog.io",
121+
"AKCp5e2gMx8TtJNDtrsuPq7Jz24Rqjkjf1d1iiy1GuEjmdsY8ghxFGgehZcK3UGNgy5TxHWdE" +
122+
"cloudendpoint.jfrog.io",
110123
},
111124
},
112125
{
113-
name: "invalid pattern",
126+
name: "invalid pattern - wrong prefix",
127+
input: `
128+
[INFO] Sending request to the artifactory API
129+
[DEBUG] Using Key=XYZp5e2gMx8TtJNDtrsuPq7Jz24Rqjkjf1d1iiy1GuEjmdsY8ghxFGgehZcK3UGNgy5TxHWdE
130+
[INFO] rwxtOp.jfrog.io
131+
[INFO] Response received: 200 OK
132+
`,
133+
useFoundEndpoint: true,
134+
want: nil,
135+
},
136+
{
137+
name: "invalid pattern - too short",
114138
input: `
115139
[INFO] Sending request to the artifactory API
116-
[DEBUG] Using Key=cmVmdGtuOjAxOjEODA_1NTFAKEM6S2J2MGswemNzZzhaRnFlVUFAKEk3amlLcGZg
140+
[DEBUG] Using Key=AKCp5e2gMx8TtJNDtrsuPq7Jz24Rqjkjf1d1iiy1GuEjmd
117141
[INFO] rwxtOp.jfrog.io
118142
[INFO] Response received: 200 OK
119143
`,
@@ -124,10 +148,10 @@ func TestArtifactory_Pattern(t *testing.T) {
124148

125149
for _, test := range tests {
126150
t.Run(test.name, func(t *testing.T) {
127-
// this detector use endpoint customizer interface so we need to enable them based on test case
151+
// this detector uses endpoint customizer interface so we need to enable them based on test case
128152
d.UseFoundEndpoints(test.useFoundEndpoint)
129153
d.UseCloudEndpoint(test.useCloudEndpoint)
130-
// if test case provide cloud endpoint use it
154+
// if the test case provides cloud endpoint, then use it
131155
if test.useCloudEndpoint && test.cloudEndpoint != "" {
132156
d.SetCloudEndpoint(test.cloudEndpoint)
133157
}

0 commit comments

Comments
 (0)