Scan codebases, GCP projects, and CI pipelines for exposed Google API credentials
Project description
keyguard
Scan codebases, GCP projects, and CI pipelines for exposed Google API credentials — before they get exploited.
The problem: Google retroactively enabled Gemini API access on existing API keys (Maps, Places, etc.) that were designed to be public and embedded in client-side code. When someone on your team enables Gemini in the same GCP project, those already-public keys silently become Gemini credentials — exposing your project to unauthorized AI usage and $80k+ billing incidents (context).
What keyguard does:
keyguard scan— finds credential strings in source files and git history using regex + entropy detectionkeyguard audit— connects to live GCP projects and flags API keys that have Gemini access right nowkeyguard ci— scans GitHub Actions, CircleCI, and GitLab CI logs and variables for leaked credentials
Install
pip install keyguard-scan
Or clone and install in development mode:
git clone https://github.com/arzaan789/keyguard.git
cd keyguard
pip install -e ".[dev]"
Quick Start
# Scan current directory and git history
keyguard scan .
# Audit your live GCP projects
keyguard audit
# Scan CI platforms
keyguard ci
Commands
keyguard scan
Scans source files and git history for exposed credentials using regex + Shannon entropy filtering. Low-entropy placeholders like "REPLACE_ME" or "XXXXXXXX" are automatically ignored.
# Scan a directory (files + full git history)
keyguard scan .
# Files only, skip git history
keyguard scan . --no-git-history
# Export to JSON and SARIF
keyguard scan . --output json --output sarif --out-file report
# Show actual key values (not redacted)
keyguard scan . --no-redact
# Use a custom config file
keyguard scan . --config /path/to/.keyguard.toml
Exit codes: 0 = clean, 1 = findings, 2 = error
keyguard audit
Connects to live GCP projects via the Cloud Resource Manager, Service Usage, and API Keys APIs. Flags keys that are unrestricted (silent Gemini access) or that explicitly allow generativelanguage.googleapis.com while Gemini is enabled on the project.
Authentication uses Application Default Credentials by default — run gcloud auth application-default login first.
# Audit all accessible GCP projects
keyguard audit
# Audit specific project(s)
keyguard audit --project my-project-id --project another-project
# Use a service account key file
keyguard audit --gcp-credentials /path/to/key.json
# Export JSON findings
keyguard audit --output json --out-file gcp-findings.json
Findings:
CRITICAL— key has no API restrictions + Gemini is enabled (the silent Maps→Gemini upgrade scenario)HIGH— key explicitly allowsgenerativelanguage.googleapis.com(intentional but potentially embedded in client code)
keyguard ci
Scans CI platform logs and stored variables for exposed credentials. Supports GitHub Actions, CircleCI, and GitLab CI.
# Scan all configured platforms
keyguard ci
# Scan one platform only
keyguard ci --platform github
# Narrow to a specific repo
keyguard ci --repo my-org/api-service
# Export JSON findings
keyguard ci --output json --out-file ci-findings.json
What it scans:
- GitHub Actions — plaintext repository variables + workflow run job logs
- CircleCI — environment variable names (values are masked by CircleCI) + pipeline job step logs
- GitLab CI — project variables (plaintext) + pipeline job traces
keyguard watch
Re-scans files on every change. Useful during development.
keyguard watch .
keyguard rules list
Lists all active detection rules.
keyguard rules list
keyguard config check
Validates a .keyguard.toml configuration file.
keyguard config check
keyguard config check --config /path/to/.keyguard.toml
Configuration
Create a .keyguard.toml in your project root:
[scan]
paths = ["."]
exclude = ["tests/fixtures/", "**/*.example"]
scan_git_history = true
[output]
format = ["terminal", "json"]
redact = true
[notify]
slack_webhook = "https://hooks.slack.com/services/..."
[rules]
disabled = []
# CI platform authentication and scope
[ci]
github_token = "ghp_xxxxxxxxxxxxxxxxxxxx"
circleci_token = "CCIPAT_xxxxxxxxxxxxxxxx"
gitlab_token = "glpat-xxxxxxxxxxxxxxxxxxxx"
gitlab_url = "https://gitlab.com" # override for self-hosted GitLab
max_runs = 10 # recent runs/pipelines per repo
[ci.github]
orgs = ["my-org"]
repos = ["my-org/specific-repo"] # optional: scan specific repos only
[ci.circleci]
orgs = ["my-org"]
[ci.gitlab]
groups = ["my-group"]
Detection
Keyguard uses a regex + Shannon entropy approach. Each rule defines:
- A pattern that matches the credential's structure (e.g.,
AIza[0-9A-Za-z\-_]{35}for Google API keys) - A minimum entropy threshold that filters out low-entropy placeholders
Built-in rules detect:
| Rule ID | What it finds |
|---|---|
google-api-key |
Google API keys (AIza...) — including Maps keys silently granted Gemini access |
gcp-service-account-key |
GCP service account RSA private keys |
google-oauth-client-secret |
Google OAuth2 client secrets (GOCSPX-...) |
You can add custom rules in .keyguard.toml:
[[rules.extra]]
id = "my-internal-token"
description = "Internal service token"
pattern = "tok-[0-9a-f]{32}"
entropy_min = 3.5
severity = "high"
tags = ["internal"]
CI Integration
GitHub Actions
name: keyguard scan
on: [push, pull_request]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # full history for git scan
- run: pip install keyguard-scan
- run: keyguard scan .
Pre-commit hook
# .pre-commit-config.yaml
repos:
- repo: local
hooks:
- id: keyguard
name: keyguard credential scan
entry: keyguard scan --no-git-history
language: system
pass_filenames: false
Docker
docker run --rm -v $(pwd):/repo ghcr.io/arzaan789/keyguard scan /repo
Output Formats
Terminal (default) — colored table grouped by severity.
JSON — machine-readable findings array:
keyguard scan . --output json --out-file findings.json
SARIF — integrates with GitHub's Security tab and other SAST tools:
keyguard scan . --output sarif --out-file findings.sarif
Slack webhook — posts a summary when findings are detected:
[notify]
slack_webhook = "https://hooks.slack.com/services/..."
Development
git clone https://github.com/arzaan789/keyguard.git
cd keyguard
pip install -e ".[dev]"
pytest
143 tests, 0 failures.
Project structure:
keyguard/
scanner/ # file + git history scanners
engine/ # regex + entropy detection (rules, matcher)
output/ # terminal, JSON/SARIF, webhook
auditor/ # GCP API client + audit logic
ci/ # GitHub Actions, CircleCI, GitLab CI scanners
cli.py # Click CLI entry point
config.py # .keyguard.toml loader
Roadmap
- v1 — File scanner (source code + git history)
- v2 — GCP API auditor (live project audit via GCP APIs)
- v3 — CI platform integration (GitHub Actions, CircleCI, GitLab CI)
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file keyguard_scan-0.1.0.tar.gz.
File metadata
- Download URL: keyguard_scan-0.1.0.tar.gz
- Upload date:
- Size: 32.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e0f5810ecdebef30089dc320ae29c847474dfe1335fdfb6dbb2a6f46463d0b4e
|
|
| MD5 |
2b5b4227582e7e7dce302513ee7f1f96
|
|
| BLAKE2b-256 |
7bcd8b6ff53b6da10107bd1cfd298043cb3f5a4150bf88e8ee87c64db0fec7fe
|
File details
Details for the file keyguard_scan-0.1.0-py3-none-any.whl.
File metadata
- Download URL: keyguard_scan-0.1.0-py3-none-any.whl
- Upload date:
- Size: 25.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e457b608761467b0aad0427d6d0a7343544253fa733f9c97032f1ecf18bb429f
|
|
| MD5 |
2934aaf3a977dfc58be6817481c6842a
|
|
| BLAKE2b-256 |
7379473132001bd4c307448aea124aa6822ec4316d18bf1a6f3b7475ddc4279a
|