Skip Navigation
Get a Demo
 
 
 
 
 
 
 
 
 
Resources Blog Threat detection

Breaking down a supply chain attack leveraging a malicious Google Workspace OAuth app

Breaking down a supply chain attack leveraging a malicious Google Workspace OAuth app

How to detect and respond to OAuth consent attacks in Google Workspace

Tre Wilkins

In late 2024, a significant supply chain attack targeted Chrome extension developers, ultimately affecting more than 2.6 million users. The campaign began with developers receiving a deceptive email containing a link. This link redirected them to a legitimate Google login page, which then fraudulently requested authorization for a malicious Google OAuth application named “Privacy Policy Extension.” Crucially, this application sought the https://www.googleapis.com/auth/chromewebstore scope.

Once a developer or user granted permissions to this adversary-controlled app, the threat actor immediately gained the ability to modify and publish a malicious version of the developers Chrome extensions to the Google Chrome Web Store. The compromised extension, upon installation, was designed to collect and exfiltrate session cookies and authentication tokens, specifically targeting Facebook Ads accounts.

Using Red Canary’s minimal viable story framework for analyzing detection data, this blog will detail how to detect and remediate this type of attack within Google Workspace. We’ll also share detection and remediation opportunities modeled after this supply chain attack.

What happened?

In this scenario, the following event occurred:

At 2025-10-29T01:08:13.274Z, within Google Workspace account C01wnsypx, developer@example.com (ID: 123456789012345678901) authorized an application, Privacy Policy Extension (Client ID: 123456789012-abc123.apps.googleusercontent.com) and consented to the following Chrome Web Store API OAuth permission: https://www.googleapis.com/auth/chromewebstore. This action was performed from the following IP address: 136.226.68.203.

Summarized at a higher level, this means that the Privacy Policy Extension app has access to see, edit, update, or publish any Chrome Web Store extensions, themes, apps, and licenses that developer@example.com has access to. The following questions may arise in the course of an investigation:

  1. Did the legitimate user behind the developer@example.com identity actually mean to use this application? Was the user somehow coerced into this consent?
  2. Is it authorized for this app to interact with the user’s extensions, themes, apps, and licenses?
  3. Is this app actually sanctioned within this organization?

In order to answer these questions, we need data, specifically, the events.name: authorize activity from the Admin Report OAuth Token Audit Activity.

Here is the mocked data that was used to model this incident:

{
   "kind": "admin#reports#activity",
   "id": {
       "time": "2025-10-29T01:08:13.274Z",
       "applicationName": "token",
       "customerId": "C01wnsypx"
   },
   "actor": {
       "email": "developer@example.com",
       "profileId": "123456789012345678901"
   },
   "ipAddress": "136.226.68.203",
   "networkInfo": {
       "ipAsn": [
           22616
       ],
       "regionCode": "US",
       "subdivisionCode": "US-VA"
   },
   "events": [
       {
           "type": "auth",
           "name": "authorize",
           "parameters": [
               {
                   "name": "client_id",
                   "value": "123456789012-abc123.apps.googleusercontent.com"
               },
               {
                   "name": "app_name",
                   "value": "Privacy Policy Extension"
               },
               {
                   "name": "client_type",
                   "value": "WEB"
               },
               {
                   "name": "scope_data",
                   "multiMessageValue": [
                       {
                           "parameter": [
                               {
                                   "name": "scope_name",
                                   "value": "https://www.googleapis.com/auth/chromewebstore"
                               },
                               {
                                   "name": "product_bucket",
                                   "multiValue": [
                                       "OTHER"
                                   ]
                               }
                           ]
                       }
                   ]
               },
               {
                   "name": "scope",
                   "multiValue": [
                       "https://www.googleapis.com/auth/chromewebstore"
                   ]
               }
           ]
       }
   ]
}

Who

This corresponds to the actor that performed the action.

developer@example.com (ID: 123456789012345678901)”

Field derivation

OperationFieldValueDescription
authorizeactor.emaildeveloper@example.comThe human-readable name for the identity.
authorizeactor.profileId123456789012345678901The user’s unique Google Workspace profile ID.

What

This corresponds to the resource that was affected and the specifics of the action that was performed on it.

“authorized an application, Privacy Policy Extension (Client ID: 123456789012-abc123.apps.googleusercontent.com) and consented to the following Chrome Web Store API OAuth permission: https://www.googleapis.com/auth/chromewebstore

Field derivation

