|
| 1 | +# `exfil.cloud-cred-read` |
| 2 | + |
| 3 | +Block reads of cloud-SDK credential stores not already covered by `rogue.secret-read`. |
| 4 | + |
| 5 | +## What it catches |
| 6 | + |
| 7 | +| Provider | Path | Holds | |
| 8 | +|---|---|---| |
| 9 | +| gcloud | `~/.config/gcloud/application_default_credentials.json` | ADC OAuth2 refresh token | |
| 10 | +| gcloud | `~/.config/gcloud/access_tokens.db`, `credentials.db` | Account credentials | |
| 11 | +| gcloud | `~/.config/gcloud/legacy_credentials/` | Per-account creds | |
| 12 | +| Azure CLI | `~/.azure/accessTokens.json`, `azureProfile.json` | Bearer tokens, sub IDs | |
| 13 | +| Azure CLI | `~/.azure/msal_token_cache.{json,bin}` | MSAL token cache | |
| 14 | +| Docker | `~/.docker/config.json` | Container registry auth | |
| 15 | +| GCP | `*service*account*.json` | Service-account private keys | |
| 16 | +| Terraform | `~/.terraform.d/credentials.tfrc.json` | TFC/TFE tokens | |
| 17 | +| Terraform | `terraform.tfstate` (and `.backup`) | **Rendered secrets baked into state** | |
| 18 | +| Helm | `~/.helm/repository/repositories.yaml`, `~/.helm/registry/config.json` | Chart registry creds | |
| 19 | +| Databricks | `~/.databrickscfg`, `~/.databricks/token-cache.json` | Workspace tokens | |
| 20 | +| Snowflake | `~/.snowflake/connections.toml` | Per-connection passwords | |
| 21 | +| Heroku | `~/.config/heroku/config.json` | API key | |
| 22 | +| GitHub CLI | `~/.config/gh/hosts.yml` | OAuth tokens for `gh` | |
| 23 | +| 1Password CLI | `~/.config/op/config` | Account configuration | |
| 24 | + |
| 25 | +## Why it matters |
| 26 | + |
| 27 | +This rule complements `rogue.secret-read`, which already covers `.aws/credentials`, `.aws/config`, kubeconfig, SSH keys, .npmrc, .pypirc, .netrc, and .gnupg. Together they form a near-complete moat around the file-system credential surface. |
| 28 | + |
| 29 | +The threat model is the same as the [Supabase MCP service-role incident](https://generalanalysis.com/blog/supabase-mcp-blog) — once a credential enters the agent's context, every downstream tool call is a potential exfil channel: |
| 30 | + |
| 31 | +> *The cursor assistant operates the Supabase database with elevated access via the service_role, which bypasses all row-level security (RLS) protections.* |
| 32 | +
|
| 33 | +…the same logic applies to a GCP service-account JSON or an Azure access token. A prompt-injected agent that has just read `~/.config/gcloud/application_default_credentials.json` can do anything that account can do across GCP — and the credential is now also sitting in the LLM provider's context window. |
| 34 | + |
| 35 | +`terraform.tfstate` is the under-appreciated entry: Terraform writes provisioned-resource secrets (DB passwords, generated API keys) into state in plaintext. Reading state is reading every secret Terraform has ever provisioned for that workspace. |
| 36 | + |
| 37 | +## False positives |
| 38 | + |
| 39 | +- A repo's own `terraform.tfstate` checked into version control (rare, anti-pattern, but happens) is caught — that's intentional, the secrets are real. |
| 40 | +- An agent debugging a `gh auth` issue that wants to inspect `~/.config/gh/hosts.yml` is denied. Use `gh auth status` instead — it doesn't leak the token. |
| 41 | +- Azure CLI's `~/.azure/clouds.config` (cloud profile, no secrets) is **not** caught. |
| 42 | + |
| 43 | +## Test it |
| 44 | + |
| 45 | +```bash |
| 46 | +agentlock fake-hook --session <id> --tool Read \ |
| 47 | + --path ~/.config/gcloud/application_default_credentials.json |
| 48 | +# expect: deny |
| 49 | + |
| 50 | +agentlock fake-hook --session <id> --tool Read \ |
| 51 | + --path ~/.config/gcloud/active_config |
| 52 | +# expect: deny (just account name, but read is the install step for follow-on attacks) |
| 53 | +``` |
| 54 | + |
| 55 | +## Sources |
| 56 | + |
| 57 | +- [Supabase MCP can leak your entire SQL database — General Analysis](https://generalanalysis.com/blog/supabase-mcp-blog) |
| 58 | +- [When AI Has Root: Lessons from the Supabase MCP Data Leak — Pomerium](https://www.pomerium.com/blog/when-ai-has-root-lessons-from-the-supabase-mcp-data-leak) |
| 59 | +- [From .env to Leakage: Mishandling of Secrets by Coding Agents — Knostic](https://www.knostic.ai/blog/claude-cursor-env-file-secret-leakage) |
0 commit comments