Skip to content

feat: add Rancher/Cattle token detector#4997

Open
sridhar-3009 wants to merge 4 commits into
trufflesecurity:mainfrom
sridhar-3009:feat/rancher-token-detector
Open

feat: add Rancher/Cattle token detector#4997
sridhar-3009 wants to merge 4 commits into
trufflesecurity:mainfrom
sridhar-3009:feat/rancher-token-detector

Conversation

@sridhar-3009
Copy link
Copy Markdown

@sridhar-3009 sridhar-3009 commented May 31, 2026

Summary

Adds a detector for Rancher Kubernetes management platform API tokens, as requested in #4622.

Token pattern

Rancher tokens are 54–64 lowercase alphanumeric characters, always assigned to named variables:

CATTLE_TOKEN=jswpl27hs8pd88rmw2mgfgrjtpljp85fd5v7rhdwr2s6z22hvt6vjt
RANCHER_API_TOKEN=k7mnp9qr4st2vwx8yz3abc5def1ghi6jkl0mno8pqr2stu4vwx9yz

The regex anchors on the variable name prefix (CATTLE_TOKEN, RANCHER_TOKEN, CATTLE_BOOTSTRAP_PASSWORD, RANCHER_API_TOKEN) to suppress false positives from the broad [a-z0-9] character class.

Validation

When CATTLE_SERVER or RANCHER_URL is found in the same chunk, the detector hits GET {server}/v3 with Authorization: Bearer {token}. HTTP 200 → verified.

Changes

  • pkg/detectors/rancher/rancher.go — detector implementation
  • pkg/detectors/rancher/rancher_test.go — pattern tests (no live calls)
  • proto/detector_type.protoRancherToken = 1053
  • pkg/pb/detector_typepb/detector_type.pb.go — updated generated maps
  • pkg/engine/defaults/defaults.go — registered rancher.Scanner{}

Closes #4622


Note

Low Risk
Isolated new detector following existing SSRF-safe verification patterns; no changes to core scan or auth paths.

Overview
Adds Rancher / Cattle API token detection for TruffleHog, including a new RancherToken detector type (1053) wired into the default engine.

The scanner finds 54–64 character lowercase alphanumeric tokens only when they appear next to known env-style names (CATTLE_TOKEN, RANCHER_TOKEN, CATTLE_BOOTSTRAP_PASSWORD, RANCHER_API_TOKEN). When verification is enabled and a server URL is present in the same chunk (CATTLE_SERVER, RANCHER_URL, RANCHER_SERVER), it checks credentials with GET {server}/v3 and a Bearer token, using the SSRF-safe HTTP client used by other detectors.

Pattern-only tests cover a positive CATTLE_TOKEN case and a negative case without Rancher variable names (no live HTTP).

Reviewed by Cursor Bugbot for commit 19490ee. Bugbot is set up for automated code reviews on this repo. Configure here.

Implements a TruffleHog detector for Rancher Kubernetes management
platform API tokens (CATTLE_TOKEN, RANCHER_TOKEN, CATTLE_BOOTSTRAP_PASSWORD,
RANCHER_API_TOKEN).

Pattern: 54–64 lowercase alphanumeric chars prefixed by a named
cattle/rancher variable (reduces false positives from the broad
character set). Validation hits the /v3 endpoint with a Bearer header
when a CATTLE_SERVER/RANCHER_URL is found in the same chunk.

Closes trufflesecurity#4622
@sridhar-3009 sridhar-3009 requested a review from a team May 31, 2026 08:14
@sridhar-3009 sridhar-3009 requested review from a team as code owners May 31, 2026 08:14
@CLAassistant
Copy link
Copy Markdown

CLAassistant commented May 31, 2026

CLA assistant check
All committers have signed the CLA.

Comment thread pkg/detectors/rancher/rancher.go Outdated

