Google Cloud incident response: a compromised project
Your Google Cloud project may be compromised. The order of operations: contain the identity, preserve the audit logs, scope with methodNames, then eradicate.
TL;DR. Treat a suspected Google Cloud compromise as an identity incident first. Disable the credential in use (usually a user-managed service account key or a user session), copy the Cloud Audit Logs out of the project before anyone with Owner rights can touch them, then scope with a short list of methodNames: CreateServiceAccountKey, SetIamPolicy, setMetadata, storage.objects.get, DeleteSink. Only then clean up. The free in-browser analyzer runs those detections on an export and gives you a verdict, a timeline and a checklist.
Most Google Cloud incidents I see do not start with an exotic exploit. Google's own Cloud Threat Horizons report (H2 2025) attributes 47.1% of the initial access it observed in H1 2025 to weak or absent credentials and 29.4% to misconfiguration. In practice that means a key file in a repository, a CI variable printed in a build log, or a VM with a weak password. The attacker then does what the permissions allow: grant themselves Owner, start miners, read buckets, and switch off what could alert you.
This guide is the order of operations. Each step links to a deeper article in the series.
Phase 1: triage in the first hour
You have a signal: a billing spike, a Security Command Center finding, an email from Google about an exposed key, or a strange IAM member. Answer three questions fast.
- Which identity? A service account email (
…@PROJECT.iam.gserviceaccount.com), a user, or a personal Gmail account that should not be there. - Which credential? If audit entries carry
authenticationInfo.serviceAccountKeyName, the caller used a user-managed key. If they carryserviceAccountDelegationInfo, someone impersonated a service account and the real actor is further up the chain. - Is it still active? Look at the last entry for that principal and caller IP.
A first Logs Explorer query is enough to answer these:
logName:"cloudaudit.googleapis.com"
protoPayload.authenticationInfo.principalEmail="ci-deployer@PROJECT.iam.gserviceaccount.com"
Phase 2: contain the identity, not the symptoms
Deleting the miner VM feels productive, but if the key that created it still works, it will be back in minutes. Google's guidance for compromised credentials lists the actions per credential type. The ones that matter most:
| Credential in use | Containment |
|---|---|
| User-managed service account key | Disable the key (then delete once you have its ID in your notes); rotate what the service account could read |
| Impersonation | Remove the Token Creator / Service Account User binding from the caller; disable the caller |
| User or Gmail account in IAM | Remove the binding; if it is one of your users, sign it out and reset the password |
| OAuth tokens (gcloud) | Revoke the token; enforce session control for Cloud access |
Then check the IAM policy for other additions. Attackers who obtain Owner rarely stop at one binding. The IAM policy abuse article shows how to read bindingDeltas to list every change.
Phase 3: preserve the evidence before it expires or disappears
Two things destroy cloud evidence: retention and the attacker.
- Retention. The
_Requiredbucket keeps Admin Activity and System Event audit logs for 400 days and cannot be modified; the_Defaultbucket keeps everything else, including Data Access logs, for 30 days by default (quotas and limits, routing overview). - The attacker. With Owner rights they can delete log sinks, add exclusions, shorten
_Defaultretention or delete logs. See defense evasion in Google Cloud.
Export now, widely: the whole suspected period plus a few weeks of baseline, every audit log type, and VPC Flow Logs if they exist. The console download caps at 10,000 entries per download (Logs Explorer interface), so for anything bigger use gcloud logging read or copy the sink bucket. Cloud Audit Logs explained covers each export path.
Phase 4: scope with a short list of methodNames
You do not need to read every entry. A handful of protoPayload.methodName values answer most scoping questions:
| Question | Where to look | Deep dive |
|---|---|---|
| Was a key created or uploaded? | google.iam.admin.v1.CreateServiceAccountKey, UploadServiceAccountKey | Leaked service account key |
| Who impersonated whom? | iamcredentials.googleapis.com GenerateAccessToken, SignBlob, SignJwt; serviceAccountDelegationInfo | Service account impersonation |
| Did anyone gain Owner? | SetIamPolicy with bindingDeltas ADD roles/owner | SetIamPolicy abuse |
| Are VMs backdoored or mining? | compute.instances.setMetadata, setCommonInstanceMetadata, compute.instances.insert with accelerators | Compute Engine abuse |
| Was data taken? | storage.objects.get bursts, storage.setIamPermissions with allUsers, BigQuery copy jobs | GCS and BigQuery exfiltration |
| Did data leave through the network? | VPC Flow Logs, bytes per external IP | VPC Flow Logs analysis |
| Did they blind you? | DeleteSink, UpdateSink, CreateExclusion, auditConfigDeltas REMOVE | Defense evasion |
Pivot on two keys throughout: the caller IP (protoPayload.requestMetadata.callerIp) and the principal. An attacker IP that appears for a service account key and then for a brand-new Gmail Owner links the two stages together. The analyzer does exactly this correlation and raises an "attack chain" finding when the same IP or principal moves from access to takeover actions.
Note that callerIp is not always a public address: Google documents that calls between Google services show private, and calls from VMs without external IPs may show the internal address or gce-internal-ip (AuditLog reference).
Phase 5: eradicate and recover
Once the scope is known, remove every foothold in one pass, otherwise the attacker notices and moves:
- delete the keys, HMAC keys and service accounts created by the attacker;
- remove the IAM bindings, restore relaxed organization policies;
- rebuild (do not clean) VMs whose startup scripts or SSH keys were changed, after snapshotting their disks;
- make buckets private again and enforce public access prevention;
- restore sinks and Data Access logging, ideally to an aggregated sink in a project the workload owners cannot administer.
The tool's remediation checklist is generated from the findings in that order: containment first, then persistence, then logging.
Phase 6: close the gaps that made it possible
The post-incident list is usually the same:
- enforce
iam.disableServiceAccountKeyCreationand move CI to Workload Identity Federation; - set
iam.serviceAccountKeyExposureResponsetoDISABLE_KEYso keys Google finds in public places are disabled automatically (Google Cloud blog); - restrict IAM members to your domains with domain restricted sharing;
- enable Data Access audit logs at least for IAM and Cloud Storage; the limitations article explains why their absence is the most common dead end.
Where the analyzer fits
The GCP Forensics analyzer takes the exports from phase 3 and runs the scoping of phase 4: 32 rules, 5 stateful analytics and one attack-chain correlation, all published in the page's rules table. It runs in your browser; the logs are not uploaded. The step-by-step guide shows the workflow, and the fictional walkthrough shows the output on a complete incident.
It does not replace judgment. A key used from a CI provider's IP or an Owner granted to a consultant can be legitimate; confirm each finding with its owner. And GKE audit entries are set aside for Kubernetes Forensics, Workspace entries for Google Workspace Forensics.
Frequently asked questions
What is the first thing to do when a Google Cloud project is compromised?
Stop the credential the attacker is using (disable the service account key, suspend the user, revoke tokens) and, in the same hour, copy the audit logs out of the project. Everything else comes after those two steps.
Which logs show what an attacker did in Google Cloud?
Cloud Audit Logs. Admin Activity logs are always on and show configuration changes (IAM, VMs, sinks). Data Access logs show reads of data but are off by default for most services. VPC Flow Logs show network traffic of VMs if they were enabled on the subnet.
How far back can I investigate?
Admin Activity and System Event logs are kept 400 days in the _Required bucket. Data Access and Policy Denied logs go to the _Default bucket, kept 30 days by default. Older data only exists if a sink exported it.
Further reading
- Respond to compromised Google Cloud credentials — Google Cloud documentation.
- Best practices for Cloud Audit Logs — Google Cloud documentation.
- MITRE ATT&CK IaaS matrix — the techniques the findings map to.
- Cloud Threat Horizons Report H2 2025 — Google Cloud's initial-access statistics.