When an attacker gets a working credential into a Google Cloud project, usually a leaked service account key, an OAuth token from a developer laptop or an over-privileged service account, they can create GPU instances, read buckets and BigQuery datasets, and mint new keys that outlive the first one. Responding well depends on knowing which credentials Google Cloud lets you revoke and which you can only wait out, and on reading Cloud Audit Logs before they age out. This playbook covers how a project compromise shows up, triage questions, containment in priority order (service account keys, deny policies, organisation policy lockdown), eradication, recovery, evidence to preserve and notification triggers. It is written for cloud security teams, incident responders and Google Cloud platform owners. Cross-provider principles live in the Cloud Incident Response Guide; this page stays on what is specific to Google Cloud.
This is an independent guide from NHI Mgmt Group, based on Google Cloud's public documentation as of November 2026. It is not sponsored or reviewed by Google. Product features change, so confirm settings against Google Cloud's current documentation.
Key takeaways
- Disabling a key does not end the session. Google documents that disabling a service account key does not revoke short-lived tokens already issued from it; those last up to 60 minutes (or 12 hours with an extended lifetime policy), so disable the service account or apply a deny policy as well.
- Admin Activity logs are always there; Data Access logs may not be. Admin Activity, System Event and Policy Denied logs are always written, but Data Access logs are off by default except for BigQuery, which limits what you can prove was read.
- Organisation policy stops the next key. Enforcing
iam.managed.disableServiceAccountKeyCreationandiam.managed.disableServiceAccountKeyUploadblocks the attacker's favourite persistence move while you clean up. - Password resets do not revoke tokens. Google notes that suspending a user or resetting a password does not invalidate OAuth tokens an attacker already holds; revoke the tokens and the gcloud grant explicitly.
- Scope at organisation level. A principal with roles on a folder or the organisation puts every project under it in scope, and attackers often create new projects to hide resources.
How the incident shows up
Most project compromises are found by billing alerts, a Security Command Center finding or a Google notification about an exposed key. The table maps signals to likely causes, using Event Threat Detection finding names as Google lists them.
| Signal | Where it appears | What it suggests |
|---|---|---|
| Account has leaked credentials | Security Command Center (Event Threat Detection) | A service account key was found exposed publicly |
| Persistence: Service Account Key Created | Security Command Center | New key minted for persistence (ATT&CK T1098.001) |
| Persistence: IAM Anomalous Grant | Security Command Center | Unusual role grant, often to an outside account (T1098.003) |
| Persistence: New Geography; Initial Access: Dormant Service Account Action | Security Command Center | Credential used from an unusual place, or an idle service account suddenly active (T1078.004) |
| Privilege Escalation: Anomalous Service Account Impersonator for Admin Activity | Security Command Center | Impersonation chains used to reach a more privileged account |
| Impact: GPU Instance Created; Malware: Cryptomining Bad IP or Bad Domain | Security Command Center, billing | Compute hijacking for crypto-mining (T1496.001) |
| Exfiltration: BigQuery Data Exfiltration | Security Command Center | Data copied out of BigQuery (T1537) |
| Defense Evasion: Modify VPC Service Control | Security Command Center | Perimeter changed to allow data out |
| Spend spike, quota increase requests, new projects | Billing reports, budgets, Resource Manager | Resource abuse, possibly outside the projects you watch |
Google also notes an organisation policy, iam.serviceAccountKeyExposureResponse, whose DISABLE_KEY value disables keys Google detects as exposed; since 16 June 2024 that is the default behaviour when no value is set. If a key was disabled automatically, treat it as an incident, not a closed event. For key hygiene before an incident see the Google Cloud Service Account Keys Security Guide.
Triage questions
- Which credential type is involved? Service account key, OAuth or gcloud user credential, Application Default Credentials file, API key, OAuth client secret or federated token. Each has a different revocation path.
- Which principal, and where does it hold roles? Check IAM at project, folder and organisation level, plus resource-level bindings on buckets and datasets, and which service accounts it can impersonate (
roles/iam.serviceAccountTokenCreator,roles/iam.serviceAccountUser). - When did it start? Find the first use in Admin Activity audit logs. The
_Defaultbucket keeps logs 30 days by default and_Required400 days; anything older depends on sinks. - Were Data Access logs on? If not, reads from Cloud Storage and most services are invisible; BigQuery Data Access logs are on by default.
- What did the attacker create? New keys, service accounts, user accounts, project-level SSH keys, VMs, functions, buckets and projects, as Google's compromised credentials guidance directs.
- Is Google Workspace or Cloud Identity also affected? If a user account was the entry point, run the Google Workspace Tenant Compromise Playbook in parallel.
- Is personal or regulated data reachable? That decides the notification clock.
Containment priorities
Google's own core rule is to issue and deploy a replacement before revoking the old credential where a workload depends on it. In an active compromise, accept some outage for credentials the attacker holds.
- Preserve logs: confirm or create an aggregated organisation sink to a logging bucket, BigQuery dataset or Cloud Storage bucket in a separate project, so audit logs survive past bucket retention and cannot be removed by the compromised principal.
- Stop the key: disable the compromised key with
gcloud iam service-accounts keys disable KEY_ID --iam-account=SA_EMAIL --project=PROJECT_ID(the console can view but not disable keys). Disable rather than delete first, so you can confirm what breaks. - Stop issued tokens: because disabling the key leaves short-lived tokens valid, disable the service account, or apply an IAM deny policy to
principal://iam.googleapis.com/projects/-/serviceAccounts/SA_EMAIL, for at least 60 minutes (longer if a lifetime extension applies). - Cut impersonation: remove Service Account Token Creator and Service Account User grants held by unauthorised principals, and
roles/iam.workloadIdentityUserbindings for federated identities you do not recognise. - Revoke user tokens: for a compromised user, remove gcloud from the user's connected apps (Workspace admin, or the user at their Google Account permissions page), revoke specific tokens through the OAuth revocation endpoint, and enforce Google Cloud session control with a short reauthentication frequency.
- Lock down by organisation policy: enforce
iam.managed.disableServiceAccountKeyCreation,iam.managed.disableServiceAccountKeyUploadandiam.managed.preventPrivilegedBasicRolesForDefaultServiceAccountson the organisation or affected folder. Organisations created on or after 3 May 2024 already enforce the key creation and upload constraints by default; check they have not been overridden. See the Google Cloud Organization Policy Guide. - Isolate attacker resources: stop unexpected VMs (prioritise Compute Engine, as Google advises) and snapshot their disks before deletion; remove external IPs or apply deny firewall rules to stop outbound mining or exfiltration.
Eradication
- Keys: list keys on every service account in scope; delete keys created during the incident window and any user-managed key without a known owner. Replace needed keys with attached service accounts or workload identity federation. See How to inventory Google Cloud service account keys and replace them with federation.
- IAM bindings: compare policies at organisation, folder, project and resource level with your infrastructure as code. Remove outside members, basic roles (Owner, Editor) added during the incident and new custom roles.
- Service accounts and users: delete service accounts the attacker created; review project-level SSH keys and OS Login grants; remove unknown Cloud Identity users.
- Other credentials: rotate API keys with Rotate key on the Credentials page, then delete the previous key; reset OAuth client secrets with Reset Secret; on affected workstations run
gcloud auth application-default revokeand removeapplication_default_credentials.json. - Workloads: rebuild VMs, GKE nodes and functions that ran attacker code from trusted images and source; check startup scripts, metadata and scheduled jobs for persistence.
- Projects and resources: search the whole organisation for projects, buckets, App Engine apps and VMs created in the window; delete after evidence capture.
- Secrets: rotate anything stored in Secret Manager, environment variables or buckets the attacker could read.
Disable, delete or rebuild
| Situation | Action | Reason |
|---|---|---|
| Key leaked, workload still needs the service account | Disable key, deploy replacement or federation, then delete | Google recommends disabling before deleting to confirm impact |
| Service account used for attacker actions | Disable account or deny policy, then rebuild with new account | Removes issued tokens and any hidden grants to that account |
| Owner-level access for days, incomplete logs | Rebuild the project from code in a clean project | Persistence you have not found leaves with the old project |
| Small team, single project, complete logs | Clean in place, rotate everything readable | Faster, and every change can be accounted for |
Recovery
- Re-enable the service account only after at least 60 minutes (or the extended lifetime period), then remove the temporary deny policy, as Google's guidance sets out.
- Restore data from backups or object versions taken before the first attacker action.
- Turn on Data Access logs for the services that hold sensitive data, so a repeat would be visible.
- Set
constraints/iam.serviceAccountKeyExpiryHours(1 to 2,160 hours) where keys must remain. - Keep Event Threat Detection findings routed to the SOC, and set budgets with alerts on every billing account.
- Watch the incident's principals, IPs and user agents for at least 30 days.
Useful measures: time from first finding to key and account disabled, number of user-managed keys (falling), percentage of projects covered by the key creation constraint, Data Access log coverage of sensitive services, and spend back to baseline.
Evidence to preserve
| Evidence | Where | Notes |
|---|---|---|
| Admin Activity audit logs | cloudaudit.googleapis.com%2Factivity | Kept 400 days in _Required; export the incident window |
| Data Access audit logs | cloudaudit.googleapis.com%2Fdata_access | Only where enabled (BigQuery by default) |
| Policy Denied and System Event logs | %2Fpolicy, %2Fsystem_event | Show blocked attempts and system changes |
| Impersonation chains | Filter on protoPayload.authenticationInfo.serviceAccountDelegationInfo.firstPartyPrincipal.principalEmail | Identifies the real principal behind a service account |
| Security Command Center findings | Findings export; query access.principal_email | Do not set findings to inactive until investigation ends |
| IAM policy snapshots | Organisation, folder, project, resource | State at discovery |
| Disk snapshots of attacker VMs | Compute Engine snapshots | Take before deletion |
| Billing export | Billing to BigQuery | Scope of abuse; supports any billing review |
Keep evidence in a dedicated project with restricted access and record hashes and chain of custody, in line with NIST SP 800-53 AU-9 and AU-11. Google's guidance also notes that Cloud Customer Care can help locate logs, and that a locked-out customer without a support entitlement can use the Support Contact Troubleshooter to reach the access recovery team.
Notification triggers
- GDPR and UK GDPR: Article 33 requires notifying the supervisory authority without undue delay and, where feasible, within 72 hours of becoming aware of a personal data breach, unless it is unlikely to result in a risk to individuals; Article 34 covers telling affected individuals where risk is high.
- NIS2: in-scope EU entities send an early warning within 24 hours and an incident notification within 72 hours of becoming aware of a significant incident (Article 23, as transposed nationally).
- SEC: US listed companies disclose a material cybersecurity incident on Form 8-K Item 1.05 within four business days of determining materiality.
- Contracts: customer agreements and data processing terms often require faster notice than law.
See the Breach Notification Laws by Country Guide for other jurisdictions.
Common failure patterns
- Deleting the key and declaring victory: tokens minted from the key keep working for up to an hour, and any second key or impersonation grant the attacker added keeps working indefinitely.
- Watching only the alerting project: attackers with folder or organisation roles create resources in new or forgotten projects; search the whole resource hierarchy and billing account.
- Trusting a password reset: OAuth refresh tokens and gcloud grants survive it; revoke them explicitly.
- Losing the logs: the
_Defaultbucket keeps 30 days by default, so a slow investigation without a sink loses the start of the timeline. - Marking findings inactive too early: Google advises leaving findings active until the threat is eliminated and the investigation is complete, so related findings stay visible.
- Re-enabling too soon: re-enabling a service account inside the token lifetime window restores any tokens the attacker still holds.
Framework mapping
| Phase | NIST CSF 2.0 | NIST SP 800-53 Rev 5 | ATT&CK techniques addressed |
|---|---|---|---|
| Detection and triage | DE.CM-03, RS.AN-03 | AU-6, IR-4 | T1078.004, T1552.001 |
| Containment and eradication | RS.MA-01 | IA-5, AC-2, AC-2(3) | T1098.001, T1098.003, T1496.001 |
| Evidence | RS.AN-03 | AU-9, AU-11 | T1530, T1537 |
| Recovery and notification | RC.RP-01, RS.CO-02 | IR-6 | T1485 |
Practitioner checklist
- An aggregated organisation log sink exports audit logs to a separate, restricted project.
- Data Access logs are on for services holding sensitive data.
- Key creation and key upload constraints are enforced organisation-wide, with exceptions documented.
iam.serviceAccountKeyExposureResponseis set toDISABLE_KEYor left at its default.- Responders have tested commands for disabling keys, disabling service accounts and applying deny policies.
- The runbook covers each credential type: keys, user OAuth tokens, ADC files, API keys, OAuth client secrets, federated tokens.
- Event Threat Detection findings and billing alerts route to the SOC.
- A break-glass organisation administrator exists and is tested, independent of everyday admin accounts.
- Infrastructure as code holds the known good IAM state for comparison.
Standards and references
- Google Cloud: Handle compromised Google Cloud credentials
- Google Cloud: Disable and enable service account keys
- Google Cloud: Restricting service account usage
- Google Cloud: Cloud Audit Logs overview
- Google Cloud: Logging quotas and limits
- Google Cloud: Security Command Center threat findings index
- Google Cloud: Investigate and respond to threat findings
Related NHI Mgmt Group resources: Cloud Incident Response Guide, Google Cloud IAM and Service Accounts Guide, Google Cloud Audit Logs Guide, Cryptojacking Incident Response Playbook.