triaged accepted triaged accepted fixed
reward decided
$5,000
reward decided
$5,000
Hi!
I found multiple vulnerabilities in Bulk Actions from Google Ads. After some trial and errors, I believe the vulnerability happens to trigger in the PREVIEW function of Bulk Actions.
I decided to report this in Markdown format so it will be easier to understand the report. There are a few endpoints that are vulnerable to IDOR however can only be impactful if chained together to cause more damage.
In Google Ads Bulk Actions, there are 4 columns in the left which are All bulk actions
, Rules
, Scripts
and Uploads
The vulnerability that I identified existed in Scripts
section. I did not find anything juicy in All bulk actions
and Rules
(maybe I missed something but let's hope otherwise).
There are two endpoints in PREVIEW function of Scripts
that matters to us. Before that, we need to understand 3 identifiers which is sent in the JSON payload with it.
Ps. I don't work in Google so I might be wrong
dashboard id
Fictional, it is made up of 10 numeric characters which represents individual dashboard of a user. It is the first numeric string you will encounter when you decode the value of __ar
. This might be public but I'm unsure which endpoint leaks it. Eg. 385089529
script id
Fictional, it is made up of 8 numeric characters which represents the individual script in a dashboard. It is the second numeric string you will encounter in /aw_bulk/_/rpc/ScriptService/Preview
when you decode the value of __ar
. This value will be bruteforced by the attacker to gain the value of execution_id
. Eg. 3931988
execution_id
Non-fictional, this parameter name is reflected in /aw_bulk/_/rpc/ExecutionProgressService/GetIncrementalProgress
. It is made up of 20 numeric characters which indicates it's not a good idea to bruteforce it. Once this value is combined with dashboard id
, it will return information of a script through /aw_bulk/_/rpc/ExecutionProgressService/GetIncrementalProgress
. Eg. 1725875959726807315
/aw_bulk/_/rpc/ScriptService/Preview
The above endpoint will need a valid dashboard id
and script id
to return a valid execution_id
. In the first request it will return an OAuth URL. By navigating to it, it will prompt user to grant access to the script which discloses the script name. After granting access, resend the request and it will return the value of execution_id
which can be used in the next endpoint.
/aw_bulk/_/rpc/ExecutionProgressService/GetIncrementalProgress
This endpoint will need a valid combination of dashboard id
and execution_id
to return the output details of the script.
This endpoint is identical to /aw_bulk/_/rpc/ExecutionProgressService/GetIncrementalProgress
above however it doesn't return useful information nor it can be chained with others.
/aw_bulk/_/rpc/BulkExecutionStatusService/GetStatus
I'm leaving it here if the security team wants to investigate further or patch it along.
Create a profile in Google Ads and navigate to Bulk Actions
Observe exists 3 columns which are Rules
, Scripts
and Uploads
Click Scripts
and create a new script with the following code and name it
function main() {
Logger.log("Hello Google VRP!")
}
Prepare to intercept a POST request to /aw_bulk/_/rpc/ScriptService/Preview
Click Preview
in the bottom right corner
Obtain the value of dashboard id
and script id
Login into another account and perform the same thing.
Retrieve the execution_id
and use it in /aw_bulk/_/rpc/ExecutionProgressService/GetIncrementalProgress
to get the script output information
Optional: Use an account to intercept a POST request to /aw_bulk/_/rpc/ScriptService/Preview
and substitude both values to 385089529
and 3931988
. Both of them are valid values of dashboard id
and script id
from my test account.
A regular user finds a way to obtain a valid dashboard id
(maybe through account sharing) and bruteforce a valid script id
to retrieve a valid execution_id
which will reveal their previous script output details.