Compare commits

...

1 Commits

Author SHA1 Message Date
Ahrav Dutta 09558f5f21 PR 14 of 40 2023-08-25 21:40:30 -07:00
20 changed files with 209 additions and 389 deletions
+7 -10
View File
@@ -1,11 +1,11 @@
package fxmarket
import (
"bytes"
"context"
"fmt"
"net/http"
"regexp"
"strings"
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
@@ -26,29 +26,27 @@ var (
// Keywords are used for efficiently pre-filtering chunks.
// Use identifiers in the secret preferably, or the provider name.
func (s Scanner) Keywords() []string {
return []string{"fxmarket"}
func (s Scanner) Keywords() [][]byte {
return [][]byte{[]byte("fxmarket")}
}
// FromData will find and optionally verify Fxmarket secrets in a given set of bytes.
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
dataStr := string(data)
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
matches := keyPat.FindAllSubmatch(data, -1)
for _, match := range matches {
if len(match) != 2 {
continue
}
resMatch := strings.TrimSpace(match[1])
resMatch := bytes.TrimSpace(match[1])
s1 := detectors.Result{
DetectorType: detectorspb.DetectorType_FXMarket,
Raw: []byte(resMatch),
Raw: resMatch,
}
if verify {
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://fxmarketapi.com/apilive?api_key=%s", resMatch), nil)
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://fxmarketapi.com/apilive?api_key=%s", string(resMatch)), nil)
if err != nil {
continue
}
@@ -59,7 +57,6 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
if res.StatusCode >= 200 && res.StatusCode < 300 {
s1.Verified = true
} else {
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
continue
}
+21 -28
View File
@@ -1,19 +1,20 @@
package gcp
import (
"bytes"
"context"
"encoding/json"
"regexp"
"strings"
"golang.org/x/oauth2/google"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
"golang.org/x/oauth2/google"
)
type Scanner struct{}
// Ensure the Scanner satisfies the interface at compile time.
var _ detectors.Detector = (*Scanner)(nil)
var (
@@ -33,33 +34,20 @@ type gcpKey struct {
ClientX509CertURL string `json:"client_x509_cert_url"`
}
func trimCarrots(s string) string {
s = strings.TrimPrefix(s, "<")
s = strings.TrimSuffix(s, ">")
return s
func (s Scanner) Keywords() [][]byte {
return [][]byte{[]byte("provider_x509")}
}
// Keywords are used for efficiently pre-filtering chunks.
// Use identifiers in the secret preferably, or the provider name.
func (s Scanner) Keywords() []string {
return []string{"provider_x509"}
}
// FromData will find and optionally verify GCP secrets in a given set of bytes.
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
dataStr := string(data)
matches := keyPat.FindAllString(dataStr, -1)
matches := keyPat.FindAll(data, -1)
for _, match := range matches {
key := match
key = strings.ReplaceAll(key, `,\\n`, `\n`)
key = strings.ReplaceAll(key, `\"\\n`, `\n`)
key = strings.ReplaceAll(key, `\\"`, `"`)
key := bytes.ReplaceAll(match, []byte(`,\n`), []byte(`\n`))
key = bytes.ReplaceAll(key, []byte(`"\n`), []byte(`\n`))
key = bytes.ReplaceAll(key, []byte(`\"`), []byte(`"`))
creds := gcpKey{}
err := json.Unmarshal([]byte(key), &creds)
err := json.Unmarshal(key, &creds)
if err != nil {
continue
}
@@ -68,15 +56,14 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
if strings.Contains(creds.ClientEmail, `<mailto:`) {
creds.ClientEmail = strings.Split(strings.Split(creds.ClientEmail, `<mailto:`)[1], `|`)[0]
}
creds.AuthProviderX509CertURL = trimCarrots(creds.AuthProviderX509CertURL)
creds.AuthURI = trimCarrots(creds.AuthURI)
creds.ClientX509CertURL = trimCarrots(creds.ClientX509CertURL)
creds.TokenURI = trimCarrots(creds.TokenURI)
creds.AuthProviderX509CertURL = string(trimCarrots([]byte(creds.AuthProviderX509CertURL)))
creds.AuthURI = string(trimCarrots([]byte(creds.AuthURI)))
creds.ClientX509CertURL = string(trimCarrots([]byte(creds.ClientX509CertURL)))
creds.TokenURI = string(trimCarrots([]byte(creds.TokenURI)))
// Not sure why this might happen, but we've observed this with a verified cred
raw := []byte(creds.ClientEmail)
if len(raw) == 0 {
raw = []byte(key)
raw = key
}
credBytes, _ := json.Marshal(creds)
@@ -107,6 +94,12 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
return
}
func trimCarrots(s []byte) []byte {
s = bytes.TrimPrefix(s, []byte("<"))
s = bytes.TrimSuffix(s, []byte(">"))
return s
}
func (s Scanner) Type() detectorspb.DetectorType {
return detectorspb.DetectorType_GCP
}
+7 -15
View File
@@ -1,11 +1,11 @@
package geckoboard
import (
"bytes"
"context"
"fmt"
"net/http"
"regexp"
"strings"
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
@@ -14,37 +14,30 @@ import (
type Scanner struct{}
// Ensure the Scanner satisfies the interface at compile time.
var _ detectors.Detector = (*Scanner)(nil)
var (
client = common.SaneHttpClient()
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"geckoboard"}) + `\b([a-zA-Z0-9]{44})\b`)
)
// Keywords are used for efficiently pre-filtering chunks.
// Use identifiers in the secret preferably, or the provider name.
func (s Scanner) Keywords() []string {
return []string{"geckoboard"}
func (s Scanner) Keywords() [][]byte {
return [][]byte{[]byte("geckoboard")}
}
// FromData will find and optionally verify Geckoboard secrets in a given set of bytes.
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
dataStr := string(data)
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
matches := keyPat.FindAllSubmatch(data, -1)
for _, match := range matches {
if len(match) != 2 {
continue
}
resMatch := strings.TrimSpace(match[1])
resMatch := bytes.TrimSpace(match[1])
s1 := detectors.Result{
DetectorType: detectorspb.DetectorType_Geckoboard,
Raw: []byte(resMatch),
Raw: resMatch,
}
if verify {
@@ -53,14 +46,13 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
continue
}
req.Header.Add("Authorization", fmt.Sprintf("Basic %s", resMatch))
req.Header.Add("Authorization", fmt.Sprintf("Basic %s", string(resMatch)))
res, err := client.Do(req)
if err == nil {
defer res.Body.Close()
if res.StatusCode >= 200 && res.StatusCode < 300 {
s1.Verified = true
} else {
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
continue
}
+15 -22
View File
@@ -10,7 +10,6 @@ import (
"encoding/json"
"net/http"
"regexp"
"strings"
"time"
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
@@ -37,32 +36,27 @@ var (
secretPat = regexp.MustCompile(`[A-Za-z0-9]{27,28}`)
)
// Keywords are used for efficiently pre-filtering chunks.
// Use identifiers in the secret preferably, or the provider name.
func (s Scanner) Keywords() []string {
return []string{"master-", "account-"}
func (s Scanner) Keywords() [][]byte {
return [][]byte{[]byte("master-"), []byte("account-")}
}
// FromData will find and optionally verify Gemini secrets in a given set of bytes.
func (s Scanner) FromData(_ context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
dataStr := string(data)
idMatches := keyPat.FindAllStringSubmatch(dataStr, -1)
secretMatches := secretPat.FindAllStringSubmatch(dataStr, -1)
idMatches := keyPat.FindAllSubmatch(data, -1)
secretMatches := secretPat.FindAllSubmatch(data, -1)
for _, match := range idMatches {
if len(match) != 2 {
continue
}
resMatch := strings.TrimSpace(match[1])
resMatch := bytes.TrimSpace(match[1])
for _, secretMatch := range secretMatches {
resSecretMatch := strings.TrimSpace(secretMatch[0])
resSecretMatch := bytes.TrimSpace(secretMatch[0])
s1 := detectors.Result{
DetectorType: detectorspb.DetectorType_Gemini,
Raw: []byte(resMatch),
RawV2: []byte(resMatch + resSecretMatch),
Raw: resMatch,
RawV2: append(resMatch, resSecretMatch...),
}
if verify {
@@ -77,7 +71,7 @@ func (s Scanner) FromData(_ context.Context, verify bool, data []byte) (results
if res.StatusCode >= 200 && res.StatusCode < 300 {
s1.Verified = true
} else {
if detectors.IsKnownFalsePositive(resSecretMatch, detectors.DefaultFalsePositives, true) {
if detectors.IsKnownFalsePositive([]byte(resSecretMatch), detectors.DefaultFalsePositives, true) {
continue
}
}
@@ -90,7 +84,7 @@ func (s Scanner) FromData(_ context.Context, verify bool, data []byte) (results
return results, nil
}
func constructRequest(secret, keyID string) (*http.Request, error) {
func constructRequest(secret, keyID []byte) (*http.Request, error) {
req, err := http.NewRequest("POST", baseURL+accountDetail, &bytes.Buffer{})
if err != nil {
return nil, err
@@ -101,9 +95,8 @@ func constructRequest(secret, keyID string) (*http.Request, error) {
"nonce": time.Now().UnixNano(),
}
acct := strings.Split(keyID, "-")
// Not entirely sure how to handle master account keys where one of the accounts is named "primary".
if len(acct) > 1 && acct[0] == "master" {
acct := bytes.Split(keyID, []byte("-"))
if len(acct) > 1 && string(acct[0]) == "master" {
params["account"] = account
}
@@ -118,7 +111,7 @@ func constructRequest(secret, keyID string) (*http.Request, error) {
req.Header = http.Header{
"Content-Type": {"text/plain"},
"Content-Length": {"0"},
"X-GEMINI-APIKEY": {keyID},
"X-GEMINI-APIKEY": {string(keyID)},
"X-GEMINI-PAYLOAD": {payload},
"X-GEMINI-SIGNATURE": {signature},
"Cache-Control": {"no-cache"},
@@ -126,8 +119,8 @@ func constructRequest(secret, keyID string) (*http.Request, error) {
return req, err
}
func constructSignature(payload string, resSecretMatch string) string {
h := hmac.New(sha512.New384, []byte(resSecretMatch))
func constructSignature(payload string, resSecretMatch []byte) string {
h := hmac.New(sha512.New384, resSecretMatch)
h.Write([]byte(payload))
signature := hex.EncodeToString(h.Sum(nil))
return signature
+25 -61
View File
@@ -1,39 +1,37 @@
package generic
// cat scanner/pkg/secrets/generic/top-1000.txt | awk 'length($0)>5' > scanner/pkg/secrets/generic/words.txt
import (
"bytes"
"context"
"encoding/base64"
"fmt"
"regexp"
"strings"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
)
func New() Scanner {
excludePatterns := []string{
`[0-9A-Fa-f]{8}(?:-[0-9A-Fa-f]{4}){3}-[0-9A-Fa-f]{12}`, // UUID
`[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[8|9|aA|bB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}`, // UUIDv4
`[A-Z]{2,6}\-[0-9]{2,6}`, // issue tracker
`#[a-fA-F0-9]{6}\b`, // hex color code
`\b[A-Fa-f0-9]{64}\b`, // hex encoded hash
`https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)`, // http
`\b([/]{0,1}([\w]+[/])+[\w\.]*)\b`, // filepath
`([0-9A-F]{2}[:-]){5}([0-9A-F]{2})`, // MAC addr
`\d{4}[-/]{1}([0]\d|1[0-2])[-/]{1}([0-2]\d|3[01])`, // date
`[v|\-]\d\.\d`, //version
`\d\.\d\.\d-`, //version
`[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}`, // IPs and OIDs
`[A-Fa-f0-9x]{2}:[A-Fa-f0-9x]{2}:[A-Fa-f0-9x]{2}`, // hex encoding
`[\w]+\([\w, ]+\)`, // function
excludePatterns := [][]byte{
[]byte(`[0-9A-Fa-f]{8}(?:-[0-9A-Fa-f]{4}){3}-[0-9A-Fa-f]{12}`), // UUID
[]byte(`[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[8|9|aA|bB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}`), // UUIDv4
[]byte(`[A-Z]{2,6}\-[0-9]{2,6}`), // issue tracker
[]byte(`#[a-fA-F0-9]{6}\b`),
[]byte(`\b[A-Fa-f0-9]{64}\b`),
[]byte(`https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)`),
[]byte(`\b([/]{0,1}([\w]+[/])+[\w\.]*)\b`),
[]byte(`([0-9A-F]{2}[:-]){5}([0-9A-F]{2})`),
[]byte(`\d{4}[-/]{1}([0]\d|1[0-2])[-/]{1}([0-2]\d|3[01])`),
[]byte(`[v|\-]\d\.\d`),
[]byte(`\d\.\d\.\d-`),
[]byte(`[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}`),
[]byte(`[A-Fa-f0-9x]{2}:[A-Fa-f0-9x]{2}:[A-Fa-f0-9x]{2}`),
[]byte(`[\w]+\([\w, ]+\)`),
}
excludeMatchers := []*regexp.Regexp{}
for _, pat := range excludePatterns {
excludeMatchers = append(excludeMatchers, regexp.MustCompile(pat))
excludeMatchers = append(excludeMatchers, regexp.MustCompile(string(pat)))
}
return Scanner{
@@ -45,57 +43,43 @@ type Scanner struct {
excludeMatchers []*regexp.Regexp
}
// Ensure the Scanner satisfies the interface at compile time.
var _ detectors.Detector = (*Scanner)(nil)
var keywords = []string{"pass", "token", "cred", "secret", "key"}
var keywords = [][]byte{[]byte("pass"), []byte("token"), []byte("cred"), []byte("secret"), []byte("key")}
var (
// \x21-\x7e == ASCII 33 (0x21) and 126 (0x7e)
keyPat = regexp.MustCompile(detectors.PrefixRegex(keywords) + `(\b[\x21-\x7e]{16,64}\b)`)
)
// Keywords are used for efficiently pre-filtering chunks.
// Use identifiers in the secret preferably, or the provider name.
func (s Scanner) Keywords() []string {
func (s Scanner) Keywords() [][]byte {
return keywords
}
// FromData will find and optionally verify Generic secrets in a given set of bytes.
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
dataStr := string(data)
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
matches := keyPat.FindAllSubmatch(data, -1)
for _, match := range matches {
token := match[1]
// Least expensive-> most expensive filters.
// Substrings, then patterns.
if detectors.IsKnownFalsePositive(token, detectors.DefaultFalsePositives, true) {
continue
}
// toss any that match regexes
if hasReMatch(s.excludeMatchers, token) {
continue
}
// clean up containment chars
token = strings.Trim(token, fmt.Sprintf(`%s" '.,)(][}{`, "`"))
token = bytes.Trim(token, []byte(fmt.Sprintf(`%s" '.,)(][}{`, "`")))
// toss any that b64 decode
// TODO: run them through again?
_, err := base64.StdEncoding.DecodeString(token)
_, err := base64.StdEncoding.DecodeString(string(token))
if err == nil {
continue
}
s := detectors.Result{
DetectorType: detectorspb.DetectorType_Generic,
Raw: []byte(token),
Raw: token,
}
results = append(results, s)
@@ -104,35 +88,15 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
return
}
func hasReMatch(matchers []*regexp.Regexp, token string) bool {
func hasReMatch(matchers []*regexp.Regexp, token []byte) bool {
for _, m := range matchers {
if m.MatchString(token) {
if m.Match(token) {
return true
}
}
return false
}
// func hasDictWord(wordList []string, token string) bool {
// lower := strings.ToLower(token)
// for _, word := range wordList {
// if strings.Contains(lower, word) {
// return true
// }
// }
// return false
// }
// func bytesToCleanWordList(data []byte) []string {
// words := []string{}
// for _, word := range strings.Split(string(data), "\n") {
// if strings.TrimSpace(word) != "" {
// words = append(words, strings.TrimSpace(strings.ToLower(word)))
// }
// }
// return words
// }
func (s Scanner) Type() detectorspb.DetectorType {
return detectorspb.DetectorType_Generic
}
+15 -28
View File
@@ -1,6 +1,7 @@
package gengo
import (
"bytes"
"context"
"crypto/hmac"
"crypto/sha1"
@@ -11,7 +12,6 @@ import (
"net/http"
"regexp"
"strconv"
"strings"
"time"
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
@@ -35,41 +35,39 @@ var (
// Keywords are used for efficiently pre-filtering chunks.
// Use identifiers in the secret preferably, or the provider name.
func (s Scanner) Keywords() []string {
return []string{"gengo"}
func (s Scanner) Keywords() [][]byte {
return [][]byte{[]byte("gengo")}
}
// FromData will find and optionally verify Gengo secrets in a given set of bytes.
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
dataStr := string(data)
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
secretMatches := secretPat.FindAllStringSubmatch(dataStr, -1)
matches := keyPat.FindAllSubmatch(data, -1)
secretMatches := secretPat.FindAllSubmatch(data, -1)
for _, match := range matches {
if len(match) != 2 {
continue
}
resMatch := strings.TrimSpace(match[1])
resMatch := bytes.TrimSpace(match[1])
for _, secretMatch := range secretMatches {
if len(secretMatch) != 2 {
continue
}
resSecretMatch := strings.TrimSpace(secretMatch[1])
resSecretMatch := bytes.TrimSpace(secretMatch[1])
s1 := detectors.Result{
DetectorType: detectorspb.DetectorType_Gengo,
Raw: []byte(resSecretMatch),
RawV2: []byte(resMatch + resSecretMatch),
Raw: resSecretMatch,
RawV2: append(resMatch, resSecretMatch...),
}
if verify {
timestamp := strconv.FormatInt(time.Now().Unix(), 10)
signature := getGengoSignature(timestamp, resSecretMatch)
signature := getGengoSignature(timestamp, string(resSecretMatch))
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://api.gengo.com/v2/account/me?ts=%s&api_key=%s&api_sig=%s", timestamp, resMatch, signature), nil)
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://api.gengo.com/v2/account/me?ts=%s&api_key=%s&api_sig=%s", timestamp, string(resMatch), signature), nil)
if err != nil {
continue
}
@@ -77,30 +75,20 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
res, err := client.Do(req)
if err == nil {
defer res.Body.Close()
body, errBody := io.ReadAll(res.Body)
if errBody == nil {
if res.StatusCode >= 200 && res.StatusCode < 300 {
var response Response
if err := json.Unmarshal(body, &response); err != nil {
continue
}
body, errBody := io.ReadAll(res.Body)
if res.StatusCode >= 200 && res.StatusCode < 300 && response.OpStat == "ok" {
if errBody == nil && json.Unmarshal(body, &response) == nil && response.OpStat == "ok" {
s1.Verified = true
} else {
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
continue
}
if detectors.IsKnownFalsePositive(resSecretMatch, detectors.DefaultFalsePositives, true) {
if detectors.IsKnownFalsePositive(match[1], detectors.DefaultFalsePositives, true) || detectors.IsKnownFalsePositive(secretMatch[1], detectors.DefaultFalsePositives, true) {
continue
}
}
}
}
}
results = append(results, s1)
}
}
@@ -113,7 +101,6 @@ type Response struct {
}
func getGengoSignature(timeStamp string, secret string) string {
mac := hmac.New(sha1.New, []byte(secret))
mac.Write([]byte(timeStamp))
macsum := mac.Sum(nil)
+7 -15
View File
@@ -1,11 +1,11 @@
package geoapify
import (
"bytes"
"context"
"fmt"
"net/http"
"regexp"
"strings"
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
@@ -14,41 +14,34 @@ import (
type Scanner struct{}
// Ensure the Scanner satisfies the interface at compile time.
var _ detectors.Detector = (*Scanner)(nil)
var (
client = common.SaneHttpClient()
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"geoapify"}) + `\b([a-z0-9]{32})\b`)
)
// Keywords are used for efficiently pre-filtering chunks.
// Use identifiers in the secret preferably, or the provider name.
func (s Scanner) Keywords() []string {
return []string{"geoapify"}
func (s Scanner) Keywords() [][]byte {
return [][]byte{[]byte("geoapify")}
}
// FromData will find and optionally verify Geoapify secrets in a given set of bytes.
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
dataStr := string(data)
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
matches := keyPat.FindAllSubmatch(data, -1)
for _, match := range matches {
if len(match) != 2 {
continue
}
resMatch := strings.TrimSpace(match[1])
resMatch := bytes.TrimSpace(match[1])
s1 := detectors.Result{
DetectorType: detectorspb.DetectorType_Geoapify,
Raw: []byte(resMatch),
Raw: resMatch,
}
if verify {
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://api.geoapify.com/v1/geocode/search?text=California&apiKey=%s", resMatch), nil)
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://api.geoapify.com/v1/geocode/search?text=California&apiKey=%s", string(resMatch)), nil)
if err != nil {
continue
}
@@ -58,7 +51,6 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
if res.StatusCode >= 200 && res.StatusCode < 300 {
s1.Verified = true
} else {
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
continue
}
+10 -17
View File
@@ -1,12 +1,12 @@
package geocode
import (
"bytes"
"context"
"fmt"
"io"
"net/http"
"regexp"
"strings"
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
@@ -15,41 +15,35 @@ import (
type Scanner struct{}
// Ensure the Scanner satisfies the interface at compile time.
var _ detectors.Detector = (*Scanner)(nil)
var (
client = common.SaneHttpClient()
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"geocode"}) + `\b([a-z0-9]{28})\b`)
)
// Keywords are used for efficiently pre-filtering chunks.
// Use identifiers in the secret preferably, or the provider name.
func (s Scanner) Keywords() []string {
return []string{"geocode"}
func (s Scanner) Keywords() [][]byte {
return [][]byte{[]byte("geocode")}
}
// FromData will find and optionally verify Geocode secrets in a given set of bytes.
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
dataStr := string(data)
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
matches := keyPat.FindAllSubmatch(data, -1)
for _, match := range matches {
if len(match) != 2 {
continue
}
resMatch := strings.TrimSpace(match[1])
resMatch := bytes.TrimSpace(match[1])
s1 := detectors.Result{
DetectorType: detectorspb.DetectorType_Geocode,
Raw: []byte(resMatch),
Raw: resMatch,
}
if verify {
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://geocode.xyz/51.4647,0.0079?json=1&auth=%s", resMatch), nil)
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://geocode.xyz/51.4647,0.0079?json=1&auth=%s", string(resMatch)), nil)
if err != nil {
continue
}
@@ -57,8 +51,7 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
if err == nil {
bodyBytes, err := io.ReadAll(res.Body)
if err == nil {
bodyString := string(bodyBytes)
validResponse := strings.Contains(bodyString, `"remaining_credits" :`)
validResponse := bytes.Contains(bodyBytes, []byte(`"remaining_credits" :`))
defer res.Body.Close()
if res.StatusCode >= 200 && res.StatusCode < 300 {
if validResponse {
@@ -67,7 +60,6 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
s1.Verified = false
}
} else {
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
continue
}
@@ -75,6 +67,7 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
}
}
}
results = append(results, s1)
}
+8 -15
View File
@@ -1,10 +1,11 @@
package geocodify
import (
"bytes"
"context"
"fmt"
"net/http"
"regexp"
"strings"
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
@@ -13,41 +14,34 @@ import (
type Scanner struct{}
// Ensure the Scanner satisfies the interface at compile time.
var _ detectors.Detector = (*Scanner)(nil)
var (
client = common.SaneHttpClient()
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"geocodify"}) + `\b([0-9a-z]{40})\b`)
)
// Keywords are used for efficiently pre-filtering chunks.
// Use identifiers in the secret preferably, or the provider name.
func (s Scanner) Keywords() []string {
return []string{"geocodify"}
func (s Scanner) Keywords() [][]byte {
return [][]byte{[]byte("geocodify")}
}
// FromData will find and optionally verify Geocodify secrets in a given set of bytes.
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
dataStr := string(data)
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
matches := keyPat.FindAllSubmatch(data, -1)
for _, match := range matches {
if len(match) != 2 {
continue
}
resMatch := strings.TrimSpace(match[1])
resMatch := bytes.TrimSpace(match[1])
s1 := detectors.Result{
DetectorType: detectorspb.DetectorType_Geocodify,
Raw: []byte(resMatch),
Raw: resMatch,
}
if verify {
req, err := http.NewRequestWithContext(ctx, "GET", "https://api.geocodify.com/v2/geocode?api_key="+resMatch, nil)
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://api.geocodify.com/v2/geocode?api_key=%s", string(resMatch)), nil)
if err != nil {
continue
}
@@ -57,7 +51,6 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
if res.StatusCode >= 200 && res.StatusCode < 300 {
s1.Verified = true
} else {
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
continue
}
+10 -17
View File
@@ -1,11 +1,11 @@
package geocodio
import (
"bytes"
"context"
"fmt"
"net/http"
"regexp"
"strings"
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
@@ -14,49 +14,43 @@ import (
type Scanner struct{}
// Ensure the Scanner satisfies the interface at compile time.
var _ detectors.Detector = (*Scanner)(nil)
var (
client = common.SaneHttpClient()
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"geocod"}) + `\b([a-z0-9]{39})\b`)
searchPat = regexp.MustCompile(detectors.PrefixRegex([]string{"geocod"}) + `\b([a-zA-Z0-9\S]{7,30})\b`)
)
// Keywords are used for efficiently pre-filtering chunks.
// Use identifiers in the secret preferably, or the provider name.
func (s Scanner) Keywords() []string {
return []string{"geocod"}
func (s Scanner) Keywords() [][]byte {
return [][]byte{[]byte("geocod")}
}
// FromData will find and optionally verify Geocodio secrets in a given set of bytes.
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
dataStr := string(data)
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
searchMatches := searchPat.FindAllStringSubmatch(dataStr, -1)
matches := keyPat.FindAllSubmatch(data, -1)
searchMatches := searchPat.FindAllSubmatch(data, -1)
for _, match := range matches {
if len(match) != 2 {
continue
}
resMatch := strings.TrimSpace(match[1])
resMatch := bytes.TrimSpace(match[1])
for _, searchMatch := range searchMatches {
if len(searchMatch) != 2 {
continue
}
resSearchMatch := strings.TrimSpace(searchMatch[1])
resSearchMatch := bytes.TrimSpace(searchMatch[1])
s1 := detectors.Result{
DetectorType: detectorspb.DetectorType_Geocodio,
Raw: []byte(resMatch),
RawV2: []byte(resMatch + resSearchMatch),
Raw: resMatch,
RawV2: append(resMatch, resSearchMatch...),
}
if verify {
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://api.geocod.io/v1.6/geocode?q=%s&api_key=%s", resSearchMatch, resMatch), nil)
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://api.geocod.io/v1.6/geocode?q=%s&api_key=%s", string(resSearchMatch), string(resMatch)), nil)
if err != nil {
continue
}
@@ -66,7 +60,6 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
if res.StatusCode >= 200 && res.StatusCode < 300 {
s1.Verified = true
} else {
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
continue
}
+8 -9
View File
@@ -1,10 +1,11 @@
package geoipifi
import (
"bytes"
"context"
"fmt"
"net/http"
"regexp"
"strings"
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
@@ -25,29 +26,27 @@ var (
// Keywords are used for efficiently pre-filtering chunks.
// Use identifiers in the secret preferably, or the provider name.
func (s Scanner) Keywords() []string {
return []string{"ipifi"}
func (s Scanner) Keywords() [][]byte {
return [][]byte{[]byte("ipifi")}
}
// FromData will find and optionally verify GeoIpifi secrets in a given set of bytes.
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
dataStr := string(data)
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
matches := keyPat.FindAllSubmatch(data, -1)
for _, match := range matches {
if len(match) != 2 {
continue
}
resMatch := strings.TrimSpace(match[1])
resMatch := bytes.TrimSpace(match[1])
s1 := detectors.Result{
DetectorType: detectorspb.DetectorType_GeoIpifi,
Raw: []byte(resMatch),
Raw: resMatch,
}
if verify {
req, err := http.NewRequestWithContext(ctx, "GET", "https://geo.ipify.org/api/v2/country?apiKey="+resMatch+"&ipAddress=8.8.8.8", nil)
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://geo.ipify.org/api/v2/country?apiKey=%s&ipAddress=8.8.8.8", string(resMatch)), nil)
if err != nil {
continue
}
+10 -23
View File
@@ -1,12 +1,12 @@
package getemail
import (
"bytes"
"context"
"fmt"
"io"
"net/http"
"regexp"
"strings"
"time"
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
@@ -16,61 +16,48 @@ import (
type Scanner struct{}
// Ensure the Scanner satisfies the interface at compile time.
var _ detectors.Detector = (*Scanner)(nil)
var (
client = common.SaneHttpClientTimeOut(5 * time.Second)
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"getemail"}) + `\b([a-zA-Z0-9-]{20})\b`)
)
// Keywords are used for efficiently pre-filtering chunks.
// Use identifiers in the secret preferably, or the provider name.
func (s Scanner) Keywords() []string {
return []string{"getemail"}
func (s Scanner) Keywords() [][]byte {
return [][]byte{[]byte("getemail")}
}
// FromData will find and optionally verify GetEmail secrets in a given set of bytes.
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
dataStr := string(data)
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
matches := keyPat.FindAllSubmatch(data, -1)
for _, match := range matches {
if len(match) != 2 {
continue
}
resMatch := strings.TrimSpace(match[1])
resMatch := bytes.TrimSpace(match[1])
s1 := detectors.Result{
DetectorType: detectorspb.DetectorType_GetEmail,
Raw: []byte(resMatch),
Raw: resMatch,
}
if verify {
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://api.getemail.io/v1/find-mail?firstname=Larry&lastname=Page&domain=google.com&api_key=%s", resMatch), nil)
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://api.getemail.io/v1/find-mail?firstname=Larry&lastname=Page&domain=google.com&api_key=%s", string(resMatch)), nil)
if err != nil {
continue
}
res, err := client.Do(req)
if err == nil {
defer res.Body.Close()
bodyBytes, err := io.ReadAll(res.Body)
if err != nil {
continue
}
bodyString := string(bodyBytes)
errCode := strings.Contains(bodyString, `"code":"USER_NOT_EXIST"`)
defer res.Body.Close()
errCode := bytes.Contains(bodyBytes, []byte(`"code":"USER_NOT_EXIST"`))
if res.StatusCode >= 200 && res.StatusCode < 300 {
if errCode {
s1.Verified = false
} else {
s1.Verified = true
}
s1.Verified = !errCode
} else {
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
continue
}
+13 -16
View File
@@ -1,10 +1,10 @@
package getemails
import (
"bytes"
"context"
"net/http"
"regexp"
"strings"
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
@@ -26,33 +26,31 @@ var (
// Keywords are used for efficiently pre-filtering chunks.
// Use identifiers in the secret preferably, or the provider name.
func (s Scanner) Keywords() []string {
return []string{"getemails"}
func (s Scanner) Keywords() [][]byte {
return [][]byte{[]byte("getemails")}
}
// FromData will find and optionally verify GetEmails secrets in a given set of bytes.
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
dataStr := string(data)
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
idMatches := idPat.FindAllStringSubmatch(dataStr, -1)
keyMatches := keyPat.FindAllSubmatch(data, -1)
idMatches := idPat.FindAllSubmatch(data, -1)
for _, match := range matches {
if len(match) != 2 {
for _, keyMatch := range keyMatches {
if len(keyMatch) != 2 {
continue
}
resMatch := strings.TrimSpace(match[1])
resKeyMatch := bytes.TrimSpace(keyMatch[1])
for _, idMatch := range idMatches {
if len(idMatch) != 2 {
continue
}
resIdMatch := strings.TrimSpace(idMatch[1])
resIdMatch := bytes.TrimSpace(idMatch[1])
s1 := detectors.Result{
DetectorType: detectorspb.DetectorType_GetEmails,
Raw: []byte(resMatch),
Raw: resKeyMatch,
}
if verify {
@@ -60,8 +58,8 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
if err != nil {
continue
}
req.Header.Add("api-key", resMatch)
req.Header.Add("api-id", resIdMatch)
req.Header.Add("api-key", string(resKeyMatch))
req.Header.Add("api-id", string(resIdMatch))
res, err := client.Do(req)
@@ -70,8 +68,7 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
if res.StatusCode >= 200 && res.StatusCode < 300 {
s1.Verified = true
} else {
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
if detectors.IsKnownFalsePositive(resKeyMatch, detectors.DefaultFalsePositives, true) {
continue
}
}
+7 -16
View File
@@ -1,11 +1,11 @@
package getgeoapi
import (
"bytes"
"context"
"fmt"
"net/http"
"regexp"
"strings"
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
@@ -14,41 +14,33 @@ import (
type Scanner struct{}
// Ensure the Scanner satisfies the interface at compile time.
var _ detectors.Detector = (*Scanner)(nil)
var (
client = common.SaneHttpClient()
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"getgeoapi"}) + `\b([0-9a-z]{40})\b`)
)
// Keywords are used for efficiently pre-filtering chunks.
// Use identifiers in the secret preferably, or the provider name.
func (s Scanner) Keywords() []string {
return []string{"getgeoapi"}
func (s Scanner) Keywords() [][]byte {
return [][]byte{[]byte("getgeoapi")}
}
// FromData will find and optionally verify Getgeoapi secrets in a given set of bytes.
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
dataStr := string(data)
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
matches := keyPat.FindAllSubmatch(data, -1)
for _, match := range matches {
if len(match) != 2 {
continue
}
resMatch := strings.TrimSpace(match[1])
resMatch := bytes.TrimSpace(match[1])
s1 := detectors.Result{
DetectorType: detectorspb.DetectorType_GetGeoAPI,
Raw: []byte(resMatch),
Raw: resMatch,
}
if verify {
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://api.getgeoapi.com/v2/currency/list?api_key=%s", resMatch), nil)
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://api.getgeoapi.com/v2/currency/list?api_key=%s", string(resMatch)), nil)
if err != nil {
continue
}
@@ -59,7 +51,6 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
if res.StatusCode >= 200 && res.StatusCode < 300 {
s1.Verified = true
} else {
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
continue
}
+7 -10
View File
@@ -1,11 +1,11 @@
package getgist
import (
"bytes"
"context"
"fmt"
"net/http"
"regexp"
"strings"
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
@@ -20,31 +20,29 @@ var _ detectors.Detector = (*Scanner)(nil)
var (
client = common.SaneHttpClient()
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
// Keeping the regexp patterns unchanged
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"getgist"}) + `\b([a-z0-9A-Z+=]{68})`)
)
// Keywords are used for efficiently pre-filtering chunks.
// Use identifiers in the secret preferably, or the provider name.
func (s Scanner) Keywords() []string {
return []string{"getgist"}
func (s Scanner) Keywords() [][]byte {
return [][]byte{[]byte("getgist")}
}
// FromData will find and optionally verify Getgist secrets in a given set of bytes.
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
dataStr := string(data)
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
matches := keyPat.FindAllSubmatch(data, -1)
for _, match := range matches {
if len(match) != 2 {
continue
}
resMatch := strings.TrimSpace(match[1])
resMatch := bytes.TrimSpace(match[1])
s1 := detectors.Result{
DetectorType: detectorspb.DetectorType_Getgist,
Raw: []byte(resMatch),
Raw: resMatch,
}
if verify {
@@ -59,7 +57,6 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
if res.StatusCode >= 200 && res.StatusCode < 300 {
s1.Verified = true
} else {
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
continue
}
+7 -14
View File
@@ -1,11 +1,11 @@
package getresponse
import (
"bytes"
"context"
"fmt"
"net/http"
"regexp"
"strings"
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
@@ -14,37 +14,31 @@ import (
type Scanner struct{}
// Ensure the Scanner satisfies the interface at compile time
var _ detectors.Detector = (*Scanner)(nil)
var (
client = common.SaneHttpClient()
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"getresponse"}) + `\b([a-z0-9]{32})\b`)
)
// Keywords are used for efficiently pre-filtering chunks.
// Use identifiers in the secret preferably, or the provider name.
func (s Scanner) Keywords() []string {
return []string{"getresponse"}
func (s Scanner) Keywords() [][]byte {
return [][]byte{[]byte("getresponse")}
}
// FromData will find and optionally verify Getresponse secrets in a given set of bytes.
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
dataStr := string(data)
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
matches := keyPat.FindAllSubmatch(data, -1)
for _, match := range matches {
if len(match) != 2 {
continue
}
resMatch := strings.TrimSpace(match[1])
resMatch := bytes.TrimSpace(match[1])
s1 := detectors.Result{
DetectorType: detectorspb.DetectorType_Getresponse,
Raw: []byte(resMatch),
Raw: resMatch,
}
if verify {
@@ -52,14 +46,13 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
if err != nil {
continue
}
req.Header.Add("X-Auth-Token", fmt.Sprintf("api-key %s", resMatch))
req.Header.Add("X-Auth-Token", fmt.Sprintf("api-key %s", string(resMatch)))
res, err := client.Do(req)
if err == nil {
defer res.Body.Close()
if res.StatusCode >= 200 && res.StatusCode < 300 {
s1.Verified = true
} else {
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
continue
}
+10 -18
View File
@@ -1,11 +1,11 @@
package getsandbox
import (
"bytes"
"context"
"fmt"
"net/http"
"regexp"
"strings"
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
@@ -14,60 +14,52 @@ import (
type Scanner struct{}
// Ensure the Scanner satisfies the interface at compile time.
var _ detectors.Detector = (*Scanner)(nil)
var (
client = common.SaneHttpClient()
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"getsandbox"}) + `\b([a-z0-9-]{40})\b`)
idPat = regexp.MustCompile(detectors.PrefixRegex([]string{"getsandbox"}) + `\b([a-z0-9-]{15,30})\b`)
)
// Keywords are used for efficiently pre-filtering chunks.
// Use identifiers in the secret preferably, or the provider name.
func (s Scanner) Keywords() []string {
return []string{"getsandbox"}
func (s Scanner) Keywords() [][]byte {
return [][]byte{[]byte("getsandbox")}
}
// FromData will find and optionally verify GetSandbox secrets in a given set of bytes.
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
dataStr := string(data)
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
idMatches := idPat.FindAllStringSubmatch(dataStr, -1)
matches := keyPat.FindAllSubmatch(data, -1)
idMatches := idPat.FindAllSubmatch(data, -1)
for _, match := range matches {
if len(match) != 2 {
continue
}
resMatch := strings.TrimSpace(match[1])
resMatch := bytes.TrimSpace(match[1])
for _, idMatch := range idMatches {
if len(idMatch) != 2 {
continue
}
resIdMatch := strings.TrimSpace(idMatch[1])
resIdMatch := bytes.TrimSpace(idMatch[1])
s1 := detectors.Result{
DetectorType: detectorspb.DetectorType_GetSandbox,
Raw: []byte(resMatch),
Raw: resMatch,
}
if verify {
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://getsandbox.com/api/1/sandboxes/%s", resIdMatch), nil)
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://getsandbox.com/api/1/sandboxes/%s", string(resIdMatch)), nil)
if err != nil {
continue
}
req.Header.Add("API-Key", resMatch)
req.Header.Add("API-Key", string(resMatch))
res, err := client.Do(req)
if err == nil {
defer res.Body.Close()
if res.StatusCode >= 200 && res.StatusCode < 300 {
s1.Verified = true
} else {
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
if detectors.IsKnownFalsePositive(resMatch, detectors.DefaultFalsePositives, true) {
continue
}
+9 -23
View File
@@ -1,6 +1,7 @@
package github
import (
"bytes"
"context"
"encoding/json"
"fmt"
@@ -24,18 +25,9 @@ func (Scanner) Version() int { return 2 }
func (Scanner) DefaultEndpoint() string { return "https://api.github.com" }
var (
// Oauth token
// https://developer.github.com/v3/#oauth2-token-sent-in-a-header
// Token type list:
// https://github.blog/2021-04-05-behind-githubs-new-authentication-token-formats/
// https://github.blog/changelog/2022-10-18-introducing-fine-grained-personal-access-tokens/
keyPat = regexp.MustCompile(`\b((?:ghp|gho|ghu|ghs|ghr|github_pat)_[a-zA-Z0-9_]{36,255})\b`)
// TODO: Oauth2 client_id and client_secret
// https://developer.github.com/v3/#oauth2-keysecret
)
// TODO: Add secret context?? Information about access, ownership etc
type userRes struct {
Login string `json:"login"`
Type string `json:"type"`
@@ -45,41 +37,35 @@ type userRes struct {
UserURL string `json:"html_url"`
}
// Keywords are used for efficiently pre-filtering chunks.
// Use identifiers in the secret preferably, or the provider name.
func (s Scanner) Keywords() []string {
return []string{"ghp_", "gho_", "ghu_", "ghs_", "ghr_", "github_pat_"}
func (s Scanner) Keywords() [][]byte {
return [][]byte{[]byte("ghp_"), []byte("gho_"), []byte("ghu_"), []byte("ghs_"), []byte("ghr_"), []byte("github_pat_")}
}
// FromData will find and optionally verify GitHub secrets in a given set of bytes.
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
dataStr := string(data)
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
matches := keyPat.FindAllSubmatch(data, -1)
for _, match := range matches {
// First match is entire regex, second is the first group.
if len(match) != 2 {
continue
}
token := match[1]
token := bytes.TrimSpace(match[1])
s1 := detectors.Result{
DetectorType: detectorspb.DetectorType_Github,
Raw: []byte(token),
Raw: token,
}
if verify {
client := common.SaneHttpClient()
// https://developer.github.com/v3/users/#get-the-authenticated-user
for _, url := range s.Endpoints(s.DefaultEndpoint()) {
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s/user", url), nil)
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s/user", string(url)), nil)
if err != nil {
continue
}
req.Header.Add("Content-Type", "application/json; charset=utf-8")
req.Header.Add("Authorization", fmt.Sprintf("token %s", token))
req.Header.Add("Authorization", fmt.Sprintf("token %s", string(token)))
res, err := client.Do(req)
if err == nil {
if res.StatusCode >= 200 && res.StatusCode < 300 {
@@ -102,7 +88,7 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
}
}
if !s1.Verified && detectors.IsKnownFalsePositive(string(s1.Raw), detectors.DefaultFalsePositives, true) {
if !s1.Verified && detectors.IsKnownFalsePositive(s1.Raw, detectors.DefaultFalsePositives, true) {
continue
}
+6 -5
View File
@@ -5,10 +5,11 @@ import (
"regexp"
"strings"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
"golang.org/x/oauth2/clientcredentials"
"golang.org/x/oauth2/github"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
)
type Scanner struct{ detectors.EndpointSetter }
@@ -28,8 +29,8 @@ const (
// Keywords are used for efficiently pre-filtering chunks.
// Use identifiers in the secret preferably, or the provider name.
func (s Scanner) Keywords() []string {
return []string{"github"}
func (s Scanner) Keywords() [][]byte {
return [][]byte{[]byte("github")}
}
// FromData will find and optionally verify GitHub secrets in a given set of bytes.
@@ -65,7 +66,7 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
s1.Verified = true
}
if !s1.Verified && detectors.IsKnownFalsePositive(string(s1.Raw), detectors.DefaultFalsePositives, true) {
if !s1.Verified && detectors.IsKnownFalsePositive(s1.Raw, detectors.DefaultFalsePositives, true) {
continue
}
+7 -27
View File
@@ -2,7 +2,6 @@ package github_old
import (
"context"
"encoding/json"
"fmt"
"net/http"
"regexp"
@@ -23,15 +22,9 @@ func (Scanner) Version() int { return 1 }
func (Scanner) DefaultEndpoint() string { return "https://api.github.com" }
var (
// Oauth token
// https://developer.github.com/v3/#oauth2-token-sent-in-a-header
keyPat = regexp.MustCompile(`(?i)(?:github|gh|pat)[^\.].{0,40}[ =:'"]+([a-f0-9]{40})\b`)
// TODO: Oauth2 client_id and client_secret
// https://developer.github.com/v3/#oauth2-keysecret
)
// TODO: Add secret context?? Information about access, ownership etc
type userRes struct {
Login string `json:"login"`
Type string `json:"type"`
@@ -40,55 +33,42 @@ type userRes struct {
Company string `json:"company"`
}
// Keywords are used for efficiently pre-filtering chunks.
// Use identifiers in the secret preferably, or the provider name.
func (s Scanner) Keywords() []string {
return []string{"github", "gh", "pat"}
func (s Scanner) Keywords() [][]byte {
return [][]byte{[]byte("github"), []byte("gh"), []byte("pat")}
}
// FromData will find and optionally verify GitHub secrets in a given set of bytes.
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
dataStr := string(data)
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
matches := keyPat.FindAllSubmatch(data, -1)
for _, match := range matches {
// First match is entire regex, second is the first group.
if len(match) != 2 {
continue
}
token := match[1]
specificFPs := []detectors.FalsePositive{"github commit"}
specificFPs := []detectors.FalsePositive{[]byte("github commit")}
if detectors.IsKnownFalsePositive(token, specificFPs, false) {
continue
}
s1 := detectors.Result{
DetectorType: detectorspb.DetectorType_Github,
Raw: []byte(token),
Raw: token,
}
if verify {
client := common.SaneHttpClient()
// https://developer.github.com/v3/users/#get-the-authenticated-user
for _, url := range s.Endpoints(s.DefaultEndpoint()) {
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s/user", url), nil)
if err != nil {
continue
}
req.Header.Add("Content-Type", "application/json; charset=utf-8")
req.Header.Add("Authorization", fmt.Sprintf("token %s", token))
req.Header.Add("Authorization", fmt.Sprintf("token %s", string(token)))
res, err := client.Do(req)
if err == nil {
if res.StatusCode >= 200 && res.StatusCode < 300 {
var userResponse userRes
err = json.NewDecoder(res.Body).Decode(&userResponse)
res.Body.Close()
if err == nil {
s1.Verified = true
}
s1.Verified = true
}
}
}