Skip to content
5 changes: 5 additions & 0 deletions binary/proto/scan_result.proto
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,7 @@ message SecretData {
SendGridAPIKey sendgrid_api_key = 72;
DenoPat deno_pat = 73;
HerokuSecretKey heroku_secret_key = 74;
CloudflareAPIToken cloudflare_api_token = 75;
}

message GCPSAK {
Expand Down Expand Up @@ -897,6 +898,10 @@ message SecretData {
string username = 2;
}

message CloudflareAPIToken {
string token = 1;
}

message DenoPat {
string pat = 1;
}
Expand Down
722 changes: 394 additions & 328 deletions binary/proto/scan_result_go_proto/scan_result.pb.go

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions binary/proto/secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
velesazurestorageaccountaccesskey "github.com/google/osv-scalibr/veles/secrets/azurestorageaccountaccesskey"
velesazuretoken "github.com/google/osv-scalibr/veles/secrets/azuretoken"
velescircleci "github.com/google/osv-scalibr/veles/secrets/circleci"
"github.com/google/osv-scalibr/veles/secrets/cloudflareapitoken"
"github.com/google/osv-scalibr/veles/secrets/cratesioapitoken"
velescursorapikey "github.com/google/osv-scalibr/veles/secrets/cursorapikey"
"github.com/google/osv-scalibr/veles/secrets/denopat"
Expand Down Expand Up @@ -147,6 +148,8 @@ func velesSecretToProto(s veles.Secret) (*spb.SecretData, error) {
return mysqlMyloginSectionToProto(t), nil
case dockerhubpat.DockerHubPAT:
return dockerHubPATToProto(t), nil
case cloudflareapitoken.CloudflareAPIToken:
return cloudflareAPITokenToProto(t), nil
case denopat.DenoUserPAT:
return denoUserPATToProto(t), nil
case denopat.DenoOrgPAT:
Expand Down Expand Up @@ -426,6 +429,16 @@ func denoOrgPATToProto(s denopat.DenoOrgPAT) *spb.SecretData {
}
}

func cloudflareAPITokenToProto(s cloudflareapitoken.CloudflareAPIToken) *spb.SecretData {
return &spb.SecretData{
Secret: &spb.SecretData_CloudflareApiToken{
CloudflareApiToken: &spb.SecretData_CloudflareAPIToken{
Token: s.Token,
},
},
}
}

func digitaloceanAPIKeyToProto(s velesdigitalocean.DigitaloceanAPIToken) *spb.SecretData {
return &spb.SecretData{
Secret: &spb.SecretData_Digitalocean{
Expand Down Expand Up @@ -1144,6 +1157,8 @@ func velesSecretToStruct(s *spb.SecretData) (veles.Secret, error) {
return mysqlMyloginSectionToStruct(s.GetMysqlMyloginSection()), nil
case *spb.SecretData_DockerHubPat_:
return dockerHubPATToStruct(s.GetDockerHubPat()), nil
case *spb.SecretData_CloudflareApiToken:
return cloudflareAPITokenToStruct(s.GetCloudflareApiToken()), nil
case *spb.SecretData_DenoPat_:
return denoPATToStruct(s.GetDenoPat()), nil
case *spb.SecretData_GitlabPat_:
Expand Down Expand Up @@ -1401,6 +1416,12 @@ func dockerHubPATToStruct(kPB *spb.SecretData_DockerHubPat) dockerhubpat.DockerH
}
}

func cloudflareAPITokenToStruct(kPB *spb.SecretData_CloudflareAPIToken) cloudflareapitoken.CloudflareAPIToken {
return cloudflareapitoken.CloudflareAPIToken{
Token: kPB.GetToken(),
}
}

func denoPATToStruct(kPB *spb.SecretData_DenoPat) veles.Secret {
pat := kPB.GetPat()
if len(pat) >= 4 && pat[:4] == "ddp_" {
Expand Down
1 change: 1 addition & 0 deletions docs/supported_inventory_types.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ See the docs on [how to add a new Extractor](/docs/new_extractor.md).
| Bitbucket | `secrets/bitbucketcredentials` |
| CircleCI Personal Access Token | `secrets/circlecipat` |
| CircleCI Project Token | `secrets/circleciproject` |
| Cloudflare API Token | `secrets/cloudflareapitoken` |
| Crates.io API Token | `secrets/cratesioapitoken` |
| Cursor API key | `secrets/cursorapikey` |
| DigitalOcean API key | `secrets/digitaloceanapikey` |
Expand Down
2 changes: 2 additions & 0 deletions enricher/enricherlist/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import (
"github.com/google/osv-scalibr/veles/secrets/anthropicapikey"
"github.com/google/osv-scalibr/veles/secrets/awsaccesskey"
"github.com/google/osv-scalibr/veles/secrets/circleci"
"github.com/google/osv-scalibr/veles/secrets/cloudflareapitoken"
"github.com/google/osv-scalibr/veles/secrets/cratesioapitoken"
"github.com/google/osv-scalibr/veles/secrets/cursorapikey"
"github.com/google/osv-scalibr/veles/secrets/denopat"
Expand Down Expand Up @@ -123,6 +124,7 @@ var (
fromVeles(slacktoken.NewAppConfigRefreshTokenValidator(), "secrets/slackconfigrefreshtokenvalidate", 0),
fromVeles(slacktoken.NewAppConfigAccessTokenValidator(), "secrets/slackconfigaccesstokenvalidate", 0),
fromVeles(dockerhubpat.NewValidator(), "secrets/dockerhubpatvalidate", 0),
fromVeles(cloudflareapitoken.NewValidator(), "secrets/cloudflareapitokenvalidate", 0),
fromVeles(denopat.NewUserTokenValidator(), "secrets/denopatuservalidate", 0),
fromVeles(denopat.NewOrgTokenValidator(), "secrets/denopatorgvalidate", 0),
fromVeles(gcpsak.NewValidator(), "secrets/gcpsakvalidate", 0),
Expand Down
2 changes: 2 additions & 0 deletions extractor/filesystem/list/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ import (
"github.com/google/osv-scalibr/extractor/filesystem/sbom/cdx"
"github.com/google/osv-scalibr/extractor/filesystem/sbom/spdx"
"github.com/google/osv-scalibr/extractor/filesystem/secrets/awsaccesskey"
"github.com/google/osv-scalibr/extractor/filesystem/secrets/cloudflareapitoken"
"github.com/google/osv-scalibr/extractor/filesystem/secrets/convert"
"github.com/google/osv-scalibr/extractor/filesystem/secrets/gitbasicauth/bitbucket"
"github.com/google/osv-scalibr/extractor/filesystem/secrets/gitbasicauth/codecatalyst"
Expand Down Expand Up @@ -329,6 +330,7 @@ var (
codecatalyst.Name: {codecatalyst.New},
codecommit.Name: {codecommit.New},
bitbucket.Name: {bitbucket.New},
cloudflareapitoken.Name: {cloudflareapitoken.New},
}

// SecretDetectors for Detector interface.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package cloudflareapitoken extends the veles cloudflareapitoken.Detector to search inside
// Cloudflare-specific configuration files
package cloudflareapitoken

import (
"strings"

"github.com/google/osv-scalibr/extractor/filesystem"
"github.com/google/osv-scalibr/extractor/filesystem/secrets/convert"
"github.com/google/osv-scalibr/veles/secrets/cloudflareapitoken"

cpb "github.com/google/osv-scalibr/binary/proto/config_go_proto"
)

const (
// Name is the name of the extractor
Name = "secrets/cloudflareapitoken"
// Version is the version of the extractor
Version = 0
)

// FileRequired reports whether the plugin should scan the given file.
// It restricts scanning to paths that contain "cloudflare" in the path or filename.
func FileRequired(api filesystem.FileAPI) bool {
path := strings.ToLower(api.Path())
return strings.Contains(path, "cloudflare")
}

// New returns a filesystem.Extractor which extracts Cloudflare API Tokens using the cloudflareapitoken.Detector
func New(_ *cpb.PluginConfig) (filesystem.Extractor, error) {
Comment thread
erikvarga marked this conversation as resolved.
return convert.FromVelesDetectorWithRequire(
cloudflareapitoken.NewDetector(), Name, Version, FileRequired,
), nil
}
Loading
Loading