OperationFieldValueDescription
authorizeevents.name“authorized”The action performed by the actor.
authorizeevents[0]['parameters']['app_name'].valuePrivacy Policy ExtensionThe name of the app.
authorizeevents[0]['parameters']['client_id'].value123456789012-abc123.apps.googleusercontent.comThe globally unique identifier of the application.
authorizeevents[0]['parameters']['scope'].multiValue["https://www.googleapis.com/auth/chromewebstore"]This array indicates the specific OAuth scopes that were consented to.

When

This corresponds to the time in which the action occurred.

“At 2025-10-29T01:08:13.274Z”

Field derivation

OperationFieldValueDescription
authorizeid.time2025-10-29T01:08:13.274ZThe date and time that this event occurred.

Where

This corresponds to the environment in which the action occurred.

“within Google Workspace account C01wnsypx

Field derivation

OperationFieldValueDescription
authorizeid.customerIdC01wnsypxThe account in which the action took place.

Whence

From where did the action originate?

“This action was performed from the following IP address: 136.226.68.203.”

Field derivation

OperationFieldValueDescription
authorizeipAddress136.226.68.203The IP address from which the actor performed the action.

Detection

If you are concerned about users being phished and consenting to unsanctioned applications that have requested rare or high-risk scopes, your detection strategy must be aligned with clearly defined objectives.

Detection objectives

  • Do you aim to detect all applications with high-risk scopes, or only a subset?
  • What is your tolerance for high detection volume and false positives?
  • Can you assess the prevalence of existing applications in your environment?

 

The combination of your scope and objectives will dictate the most effective detection strategy.

As a foundational step to minimize detection volume, we recommend first identifying the existing applications in your environment. You can leverage the following GAM command to create this initial list:

gam all users print tokens todrive

1. Detect an initial authorization of a high-risk application, defined as an app never before seen in the organization that requests high-risk scopes.

This strategy focuses on two key criteria:

  1. New application: The application doesn’t already exist in the organization, as an existing app is more likely to be sanctioned.
  2. High-risk scopes: The application requests scopes that Google defines as high-risk, such as those related to sending mail or deleting files in Drive. As of this writing, Google allows you to restrict access to high-risk scopes for Gmail, Google Drive, and Google Chat, including the following:
    • https://mail.google.com/,https://www.googleapis.com/auth/gmail.compose, https://www.googleapis.com/auth/gmail.insert, https://www.googleapis.com/auth/gmail.metadata, https://www.googleapis.com/auth/gmail.modify, https://www.googleapis.com/auth/gmail.readonly, https://www.googleapis.com/auth/gmail.send, https://www.googleapis.com/auth/gmail.settings.basic, https://www.googleapis.com/auth/gmail.settings.sharing, https://www.googleapis.com/auth/documents, https://www.googleapis.com/auth/documents.readonly, https://www.googleapis.com/auth/drive, https://www.googleapis.com/auth/drive.activity, https://www.googleapis.com/auth/drive.activity.readonly, https://www.googleapis.com/auth/drive.admin, https://www.googleapis.com/auth/drive.admin.labels, https://www.googleapis.com/auth/drive.admin.labels.readonly, https://www.googleapis.com/auth/drive.admin.readonly, https://www.googleapis.com/auth/drive.admin.shareddrive, https://www.googleapis.com/auth/drive.admin.shareddrive.readonly, https://www.googleapis.com/auth/drive.apps, https://www.googleapis.com/auth/drive.apps.readonly, https://www.googleapis.com/auth/drive.categories.readonly, https://www.googleapis.com/auth/drive.labels.readonly, https://www.googleapis.com/auth/drive.meet.readonly, https://www.googleapis.com/auth/drive.metadata, https://www.googleapis.com/auth/drive.metadata.readonly, https://www.googleapis.com/auth/drive.photos.readonly, https://www.googleapis.com/auth/drive.readonly, https://www.googleapis.com/auth/drive.scripts, https://www.googleapis.com/auth/drive.teams, https://www.googleapis.com/auth/forms.body, https://www.googleapis.com/auth/forms.body.readonly, https://www.googleapis.com/auth/forms.currentonly, https://www.googleapis.com/auth/forms.responses.readonly, https://www.googleapis.com/auth/presentations, https://www.googleapis.com/auth/presentations.readonly, https://www.googleapis.com/auth/script.addons.curation, https://www.googleapis.com/auth/script.projects, https://www.googleapis.com/auth/sites, https://www.googleapis.com/auth/sites.readonly, https://www.googleapis.com/auth/spreadsheets, https://www.googleapis.com/auth/spreadsheets.readonly, https://www.googleapis.com/auth/chat.delete, https://www.googleapis.com/auth/chat.import, https://www.googleapis.com/auth/chat.messages, https://www.googleapis.com/auth/chat.messages.readonly

 

