@@ -2,6 +2,7 @@ package anthropic
2
2
3
3
import (
4
4
"context"
5
+ "errors"
5
6
"fmt"
6
7
"net/http"
7
8
"strings"
@@ -23,40 +24,60 @@ var _ detectors.Detector = (*Scanner)(nil)
23
24
var (
24
25
defaultClient = common .SaneHttpClient ()
25
26
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
26
- keyPat = regexp .MustCompile (`\b(sk-ant-api03-[\w\-]{93}AA)\b` )
27
+ keyPat = regexp .MustCompile (`\b(sk-ant-(?:admin01|api03)-[\w\-]{93}AA)\b` )
28
+
29
+ // verification endpoints
30
+ apiKeyEndpoint = "https://api.anthropic.com/v1/models"
31
+ adminKeyEndpoint = "https://api.anthropic.com/v1/organizations/api_keys"
27
32
)
28
33
29
34
// Keywords are used for efficiently pre-filtering chunks.
30
35
// Use identifiers in the secret preferably, or the provider name.
31
36
func (s Scanner ) Keywords () []string {
32
- return []string {"sk-ant-api03" }
37
+ return []string {"sk-ant-api03" , "sk-ant-admin01" }
33
38
}
34
39
35
40
// FromData will find and optionally verify Anthropic secrets in a given set of bytes.
36
41
func (s Scanner ) FromData (ctx context.Context , verify bool , data []byte ) (results []detectors.Result , err error ) {
37
42
dataStr := string (data )
38
43
39
- matches := keyPat .FindAllStringSubmatch (dataStr , - 1 )
44
+ keys := keyPat .FindAllStringSubmatch (dataStr , - 1 )
40
45
41
- for _ , match := range matches {
42
- resMatch := strings .TrimSpace (match [1 ])
46
+ for _ , key := range keys {
47
+ keyMatch := strings .TrimSpace (key [1 ])
43
48
44
49
s1 := detectors.Result {
45
50
DetectorType : detectorspb .DetectorType_Anthropic ,
46
- Raw : []byte (resMatch ),
51
+ Raw : []byte (keyMatch ),
52
+ ExtraData : make (map [string ]string ),
47
53
}
48
54
49
55
if verify {
50
56
client := s .client
51
57
if client == nil {
52
58
client = defaultClient
53
59
}
54
- isVerified , err := verifyToken (ctx , client , resMatch )
60
+
61
+ isAdminKey := isAdminKey (keyMatch )
62
+ var isVerified bool
63
+ var err error
64
+
65
+ if isAdminKey {
66
+ isVerified , err = verifyAnthropicKey (ctx , client , adminKeyEndpoint , keyMatch )
67
+ s1 .ExtraData ["Type" ] = "Admin Key"
68
+ } else if ! isAdminKey {
69
+ isVerified , err = verifyAnthropicKey (ctx , client , apiKeyEndpoint , keyMatch )
70
+ s1 .ExtraData ["Type" ] = "API Key"
71
+ } else {
72
+ return nil , errors .New ("unknown key type detected for anthropic" )
73
+ }
74
+
55
75
s1 .Verified = isVerified
56
- s1 .SetVerificationError (err , resMatch )
76
+ s1 .SetVerificationError (err , keyMatch )
77
+
57
78
if s1 .Verified {
58
79
s1 .AnalysisInfo = map [string ]string {
59
- "key" : resMatch ,
80
+ "key" : keyMatch ,
60
81
}
61
82
}
62
83
}
@@ -67,14 +88,22 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
67
88
return results , nil
68
89
}
69
90
70
- func verifyToken (ctx context.Context , client * http.Client , apiKey string ) (bool , error ) {
71
- // https://docs.anthropic.com/en/api/models-list
72
- req , err := http .NewRequestWithContext (ctx , http .MethodGet , "https://api.anthropic.com/v1/models" , http .NoBody )
91
+ /*
92
+ verifyAnthropicKey verify the anthropic key passed against the endpoint
93
+
94
+ Endpoints:
95
+
96
+ - For api keys: https://docs.anthropic.com/en/api/models-list
97
+
98
+ - For admin keys: https://docs.anthropic.com/en/api/admin-api/apikeys/list-api-keys
99
+ */
100
+ func verifyAnthropicKey (ctx context.Context , client * http.Client , endpoint , key string ) (bool , error ) {
101
+ req , err := http .NewRequestWithContext (ctx , http .MethodGet , endpoint , http .NoBody )
73
102
if err != nil {
74
103
return false , nil
75
104
}
76
105
77
- req .Header .Set ("x-api-key" , apiKey )
106
+ req .Header .Set ("x-api-key" , key )
78
107
req .Header .Set ("Content-Type" , "application/json" )
79
108
req .Header .Set ("anthropic-version" , "2023-06-01" )
80
109
@@ -104,3 +133,7 @@ func (s Scanner) Type() detectorspb.DetectorType {
104
133
func (s Scanner ) Description () string {
105
134
return "Anthropic is an AI research company. The API keys can be used to access their AI models and services."
106
135
}
136
+
137
+ func isAdminKey (key string ) bool {
138
+ return strings .HasPrefix (key , "sk-ant-admin01" )
139
+ }
0 commit comments