-
Notifications
You must be signed in to change notification settings - Fork 28
Authentication Reference
If you are new to GCPwn, read Getting Started first.
This page is the canonical authentication reference for GCPwn. It covers each auth mode, setup patterns, startup syntax, and in-workspace credential operations.
- Auth Modes at a Glance
- GCPwn Startup Commands
- After Startup
- Non-Interactive Runs (
--module) - Tokeninfo Quick Note
- Application Default Credentials (ADC)
- OAuth2 Token
- No Service Account Key? Load a User Token
- Service Account Key
- Google Workspace (Domain-Wide Delegation)
- Auth Operational Notes
- Common Auth Errors
- Source References
| Auth Type | Supported in GCPwn | Typical Credential Source | Rotation Model | Common Use |
|---|---|---|---|---|
ADC (adc) |
Yes | Local Google auth defaults / ADC JSON | Refresh-token backed OAuth flow | Standard operator workflow with gcloud. Can result in OAuth2 tokens for next row being created, but has refresh mechanism backing. |
OAuth2 bare token (oauth2 --token) |
Yes | Direct bearer token input | Short-lived bearer token, no refresh material | Testing standalone delegated/harvested access tokens identified (ex ya29.a0AfH6SM...) |
OAuth2 token file (oauth2 --token-file) |
Yes | An authorized_user-shaped JSON (a token.json, same shape as an ADC file) |
Refresh-token backed — reloads/auto-renews like ADC | Loading a pre-obtained user credential — one you obtained elsewhere, recovered from a compromised host, or exported from another tool. |
Service account key (service-acc-key / service) |
Yes | Service account JSON key file | Long-lived key unless rotated | Service-account identity operations |
At startup, add credentials with one of the following patterns:
adc
adc <credential_name> [--filepath-to-adc <adc_json_path>] [--tokeninfo]
oauth2
oauth2 <credential_name> --token <access_token> [--tokeninfo]
service-acc-key
service-acc-key <credential_name> --service-file <service_account_json_path>
Quick startup examples:
adc corp-adc --filepath-to-adc ~/.config/gcloud/application_default_credentials.json
oauth2 redteam-token --token ya29.a0AfH6SM...
service-acc-key app-sa --service-file /tmp/app-sa.json
You can also select an existing credential by name/index, or press Enter to continue without loading credentials.
The startup screen above is a shorthand for the three most common cases.
--token-file(no service account / no ADC needed — see below) is only available via the in-workspacecreds addcommand, not the startup menu — press Enter to skip startup creds (or load any existing credential) and run it once you're in the workspace.
creds listcreds swap [<credname>]creds info [<credname>] [--csv]creds tokeninfo [<credname>]creds add <credname> --type <adc|oauth2|service> [credential flags...] [--assume]creds update [<credname>] --type <adc|oauth2|service> [credential flags...] [--assume]
Add new credentials at startup (adc, oauth2, service-acc-key), or in-workspace via creds add
(strictly more options, including --token-file), then use creds update to refresh stored
credentials.
For full workspace command coverage, see Workspace Instructions.
Some workflows (CI, scripting, scheduled scans) need to run a single module without dropping into the interactive REPL. GCPwn supports two non-interactive "passthrough" modes from the shell.
Run an unauthenticated module directly — no workspace or credential needed:
gcpwn --module unauth_apikey_enum_all_scopes --api-key AIza...
gcpwn --module unauth_bucketbrute --keyword acme --checkOnly unauthenticated modules (the unauth_* family) are allowed here. --project-id
optionally supplies a project context for modules that derive target URLs from it.
Run an authenticated module against a stored credential by supplying the workspace and credential names as flags — the credential must already have been added to that workspace via a previous interactive session (see GCPwn Startup Commands):
# Enumerate IAM against the credential's own project
gcpwn --module enum_iam --workspace WORKSPACE_NAME --cred CRED_NAME --current-project
# Target a specific project (or a comma list)
gcpwn --module enum_iam --workspace WORKSPACE_NAME --cred CRED_NAME --project-id my-project
# Fan out across every project already known to the workspace
gcpwn --module enum_gcp --workspace WORKSPACE_NAME --cred CRED_NAME --all-projects-
--workspace <name>— the workspace that holds the credential (matched by exact name). -
--cred <credname>— the stored credential to load into the session. -
Project scope flows through the normal selectors:
--project-id/--project-ids/--project-id-file,--current-project, or--all-projects. If you pass none, the run defaults to the credential's own project and never blocks on a prompt (drive-through mode is non-interactive). - Everything after the recognized flags is passed straight to the module, so
modules run <module> -hflags work here too.
Errors are explicit: an unknown --workspace lists the available workspaces; an unknown
or missing --cred lists the credentials stored in that workspace; and running an
authenticated module without --workspace/--cred prints the exact drive-through command
to use.
Resuming enum_all (Ctrl+C / mid-run failure): resumability is fully preserved in
drive-through mode. enum_all / enum_gcp run with --parallel-services N record
every completed (project, service) unit in a workspace-scoped SQLite ledger
(enum_all_task_ledger). The workspace itself is the checkpoint — there is no separate
token to save. If a run is interrupted (Ctrl+C) or fails partway, just re-run the exact
same command (same --workspace, --cred, and project scope): completed units are skipped
(... resuming: N services already done) and only the remaining work runs. The default
(non-parallel) path does not skip-track units, but its writes are idempotent upserts, so a
re-run re-enumerates without duplicating or losing data. For large scans, prefer
--parallel-services N for true skip-done resume.
Note: Drive-through is designed for non-prompting modules (enumeration,
enum_all, policy bindings, OpenGraph). Modules that require interactive selection or confirmation (mostexploit_*modules) will skip the prompt rather than hang — auto-selecting when there is a single obvious choice, otherwise reporting that the step needs the interactive REPL. Run those from a normal session.
BOTH user and service account access tokens can exist, but the token string by itself does not clearly identify the principal behind it (you can't base64 decode it like a JWT; its "opaque").
The --tokeninfo flag and creds tokeninfo command call Google’s /tokeninfo endpoint to return token metadata (for example, email and scopes) given an access token. This helps enrich your session data, details who the token belongs to if you don't have that context, and maps the current credential to the correct IAM identity during enumeration.
Tokeninfo Endpoint
https://oauth2.googleapis.com/tokeninfo?access_token=<ACCESS_TOKEN>
GCPwn examples
# When adding creds
oauth2 redteam-token --token ya29.a0AfH6SM... --tokeninfo# While in workspace
creds tokeninfo redteam-tokenReferences
- https://docs.cloud.google.com/docs/authentication/token-types#user-access-tokens
- https://docs.cloud.google.com/docs/authentication/token-types#sa-access-tokens
Application Default Credentials (ADC) is not a single credential. It is Google’s credential discovery mechanism used by SDK-backed tooling to automatically locate usable auth material.
In GCPwn, this maps to google.auth.default() behavior. The library resolves the active credential source for you (local user ADC, service account material, workload identity config, or metadata-attached identity).
Common ADC lookup order in operator workflows as follows, so unset GOOGLE_APPLICATION_CREDENTIALS if that is potentially causing you issues as we focus on 2 for now:
-
GOOGLE_APPLICATION_CREDENTIALSenvironment variable - Local ADC file from
gcloud auth application-default login
If you are operating interactively, "ADC" usually maps to user-backed OAuth credentials (aka. username/password login) which is what we will consider here.
# Browser-based user auth + local ADC file
gcloud auth application-default login
# Recommended to avoid project-context confusion
gcloud config set project <project_ID>
# After starting gcpwn choose ADC as your option with your crednmae. Default ADC file location is usually ~/.config/gcloud/application_default_credentials.json but you can specify path to another file if needed
gcpwn> adc <credname> [--filepath-to-adc ~/.config/gcloud/application_default_credentials.json]| Field | Required | Source |
|---|---|---|
credential_name |
Yes | Operator-defined alias |
--filepath-to-adc |
No | ADC JSON file path |
--tokeninfo |
No | Query Google tokeninfo metadata endpoint |
-
gcloud auth login: authenticates thegcloudCLI user context. i.e. you can make furthergcloudcommands at command line as that user. -
gcloud auth application-default login: creates ADC material for SDK/client-library usage. i.e. you can make further SDK calls as the user you authenticated as
For GCPwn, application-default login is the key requirement because GCPwn relies on SDK-backed authentication resolution.
> gcloud auth application-default login
Your browser has been opened to visit:
https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=76408[REDACTED]Sign in through the browser flow:

After redirecting back to localhost, Google writes your ADC credential file under .config/gcloud:
Credentials saved to file: [/home/user/.config/gcloud/application_default_credentials.json]
These credentials will be used by any library that requests Application Default Credentials (ADC).Inspect the file. Note there is a client_id, client_secret, and refresh_token. These can be ingested as we will see by a python SDK/code for GCP to auto gen a token and make subsequent API calls.
# cat /home/user/.config/gcloud/application_default_credentials.json
{
"account": "",
"client_id": "764086[REDACTED].apps.googleusercontent.com",
"client_secret": "d-FL[REDACTED]",
"refresh_token": "1//01i[REDACTED]",
"type": "authorized_user",
"universe_domain": "googleapis.com"
}
The ADC file itself does not set your intended project target. Set project context explicitly to avoid issues with gcpwn:
# Set the project to avoid issues down the road
gcloud config set project <PROJECT_ID>
In the ADC file we saw a client_id, client_secret, refresh_token but no access token to send directly to a GCP API. You will typically see a refresh token, not a long-lived pre-generated access token.
At runtime, GCPwn loads the ADC material, uses the material to request and store an access token, uses that access token for subsequent calls, and reuses stored refresh material (ex. refresh_token) for future auto-refresh attempts when the token is invalid.
After startup, load ADC. Note this was successful and gcpwn in the background requested and stored an access token as we will see in the next step.
What you will notice is the final access token (ya29...) is opaque, or you can't decode it locally. Same with gpwn. If you want to decode the opaque access token to better enrich your data then run creds tokeninfo to inspect token metadata (email/scopes) from Google’s tokeninfo endpoint:
Welcome to your workspace! Type 'help' or '?' to see available commands.
[-] No creds found
Submit the name or index of an existing credential from above, or add NEW credentials via:
[1] adc <credential_name> [--filepath-to-adc <adc_json_path>] [--tokeninfo]
[2] oauth2 <credential_name> --token <access_token> [--tokeninfo]
[3] service-acc-key <credential_name> --service-file <service_account_json_path>
Tip: `--tokeninfo` queries Google's tokeninfo endpoint to capture scope/email for OAuth-style creds.
Input: adc starting_user_token
[*] Project ID of credentials is: <PROJECT_ID>
[*] Credentials successfully added
[*] Loading in ADC credentials...
[*] Attempting to refresh the credentials using the stored refresh token. Note this is normal for brand new OAuth2 credentials added/updated.
[*] Credentials successfully refreshed...
[*] Credentials successfully stored/updated...
[*] Proceeding with up-to-date ADC credentials for starting_user_token...
[*] Loaded credentials starting_user_token
(<PROJECT_ID>:starting_user_token)> creds tokeninfo
[*] Checking credentials against https://oauth2.googleapis.com/tokeninfo endpoint...
[*] Succeeded in querying tokeninfo. The response is shown below:
{
"azp": "764086[TRUNCATED]",
"aud": "764086[TRUNCATED]",
"sub": "1057[TRUNCATED]",
"scope": "email https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/sqlservice.login https://www.googleapis.com/auth/userinfo.email openid",
"exp": "1778303317",
"expires_in": "3512",
"email": "[REDACTED_EMAIL]",
"email_verified": "true",
"access_type": "offline"
}
If you want to see the actual access token generated, you can inspect the unified databases/gcpwn.db (the session table) to confirm that GCPwn stored session credential material, including refreshed access-token state:
# sqlite3 databases/gcpwn.db
SQLite version 3.46.1 2024-08-13 09:16:08
Enter ".help" for usage hints.
sqlite> SELECT workspace_id, credname, credtype, email, default_project FROM session;
1|starting_user_token|adc|[REDACTED_EMAIL]|<PROJECT_ID>
Session credential payload (formatted):
{
"token": "ya29.a0AQvPyI[REDACTED]",
"refresh_token": "1//01in[REDACTED]",
"token_uri": "https://oauth2.googleapis.com/token",
"client_id": "76408[TRUNCATED]",
"client_secret": "d-FL[REDACTED]",
"universe_domain": "googleapis.com",
"account": "",
"expiry": "2026-05-09T05:08:36.410200Z"
}If needed, you can manually:
- exchange refresh token material for an access token
- send that access token to
/tokeninfo - Use that access token as a token input credential in gcpwn covered in the next section
Generate Access Token
# curl request
CLIENT_ID="<CLIENT_ID>"
CLIENT_SECRET="<CLIENT_SECRET>"
REFRESH_TOKEN="<REFRESH_TOKEN>"
curl -sS -X POST "https://oauth2.googleapis.com/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "client_id=${CLIENT_ID}" \
--data-urlencode "client_secret=${CLIENT_SECRET}" \
--data-urlencode "refresh_token=${REFRESH_TOKEN}" \
--data-urlencode "grant_type=refresh_token"
# curl example
CLIENT_ID="764[TRUNCATED]"
CLIENT_SECRET="d-FL[REDACTED]"
REFRESH_TOKEN="1//01i[REDACTED]"
curl -sS -X POST "https://oauth2.googleapis.com/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "client_id=${CLIENT_ID}" \
--data-urlencode "client_secret=${CLIENT_SECRET}" \
--data-urlencode "refresh_token=${REFRESH_TOKEN}" \
--data-urlencode "grant_type=refresh_token"
{
"access_token": "ya29.a0AQvPyIOFt[REDACTED]",
"expires_in": 3599,
"scope": "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/sqlservice.login openid https://www.googleapis.com/auth/cloud-platform",
"token_type": "Bearer",
"id_token": "eyJhbGciOiJSUz[REDACTE]"
} Send Token to /tokeninfo
# curl request
>curl "https://oauth2.googleapis.com/tokeninfo?access_token=<token>"
#example
> curl "https://oauth2.googleapis.com/tokeninfo?access_token=ya29.a0AQvPy[REDACTED]"
{
"azp": "7640[TRUNCATED].com",
"aud": "7640[TRUNCATED].com",
"sub": "1057[TRUNCATED]",
"scope": "email https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/sqlservice.login https://www.googleapis.com/auth/userinfo.email openid",
"exp": "1778303317",
"expires_in": "3188",
"email": "[REDACTED_EMAIL]",
"email_verified": "true",
"access_type": "offline"
}Like I showed before, gcpwn ALSO stores the refresh material from ADC. So if your access token expires and the tool doesn't auto-refresh it, or you want to refresh your token sooner, you can do that as shown below assuming your adc creds have not changed
(<PROJECT_ID>:starting_user_token)> creds update starting_user_token --type adc --assume
[*] Project ID of credentials is: <PROJECT_ID>
[*] Credentials successfully added
[*] Loading in ADC credentials...
[*] Attempting to refresh the credentials using the stored refresh token. Note this is normal for brand new OAuth2 credentials added/updated.
[*] Credentials successfully refreshed...
[*] Credentials successfully stored/updated...
[*] Proceeding with up-to-date ADC credentials for starting_user_token...
[*] Loaded credentials starting_user_token
OAuth2 tokens can come from multiple sources in GCP for both users and service accounts. They typically look like ya29.... These might be from a local user:<email> on the system or a serviceAccount:<email> attached to something like a compute instance for example (classic SSRF).
If you recover a standalone OAuth2 token, you can load it directly into GCPwn and begin making API calls immediately.
Important caveat: a standalone access token is short-lived and cannot be auto-refreshed by itself unless you also have refresh material. Review the instructions to refresh the <credname> at the end of this section
# Obtain a valid OAuth2 access token (ex. `ya29...`)
# Pass the token into GCPwn
oauth2 redteam-token --token ya29.a0AfH6SM...| Field | Required | Source |
|---|---|---|
credential_name |
Yes | Operator-defined alias |
--token |
Yes | OAuth2 bearer token |
--tokeninfo |
No | Query Google tokeninfo metadata endpoint |
There are a lot of paths that can lead to an OAuth token being recovered. Two common operator paths are:
- user token via
gcloud auth login(or recovered local gcloud token cache) - service-account token via instance metadata (IMDS)
Run login and complete browser auth:
# gcloud auth login
Your browser has been opened to visit:
https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=3255[REDACTED]
You are now logged in as [REDACTED_EMAIL].
Your current project is [<PROJECT_ID>]. You can change this setting by running:
$ gcloud config set project PROJECT_IDgcloud auth login commonly creates/updates token stores under ~/.config/gcloud, including:
-
access_tokens.db(short-lived access tokens) -
credentials.db(credential profile material that may include refresh-backed fields)
$ ls -lart /home/user/.config/gcloud/
total 72
[TRUNCATED]
-rw------- 1 user user 5 May 9 01:03 gce
-rw-r--r-- 1 user user 12288 May 9 01:03 default_configs.db
-rw------- 1 user user 12288 May 9 01:03 access_tokens.db
-rw------- 1 user user 12288 May 9 01:03 credentials.db
drwxrwxr-x 3 user user 4096 May 9 01:03 legacy_credentials
$ sqlite3 /home/user/.config/gcloud/access_tokens.db
SQLite version 3.46.1 2024-08-13 09:16:08
Enter ".help" for usage hints.
sqlite> PRAGMA table_info(access_tokens);
0|account_id|TEXT|0||1
1|access_token|TEXT|0||0
2|token_expiry|TIMESTAMP|0||0
3|rapt_token|TEXT|0||0
4|id_token|TEXT|0||0
sqlite> SELECT * FROM access_tokens;
[REDACTED_EMAIL]|ya29.a0[TRUNCATED]|2026-05-09 06:03:55.997030||eyJhbG[TRUNCATED]
credentials.db can also contain refresh/token profile material:
$ sqlite3 /home/user/.config/gcloud/credentials.db
SQLite version 3.46.1 2024-08-13 09:16:08
Enter ".help" for usage hints.
sqlite> .tables
credentials
sqlite> SELECT * FROM credentials;
[REDACTED_EMAIL]|{
"client_id": "32555940559.apps.googleusercontent.com",
"client_secret": "Zms[REDACTED]",
"refresh_token": "1//01p9Q[REDACTED]",
"revoke_uri": "https://oauth2.googleapis.com/revoke",
"scopes": [
"openid",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/appengine.admin",
"https://www.googleapis.com/auth/sqlservice.login",
"https://www.googleapis.com/auth/compute",
"https://www.googleapis.com/auth/accounts.reauth"
],
"token_uri": "https://oauth2.googleapis.com/token",
"type": "authorized_user",
"universe_domain": "googleapis.com"
}
On a compute instance with an attached service account, IMDS can return a service-account OAuth2 token:
user@gcp-instance:~$ curl -H "Metadata-Flavor: Google" \
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/111122223333-compute@developer.gserviceaccount.com/token
{"access_token":"ya29.c.c0AZ[REDACTED]","expires_in":3599,"token_type":"Bearer"}
Whichever route you followed plug the OAuth2 credential into GCPwn and set project the project after loading the token:
Input: oauth2 my_compute_oauth_token --token "ya29.c.c0AZ4bNpad[REDACTED]"
[*] Project ID of credentials is: Unknown
[*] Credentials successfully added
Loading in OAuth2 token. Note it might be expired based on how long its existed...
[*] Loaded credentials my_compute_oauth_token
(Unknown:my_compute_oauth_token)> modules run enum_cloudstorage
(Unknown:my_compute_oauth_token)> projects set <PROJECT_ID>
(<PROJECT_ID>:my_compute_oauth_token)> modules run enum_cloudstorage
[*] Target project 1/1: <PROJECT_ID>
[**] Reviewing test_[TRUNCATED]
[*] GCPwn found 1 Buckets in project <PROJECT_ID>
[*] TEXT OUTPUT (<PROJECT_ID>)
Resource Type: Buckets
Columns: name | location | blobs
Rows: showing 1 of 1
[TRUNCATED]
A standalone OAuth2 token cannot be refreshed unless you also have refresh material.
When a token expires, obtain a new token for the same principal and update the existing credential name:
creds update redteam-token --type oauth2 --token ya29.NEWTOKEN... --assumeEvery auth mode above assumes you already have something — an ADC file, a harvested token, a service-account key. Two notes for the "I only have X" cases:
Have a user's token already? Load it directly — no service account or ADC needed. An
authorized_user-shaped JSON (a token.json, refresh token included) auto-renews like
ADC; a bare ya29. access token works too but expires in ~1h with no refresh:
creds add CRED_NAME --type oauth2 --token-file token.json --assume # refresh-token backed, auto-renews
creds add CRED_NAME --type oauth2 --token ya29.<...> --assume # bare access token, ~1h, no refreshThis is a general Google user credential — if the identity has IAM grants on GCP
projects the regular enum_*/exploit_* GCP modules work against it; if it's a Workspace
admin the Workspace modules work against it directly (no impersonation needed).
Only have an email + password, no token? Google has no password→token API (no
ClientLogin/ROPC-style endpoint for Google identities — a deliberate security decision),
so raw credentials cannot be exchanged for a token programmatically. The equivalent is a
one-time interactive OAuth consent in a browser; a built-in creds login browser flow is
planned but not currently shipped. For now, mint an authorized_user token
out-of-band — e.g. gcloud auth application-default login on a machine with a browser —
and load the resulting token.json with --token-file above.
For Google Workspace, the intended path is a service account with domain-wide
delegation impersonating an admin — see
Google Workspace Enumeration (customer ID, --impersonate,
per-module scopes).
Service accounts are included in IAM bindings throughout GCP environments. Users can generate long-lasting static JSON API keys for service accounts which can then be used in various tools/SDKs to make API calls as the service account.
# Obtain a service account JSON key file
# (usually via IAM -> Service Accounts -> Keys)
# Load the key into GCPwn at startup
service-acc-key app-sa --service-file /tmp/app-sa.json| Field | Required | Source |
|---|---|---|
credential_name |
Yes | Operator-defined alias |
--service-file |
Yes | Service account JSON key file path |
Service account auth requires a JSON key file. Operators usually obtain this from IAM key-management workflows (or recover it from an accessible host/workspace path).
Typical file shape:
{
"type": "service_account",
"project_id": "example-project",
"private_key_id": "[REDACTED]",
"private_key": "-----BEGIN PRIVATE KEY-----\n[REDACTED]\n-----END PRIVATE KEY-----\n",
"client_email": "sa-name@example-project.iam.gserviceaccount.com",
"client_id": "[REDACTED]",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token"
}Treat this file like a password-equivalent secret.
chmod 600 /tmp/app-sa.jsonAt startup:
service-acc-key app-sa --service-file /tmp/app-sa.json
The tool should auto-detect the project based off the project_id field in the key. However, depending on the key/project context, explicitly setting the active project might be required:
(Unknown:app-sa)> projects set <PROJECT_ID>
(<PROJECT_ID>:app-sa)> modules run enum_cloudstorage
Service account keys don't auto-refresh like the ADC example. If you recover another keyf or the same principle you can update a credname with
creds update app-sa --type service --service-file /tmp/app-sa.json --assumeThe Google Workspace enumeration modules (enum_cloud_identity, enum_admin_roles,
enum_org_units, enum_domains, enum_mobile_devices, enum_oauth_tokens, and the
once-only enum_google_workspace phase) call the Cloud Identity API
(cloudidentity.googleapis.com) and the Admin SDK Directory API
(admin.googleapis.com). These are not regular GCP project APIs, and this is the
single most common point of confusion:
GCP credentials do not grant Google Workspace access. A
cloud-platform-scoped ADC/OAuth token or a service-account key that works perfectly for GCP project APIs still returns 403/404 against Directory/Cloud Identity. Workspace is a separate tenant (an admin console atadmin.google.com) with its own identities and OAuth scopes. You need a principal that Workspace itself recognizes as an admin.
There is nothing to load differently at auth time — you still add creds with adc,
oauth2, or service-acc-key as usual. What matters is which principal the creds
resolve to, and Workspace supports two paths.
If the credential you loaded is a user who is a Workspace admin (an ADC/OAuth2
credential for e.g. admin@yourdomain.com), the Workspace modules work directly. The
required OAuth scopes (cloud-identity.groups.readonly,
admin.directory.user/group/group.member.readonly) are attached automatically at client
build time, and no impersonation/subject is used (user credentials have no with_subject,
so the subject resolution is a no-op). Just run the Workspace modules.
No gcloud installed and no key file for that admin — just their email/password? Google
has no password→token API, so mint an authorized_user token out-of-band (e.g. gcloud auth application-default login on a machine with a browser) and load it with creds add <name> --type oauth2 --token-file token.json; the result is a plain OAuth2 user credential
that works exactly the same as ADC here.
A service account cannot read Workspace on its own. It must:
- Have domain-wide delegation configured in the Workspace Admin console — its OAuth client ID authorized for the Directory/Cloud Identity scopes above. This is done outside gcpwn, once, by a Workspace super admin.
-
Impersonate an admin subject at runtime. gcpwn performs the impersonation for you
via
credentials.with_subject(admin@domain); all you supply is the admin email.
You still load the SA the normal way (service-acc-key wsp-sa --service-file ...). Then
supply the admin subject to impersonate with the --impersonate <admin@domain> flag,
which every Workspace module and the enum_google_workspace orchestrator accepts:
# Load the delegated service account, then impersonate an admin subject
(<PROJECT_ID>:wsp-sa)> modules run enum_cloud_identity --impersonate admin@yourdomain.com
(<PROJECT_ID>:wsp-sa)> modules run enum_google_workspace --impersonate admin@yourdomain.com
The admin subject can also live in a persistent config field, workspace_admin_subject,
which the modules read when --impersonate is not passed. Note, however, that this key is
not currently settable through the interactive configs set command (only
workspace_customer_id is, see below) — in practice supply the subject with
--impersonate. With no subject resolved and an SA credential, the modules run
un-delegated and most Directory/Cloud Identity admin reads are denied (403/404). All
Workspace modules degrade gracefully in that case rather than crashing.
The Cloud Identity and Directory calls are scoped to a Workspace tenant by its
Directory Customer ID (directoryCustomerId, looks like C0xxxxxxx). gcpwn resolves
it in this order:
- Explicit
--customer-id C...on the module. - The persistent
workspace_customer_idconfig (configs set workspace_customer_id C...). - Derived from the current GCP organization: Resource Manager
organizations.getreads the org'sdirectoryCustomerId. You can point at a specific org with--org-id <numeric>; otherwise gcpwn walks the cached project hierarchy to find the org.
When step 3 succeeds it auto-persists the resolved customer ID into
workspace_customer_id (via configs set), so later runs skip the organizations.get
round-trip. If no customer ID can be resolved, the user-enumeration path is skipped with a
notice.
# Explicit customer ID for this run
(<PROJECT_ID>:wsp-sa)> modules run enum_cloud_identity --customer-id C0xxxxxxx --impersonate admin@yourdomain.com
# Persist the customer ID once (settable via configs), then just impersonate
(<PROJECT_ID>:wsp-sa)> configs set workspace_customer_id C0xxxxxxx
(<PROJECT_ID>:wsp-sa)> modules run enum_google_workspace --impersonate admin@yourdomain.com
# Let gcpwn derive + auto-persist the customer ID from the GCP org
(<PROJECT_ID>:wsp-sa)> modules run enum_cloud_identity --org-id 123456789012 --impersonate admin@yourdomain.com
enum_all runs the normal GCP services plus a once-only Workspace phase; enum_gcp
is GCP-only (skips Workspace); enum_google_workspace runs just the Workspace modules.
-
creds infoprints current credential summary and discovered permission view. -
creds info --csvexports flattened permission rows for review/filtering. -
creds tokeninfoworks for OAuth-style creds and is metadata enrichment only. -
creds setupdates stored email/project metadata for a credential context.
| Error Pattern | Meaning | Remediation |
|---|---|---|
Must supply token via --token |
OAuth2 mode called without token | Re-run with --token <access_token>
|
File ... does not exist |
ADC/service file path invalid | Verify path and re-run |
ADC not setup |
No default ADC available | Run gcloud auth application-default login and gcloud config project set <PROJECT_ID> before starting gcpwn |
Can't perform tokeninfo operations with a service account token |
tokeninfo used with service-account creds |
Use tokeninfo for OAuth-style creds only |
| Credential refresh errors | Expired/invalid refresh state | Your crednetials/token are expired. Re-authenticate and run creds update if you have a new token to replace your current expired session with |
- Authentication Reference
- Workspace Instructions
- Google Workspace Enumeration
- CLI Module Reference
- Enumeration Module Reference
- Exploit Module Reference
- Downloads to Disk
- Logging & Verbosity
- Data View/Export
- IAM Enumeration and Analysis Workflow
- Troubleshooting and FAQ