Skip to content

[INS-246] Add Google Gemini API key detector#4649

Merged
mustansir14 merged 14 commits intotrufflesecurity:mainfrom
mustansir14:INS-246-Add-detector-for-Google-Gemini-API-Key
Feb 20, 2026
Merged

[INS-246] Add Google Gemini API key detector#4649
mustansir14 merged 14 commits intotrufflesecurity:mainfrom
mustansir14:INS-246-Add-detector-for-Google-Gemini-API-Key

Conversation

@mustansir14
Copy link
Copy Markdown
Contributor

@mustansir14 mustansir14 commented Jan 8, 2026

Description:

This PR closes #4623 by introducing the Google Gemini API Key detector

All Google Gemini API Keys follow a strict pattern: A prefix AIzaSy followed by 33 characters.
Regex for the detector: \b(AIzaSy[A-Za-z0-9_-]{33})
Note: A trailing word boundary is not added because the key can end with a hyphen, and having a trailing \b will not match such a key.
I have verified the regex by generating 5-10 keys.

For verification, we're using Gemini's GET /v1/models endpoint. This is a safe endpoint that only lists the available models, which means no costs will be incurred. For non-gemini keys, this endpoint will return 403, which indicates that the key is active, just not scoped to Gemini. In this case, we will mark the key as unverified, but set "active_google_key": "true" in the ExtraData, so that the user can distinguish.

Added unit and integration tests as well.

Update: I've tested this with our new method of detector testing. I ran it against both files (the 30gb and 3gb one) and this detector showed up in both of them (which is expected because the Google Cloud API key is a common one). However, it was not in the top 5, so we should be good. See screenshots:
image
image

Checklist:

  • Tests passing (make test-community)?
  • Lint passing (make lint this requires golangci-lint)?

Note

Medium Risk
Introduces a new network-verifying detector and a new protobuf enum value; risk is mainly around false positives/verification behavior and downstream compatibility with the updated detector type list.

Overview
Adds a new googlegemini detector that finds API keys matching AIzaSy… via regex prefiltered by the aizasy keyword, and optionally verifies keys by calling Gemini’s GET /v1/models endpoint.

Verification distinguishes Gemini-enabled keys (200) from active but not Gemini-scoped Google API keys (403, reported with ExtraData["active_google_key"]=true), while invalid keys (400) are treated as unverified. The detector is wired into default scanning (defaults.go) and introduces a new DetectorType_GoogleGeminiAPIKey enum value in proto/detectors.proto (and regenerated detectors.pb.go), with accompanying unit + integration tests and a benchmark.

Written by Cursor Bugbot for commit a0989d8. This will update automatically on new commits. Configure here.

@mustansir14 mustansir14 requested a review from a team January 8, 2026 08:19
@mustansir14 mustansir14 requested review from a team as code owners January 8, 2026 08:19
Comment thread proto/detectors.proto Outdated
PhraseAccessToken = 1037;
Photoroom = 1038;
JWT = 1039;
GoogleGemini = 1040;
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.

GoogleGemini is already quite specific, but are there different types of credentials available for Gemini (for example, API keys vs tokens)? If so, we might consider using a more explicit detector type like GoogleGeminiApiKey or GoogleGeminiToken instead of the generic GoogleGemini. Just a suggestion, not a blocker at all.

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.

+1

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for this. Yes, Google Gemini does have other ways of authenticating. I'll make the change.

_, _ = io.Copy(io.Discard, res.Body)
}()

switch res.StatusCode {
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.

It's common to receive a 403 response in a few situations:

  • the key is not scoped to Gemini, but still valid for other google services
  • the key is "restricted" either via IP address, referer, etc.

Might make sense add a case for 403s just so it's not throwing an error, when those cases are normal.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for this!

You are very much right. I just confirmed this by generating a Google Cloud API Key. I also realized it's not just about adding this case. Getting a 403 means that the key is live, it just does not have the Generative Language API scope enabled.

Now I'm wondering if it makes sense to create a GoogleGeminiAPIKey detector, or simply a GoogleAPIKey detector. What do you think?

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.

I recommend keeping the original intent here and authoring a detector for only Gemini. If any other Google API services surface that are similarly risky, we can adapt then.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I agree with the approach of authoring a detector only for Gemini. My only concern here is that for 403 we'll mark the credential as inactive/rotated, but that's misleading, because the credential will be live, just not scoped to Gemini.

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.

I would endorse that we mark an API key "LIVE" if we're certain that a 403 Forbidden response implies the key is valid and capable of accessing Google services beyond just Gemini.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed.

I've gone ahead and made the changes to make this a GoogleCloudAPIKey detector. @joeleonjr let me know if you have concerns and we can discuss.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

After internal discussion, it has been decided to make this a GoogleGeminiAPIKey detector as originally intended. For other Google Cloud API keys that have gemini disabled, we will mark them as disabled but set "active-google-key": "true" in the ExtraData field.

@mustansir14 mustansir14 changed the title [INS-246] Add Google Gemini API key detector [INS-246] Add Google Cloud API key detector Jan 12, 2026
Comment thread pkg/detectors/googlegemini/googlegemini_integration_test.go Outdated
@mustansir14 mustansir14 changed the title [INS-246] Add Google Cloud API key detector [INS-246] Add Google Gemini API key detector Jan 15, 2026
@joeleonjr
Copy link
Copy Markdown
Contributor

Is it possible to merge this in the next week?

@mustansir14
Copy link
Copy Markdown
Contributor Author

Is it possible to merge this in the next week?

As a safety precaution for EE, we're only merging one detector per week. I'll ask the team if we can merge this one next.

Comment thread pkg/detectors/googlegemini/googlegemini.go
Comment thread pkg/detectors/googlegemini/googlegemini.go Outdated
Comment thread pkg/detectors/googlegemini/googlegemini.go Outdated
Copy link
Copy Markdown

@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.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

return false, nil, nil
default:
return false, nil, fmt.Errorf("unexpected status code: %d", res.StatusCode)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Missing HTTP 401 handler for invalid API keys

Medium Severity

The verify function's status code switch handles 200, 403, and 400 but not 401 (Unauthorized). Google's Generative Language API returns 401 for invalid, missing, or automatically blocked API keys (e.g., keys leaked in public repos). These cases fall through to the default branch, producing a verification error instead of correctly returning false, nil, nil. Many other detectors in the codebase (e.g., browshot, dropbox, elevenlabs) handle both StatusBadRequest and StatusUnauthorized together for invalid keys.

Fix in Cursor Fix in Web

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I have verified with multiple tests that the API never returns 401. It is either 400 for expired, invalid and revoked keys, or 403 for keys without the generative AI permission.

@mustansir14 mustansir14 merged commit 7c84b27 into trufflesecurity:main Feb 20, 2026
14 checks passed
peterfraedrich pushed a commit to peterfraedrich/trufflehog that referenced this pull request Mar 15, 2026
* add google gemini api key detector

* change detector name to google cloud api key, mark as verified if 403 is returned

* add build tags for integration test

* changes in defaults.go

* Revert "changes in defaults.go"

This reverts commit 12e7b6f.

* Revert "change detector name to google cloud api key, mark as verified if 403 is returned"

This reverts commit e46bb29.

* revert google cloud api changes, change keyword to gemini, add extra field active_google_key

* use aizasy as keyword instead of gemini

* close response body after draining

* remove \b from regex to support keys that end with -

* add \b to the beginning
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.

Google Gemini API

6 participants