Skip to content

Commit 869df44

Browse files
authored
added tunnel authtoken detection in ngrok detector (#4115)
1 parent afbf580 commit 869df44

File tree

2 files changed

+39
-6
lines changed

2 files changed

+39
-6
lines changed

pkg/detectors/ngrok/ngrok.go

+18-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"io"
77
"net/http"
8+
"strings"
89

910
regexp "github.com/wasilibs/go-re2"
1011

@@ -31,6 +32,11 @@ func (s Scanner) Keywords() []string {
3132
return []string{"ngrok"}
3233
}
3334

35+
const (
36+
ngrokVerificationURL = "https://api.ngrok.com/agent_ingresses"
37+
tunnelCredentialErrorCode = "ERR_NGROK_206"
38+
)
39+
3440
var (
3541
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"ngrok"}) + `\b(2[a-zA-Z0-9]{26}_\d[a-zA-Z0-9]{20})\b`)
3642
)
@@ -69,7 +75,7 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
6975
}
7076

7177
func verifyMatch(ctx context.Context, client *http.Client, token string) (bool, error) {
72-
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://api.ngrok.com/agent_ingresses", nil)
78+
req, err := http.NewRequestWithContext(ctx, http.MethodGet, ngrokVerificationURL, nil)
7379
if err != nil {
7480
return false, err
7581
}
@@ -90,7 +96,16 @@ func verifyMatch(ctx context.Context, client *http.Client, token string) (bool,
9096
return true, nil
9197
case http.StatusUnauthorized:
9298
return false, nil
93-
default:
94-
return false, fmt.Errorf("ngrok: unexpected status code: %d", res.StatusCode)
99+
case http.StatusBadRequest:
100+
bodyBytes, err := io.ReadAll(res.Body)
101+
if err != nil {
102+
return false, err
103+
}
104+
// Check if the error code is "ERR_NGROK_206" which indicates that
105+
// the credential is a valid tunnel Authtoken rather than an API key.
106+
if strings.Contains(string(bodyBytes), tunnelCredentialErrorCode) {
107+
return true, nil
108+
}
95109
}
110+
return false, fmt.Errorf("ngrok: unexpected status code: %d", res.StatusCode)
96111
}

pkg/detectors/ngrok/ngrok_integration_test.go

+21-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ func TestNgrok_FromChunk(t *testing.T) {
2525
if err != nil {
2626
t.Fatalf("could not get test secrets from GCP: %s", err)
2727
}
28-
secret := testSecrets.MustGetField("NGROK")
28+
secretAPIKey := testSecrets.MustGetField("NGROK")
29+
secretAuthtoken := testSecrets.MustGetField("NGROK_AUTHTOKEN")
2930
inactiveSecret := testSecrets.MustGetField("NGROK_INACTIVE")
3031

3132
type args struct {
@@ -42,11 +43,28 @@ func TestNgrok_FromChunk(t *testing.T) {
4243
wantVerificationErr bool
4344
}{
4445
{
45-
name: "found, verified",
46+
name: "found, API key, verified",
4647
s: Scanner{},
4748
args: args{
4849
ctx: context.Background(),
49-
data: []byte(fmt.Sprintf("You can find a ngrok secret %s within", secret)),
50+
data: []byte(fmt.Sprintf("You can find a ngrok secret API key %s within", secretAPIKey)),
51+
verify: true,
52+
},
53+
want: []detectors.Result{
54+
{
55+
DetectorType: detectorspb.DetectorType_Ngrok,
56+
Verified: true,
57+
},
58+
},
59+
wantErr: false,
60+
wantVerificationErr: false,
61+
},
62+
{
63+
name: "found, tunnel authtoken, verified",
64+
s: Scanner{},
65+
args: args{
66+
ctx: context.Background(),
67+
data: []byte(fmt.Sprintf("You can find a ngrok secret tunnel authtoken %s within", secretAuthtoken)),
5068
verify: true,
5169
},
5270
want: []detectors.Result{

0 commit comments

Comments
 (0)