This detection strategy can be implemented with the following pseudo-logic:

OperationFieldConditionValueDescription
authorizeevents[0]['parameters']['client_id'].valueNot inA list of approved client IDsThe application’s Client ID is not in a pre-approved list.
authorizeevents[0]['parameters']['client_id'].valueNot inA list of client IDs observed in the last X amount of days (e.g., 90 days).The application’s Client ID has not been seen in the environment in the last X amount of days (e.g., 90 days).
authorizeevents[0]['parameters']['scope'].multiValueContains one or more of the followingSee the list of risky scopes above, e.g., https://www.googleapis.com/auth/gmail.readonlyOne or more of the known high-risk scopes.

 

2. Detect an initial authorization of a potentially malicious application, defined as an app never before seen in the organization that requests rare or unapproved scopes.

This strategy focuses on two key criteria:

  1. New application: The application has never been authorized by any user in the organization before.
  2. Suspicious scopes: The application is requesting permissions (scopes) that are rarely requested by other applications or are considered high-risk/unapproved by the organization’s policy.

This detection strategy can be implemented with the following pseudo-logic:

OperationFieldConditionValueDescription
authorizeevents[0]['parameters']['client_id'].valueNot inA list of approved client IDsThe application’s Client ID is not in a pre-approved list.
authorizeevents[0]['parameters']['client_id'].valueNot inA list of client IDs observed in the last X amount of days (e.g., 90 days).The application’s Client ID has not been seen in the environment in the last X amount of days.
authorizeevents[0]['parameters']['scopes']Not inA list of common or approved scopesThe scopes requested by the application are not in a list of common or approved scopes.

Remediation

If it has been determined that an OAuth consent grant was malicious, the following immediate actions can be performed:

1. Revoke tokens for the flagged client ID.

Using the client ID value found in events[0]['parameters']['client_id'].value field, the following GAM command can be executed:

gam all users delete tokens clientId 1234567890-abc123.apps.googleusercontent.com

2. Block the flagged client ID.

Using the client ID value found in events[0][‘parameters’][‘client_id’].value field, an administrator can revoke an application’s access to any Google data.

Mitigations

Fortunately, Google offers several opportunities to mitigate this technique. As discussed, this attack relies on a victim having permission to consent to an application without prior administrative approval.

As Google states, by default, users can sign in with Google to any third-party app, and accessed apps can request unrestricted Google data for that user.

To prevent users from introducing unvetted applications and over-provisioning OAuth permissions, Google provides two primary mitigation options:

  1. Restrict all third-party app access (safest, highest administrative burden): This option involves not allowing users to access any third-party apps by default, but still allowing them to request access to unconfigured apps. This requires an administrator with the Security settings administrator privilege to configure the app’s access settings (e.g., Trusted, Limited, Specific Google data, or Blocked).
  2. Allow limited access (balances security and usability): This option grants users the ability to consent to apps that request only basic information necessary for “Sign in with Google,” such as a user’s name, email, and profile picture. This eases the administrative burden while maintaining a stronger security posture than the default.

Threat hunting

Proactive hunting methods include querying for external apps that have been consented to by fewer than a set minimum number of users, helping administrators zero in on unique and potentially dangerous installations. Threat hunting for malicious OAuth applications should then continue with a thorough audit of all authorized apps in your environment. Review each app’s name, publisher, permissions, and unique application ID.

One of the strongest indicators of a custom-built malicious app is “rare” community use meaning the app is not commonly found across other organization and may be tailored for a specific target. Malicious apps often request excessive, high-risk permissions, such as full read/write access to files or the ability to read and send mail, far beyond what’s needed for normal operation. Unlike trusted enterprise apps, suspicious applications are usually authorized by only one or a handful of users, often without elevated privileges. Analysts should regularly review activity and audit logs for behavioral anomalies, such as dormant apps suddenly using rare or risky permissions, which can signal the start of malicious actions like internal phishing or data theft.

References

 

Moving up the Assemblyline: Exposing malicious code in browser extensions

 

Hunting for malicious OpenClaw AI in the modern enterprise

 

The million-dollar front door and the tailgater: Why strong auth could fail at SaaS session integrity

 

ChatGPT in your inbox? Investigating Entra apps that request unexpected permissions

Subscribe to our blog

Security gaps? We got you.

Sign up for our monthly email newsletter for expert insights on MDR, threat intel, and security ops—straight to your inbox.


 
 
Back to Top