req, err := http.NewRequestWithContext(ctx, "GET", serverURL+"/v3", nil)
if err != nil {
continue
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

continue silently drops detected secrets during verification failure

High Severity

When http.NewRequestWithContext returns an error (e.g., due to a malformed server URL), the continue statement skips the results = append(results, s1) on line 69. This causes a legitimately detected secret to be silently dropped instead of being reported as an unverified finding. Every other multi-part detector in this codebase (e.g., databrickstoken, grafana) always appends the result regardless of verification outcome.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit ffc2490. Configure here.

Comment thread pkg/detectors/rancher/rancher.go Outdated

res, err := client.Do(req)
if err == nil {
defer func() { _ = res.Body.Close() }()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

defer inside loop delays response body cleanup

Medium Severity

The defer res.Body.Close() is inside the for loop, so response bodies accumulate and are only closed when FromData returns rather than after each iteration. Every comparable detector in this codebase extracts verification into a separate function where defer executes promptly upon that function's return. With multiple token matches, this leaks open connections during the loop.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit ffc2490. Configure here.

Comment thread pkg/detectors/rancher/rancher.go Outdated
var _ detectors.Detector = (*Scanner)(nil)

var (
client = common.SaneHttpClient()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SSRF risk: unconstrained URL with permissive HTTP client

Medium Severity

The detector uses common.SaneHttpClient() which lacks local/private IP blocking, but the serverPat regex accepts any https?:// URL from scanned data. Other detectors with unconstrained user-supplied URLs (like artifactory and jiradatacenterpat) specifically use detectors.DetectorHttpClientWithNoLocalAddresses to prevent SSRF. An attacker could embed CATTLE_SERVER=http://169.254.169.254 in scanned content to trigger requests to cloud metadata endpoints during verification.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit ffc2490. Configure here.

- Use DetectorHttpClientWithNoLocalAddresses to prevent SSRF via
  attacker-controlled CATTLE_SERVER values
- Extract verification into verifyToken() helper so defer executes
  promptly after each call, not when FromData returns
- Always append result even when request creation fails; only
  s1.Verified stays false, matching other detector conventions
Copy link
Copy Markdown
Author

@sridhar-3009 sridhar-3009 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you check this ?

Comment thread pkg/detectors/rancher/rancher.go Outdated
client = detectors.DetectorHttpClientWithNoLocalAddresses

// Rancher API tokens: 54–64 lowercase alphanumeric chars, named with cattle/rancher prefixes.
keyPat = regexp.MustCompile(`(?i)(?:CATTLE_TOKEN|RANCHER_TOKEN|CATTLE_BOOTSTRAP_PASSWORD|RANCHER_API_TOKEN)[\w]*\s*[=:]\s*["']?([a-z0-9]{54,64})["']?`)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Case-insensitive flag broadens token matching unintentionally

Medium Severity

The (?i) flag at the start of keyPat applies to the entire regex, including the token capture group [a-z0-9]{54,64}. In RE2, (?i) causes [a-z] to also match uppercase letters, so the capture group effectively becomes [a-zA-Z0-9]{54,64}. This contradicts the PR's stated intent of matching only "lowercase alphanumeric characters" and weakens the false-positive suppression the narrow character class was meant to provide. The (?i) flag is needed for case-insensitive variable name matching, but it needs to be scoped (e.g., via (?i:...)) so it doesn't affect the token capture group.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 9bf0780. Configure here.

Comment thread pkg/engine/defaults/defaults.go Outdated
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/sonarcloud"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/sourcegraph"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/sourcegraphcody"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/rancher"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import and registration placed out of alphabetical order

Low Severity

The rancher import and &rancher.Scanner{} registration are placed between sourcegraphcody and spectralops (in the 's' section) instead of in the 'r' section between ramp and rapidapi where they belong alphabetically. All other detectors in this file follow strict alphabetical ordering.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 9bf0780. Configure here.

… order

- keyPat: use (?i:...) to apply case-insensitivity only to the variable
  name prefix (CATTLE_TOKEN etc.), leaving the token capture group
  [a-z0-9]{54,64} strictly lowercase as intended
- defaults.go: move rancher import and Scanner{} registration to
  alphabetical position between ramp and rapidapi
Copy link
Copy Markdown
Contributor

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 6 total unresolved issues (including 5 from previous reviews).

Fix All in Cursor

Reviewed by Cursor Bugbot for commit df672a6. Configure here.

}
defer func() { _ = res.Body.Close() }()
return res.StatusCode == http.StatusOK
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verification errors silently swallowed, misclassifying results

Medium Severity

verifyToken returns only bool, swallowing all errors (network timeouts, DNS failures, non-200 status codes). Because SetVerificationError is never called, the engine at engine.go:1274 misclassifies transient verification failures as definitively "unverified" instead of "unknown." Users filtering with --results=verified,unknown will silently miss these results. The established pattern (seen in apiflash.go, abstract.go, and most other detectors) is to return (bool, error) and call s1.SetVerificationError(...).

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit df672a6. Configure here.

Return (bool, error) from verifyToken so transient failures (network
timeouts, DNS errors) are reported via s1.SetVerificationError instead
of being silently swallowed. This lets the engine classify results as
'verification error' rather than 'unverified', consistent with the
rest of the detector codebase (apiflash, abstract, etc).
@sridhar-3009
Copy link
Copy Markdown
Author

All 6 issues from Cursor Bugbot reviews are now resolved:

  1. continue silently drops secrets on request creation error — fixed in 9bf0780: removed continue, always append result, verification failure leaves s1.Verified = false.

  2. defer inside loop delays body cleanup — fixed in 9bf0780: extracted verification into verifyToken() helper, defer res.Body.Close() now runs at helper return.

  3. SSRF risk with common.SaneHttpClient() — fixed in 9bf0780: switched to detectors.DetectorHttpClientWithNoLocalAddresses.

  4. (?i) flag broadens token capture group to include uppercase — fixed in df672a6: changed to (?i:...) scoped form so case-insensitivity applies only to the variable name prefix; token capture group [a-z0-9]{54,64} remains strictly lowercase.

  5. Import and registration out of alphabetical order — fixed in df672a6: rancher import and &rancher.Scanner{} moved to the r section between ramp and rapidapi.

  6. verifyToken errors silently swallowed, misclassifying results — fixed in 19490ee: verifyToken now returns (bool, error); FromData calls s1.SetVerificationError(verifyErr, token) on network/DNS failures so the engine can correctly distinguish unverified from verification-error results.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rancher Tokens

2 participants