NewCyngular is now live across AWS, Azure, GCP & on-prem environments — book a demo
All articles
GCPSeptember 20254 min read

Lateral Movement via External GCP Service Accounts

Cyngular Research Team

In Google Cloud Platform (GCP), Service Accounts (SAs) are designed as non-human identities for workloads like Compute Engine, Cloud Functions, and GKE. They hold credentials and roles that often allow automation at scale. But when Service Accounts from outside an organization are granted permissions inside projects, they become a hidden backdoor for attackers.

This article explores how adversaries can exploit external Service Accounts for lateral movement into victim environments, why this is uniquely dangerous, and how defenders can detect and block it using MITRE ATT&CK mapping and Organization Policies.

The risk of external Service Accounts

Unlike human accounts, Service Accounts do not require MFA, login monitoring, or password rotation. If an organization misconfigures IAM and allows a foreign SA to be bound to its resources:

  • Attackers can use their own SA (from a project they control) to authenticate into the victim's projects.
  • These bindings may persist unnoticed for months, especially if granted at the project or organization level.
  • External SAs can then impersonate other SAs inside the victim's environment if granted roles/iam.serviceAccountTokenCreator.

This is effectively trusting another tenant's user. Once granted, it is as if the attacker has a permanent bridge into your cloud.

Attack scenario: external SA backdoor

Step 1: Misconfiguration by a victim project owner

A project owner in Org A mistakenly grants broad access to an external SA from Org B:

json
{
  "role": "roles/storage.admin",
  "members": [
    "serviceAccount:[email protected]"
  ]
}

Step 2: Attacker uses their own Service Account

The attacker activates their SA in their environment:

bash
gcloud auth activate-service-account [email protected] \
  --key-file=attacker-sa-key.json

Step 3: Access victim resources

Now the attacker can directly list buckets inside Org A:

bash
gcloud storage buckets list --project=victim-project

Or with Python:

python
from google.cloud import storage
from google.oauth2 import service_account

creds = service_account.Credentials.from_service_account_file("attacker-sa-key.json")
client = storage.Client(credentials=creds, project="victim-project")

for bucket in client.list_buckets():
    print(bucket.name)

Step 4: Lateral movement via impersonation

If the external SA also has roles/iam.serviceAccountTokenCreator on an internal SA, the attacker can impersonate it:

bash
gcloud auth print-access-token \
  --impersonate-service-account=internal-sa@victim-project.iam.gserviceaccount.com

From here, the attacker can move laterally to other projects or escalate privileges inside Org A.

Detection strategies (MITRE ATT&CK mapping)

  • Detect cross-domain IAM bindings — regularly scan IAM policies for serviceAccount:*@external-domain.com. MITRE: T1098 – Account Manipulation.
  • Monitor GenerateAccessToken calls — audit logs from iamcredentials.googleapis.com reveal impersonation events. MITRE: T1134 – Access Token Manipulation.
  • Watch for abnormal SA behavior — flag when an SA from outside the organization starts accessing storage, BigQuery, or Pub/Sub. MITRE: T1078 – Valid Accounts.
  • Key creation monitoring — alert on google.iam.admin.v1.CreateServiceAccountKey for unexpected SAs. MITRE: T1552 – Unsecured Credentials.

Mitigation strategies

1. Restrict cross-domain members

The most important safeguard is the Organization Policy iam.allowedPolicyMemberDomains. This enforces which identity domains can be granted IAM roles.

Example policy YAML:

yaml
constraint: iam.allowedPolicyMemberDomains
listPolicy:
  allowedValues:
    - "gcp.myorg.com"

Command to apply:

bash
gcloud org-policies set-policy policy.yaml --organization=ORG_ID

This ensures that only SAs from your own domain (e.g., *.gserviceaccount.com linked to your Workspace/Org) can be bound.

2. Disable Service Account key creation

bash
gcloud org-policies enable-enforce iam.disableServiceAccountKeyCreation \
  --organization=ORG_ID

Prevents attackers from exporting long-lived SA keys.

3. Principle of least privilege

  • Avoid assigning Editor or Owner to SAs.
  • Never grant roles/iam.serviceAccountTokenCreator to external accounts.

4. Continuous monitoring

Set alerts on abnormal impersonation events.

The Cyngular take

Cyngular's agentic SOC correlates activity across identity, SaaS and cloud so sequences like this one surface as a single investigation — not a scatter of benign-looking events.