Inserting arbitrary files into anyone’s Google Earth Studio Projects Archive

Google Earth Studio is a web-based animation tool for Google Earth’s satellite and 3D imagery. It was first released in 2018 as an invite-only beta.

Google Earth Studio
Google Earth Studio landing screen

Creating projects and folders

Google Earth Studio lets users create 3D animations which are saved in projects. Each project contains information like its name, what folder it is stored in, when it was last created/edited, and so on.

Every project is saved in a folder — either the root folder or a sub-folder the user has created. Surprisingly, folders have incremental IDs. That means the first folder ever created has ID 0, the thousandth folder has ID 999 etc.

Allowing access to resources using incremental IDs (also known as IDOR = Insecure Direct Object Reference) is a bad practice as — if proper authorization restrictions are missing — it makes it possible to enumerate through all the entries that exist in the database. One way of preventing this is to use UUIDs.

Google Earth Studio Open Project Dialog
Open project dialog with projects and folders

Saving projects

When a project is saved, a POST request is sent to with the following JSON body:

  "name": "My project",
  "data": { .... some json project data .... },
  "version": 16,
  "folder": ""

The folder parameter contains a reference to the folder ID where it’s going to be saved, name is the title of the project and data contains a JSON object with the project configuration.

In this case, 31337 is an ID of a folder we have created before in our account. If however, another user creates a new folder in their own account that will have ID let’s say 12345 — and we use this ID (12345) instead of the ID of our own folder, the project will get saved there!

That means it’s possible to save our projects into folders that we don’t own.

Although the project is saved in the folder of another user, the user won’t see that project listed there. The code that shows the projects most likely checks if the user is the owner of the project as well.

Projects Archive

There’s however a place where the project does show up in the folder — the Projects Archive.

Google Earth Studio Preferences
Google Earth Studio preferences

The Projects Archive is a zip file that contains a copy of all your projects.

The projects are stored in .esp files with their name as the filename and in corresponding folders. The content of the file is simply the data value as a serialized JSON. And this time the project we have created is included here as well.

So far we have found a way to save projects into zip archives of other users.

Google Earth Studio zip Archive
Project .zip archive

File payload

Since we know that the project’s data JSON value is reflected in the file’s content, we can try changing the JSON itself. As it turns out, we can change the value to any valid JSON. And a string is a valid JSON as well.

This means if we change the data value to <script>alert('oops')</script>, this payload is going to be reflected in the file as well.

So we have a file with a JavaScript payload saved in someone’s folder.

HTML payload source
HTML file with a payload

Changing the filename

When we open the file, the payload won’t be executed because the filename still ends with .esp. The filename is made with the project’s name and the just mentioned file extension. This gives us control of the filename — or at least the part before the extension — by changing the project’s name.

Changing the name simply to dangerous_file.html won’t work as the resulting filename will be dangerous_file.html.esp.

I tried to make the filename really long, hoping for some kind of overflow vulnerability that would make the filename end with .html. I’ve seen this one work in PHP, but unfortunately, it didn’t work this time.

Another option would be to add a null character at the end of the filename. Fortunately, adding special characters is easy in JSON. All we need to do is: dangerous_file.html\u0000.

JSON request
JSON request with modified parameters

In most low-level programming languages, a null byte represents the termination of a string, which means that what would be dangerous_file.html<NULL>.esp becomes dangerous_file.html just thanks to the fact that null is treated as the end of the string. Many frameworks/languages defend against this Null Byte Injection by simply not allowing null characters in the filename, but this was not the case at Google’s side.

Now we have a file saved in someone else’s folder, the file contains a JavaScript payload in a script tag, and the file is saved as .html.

Malicious files in a .zip archive
Malicious files in a .zip archive


Thanks to multiple combined vulnerabilities we are able to insert arbitrary files into anyone’s Google Earth Studio Projects Archive.

All we need now is that a user downloads their Projects Archive and opens the malicious file.

Google decided that this issue is not severe enough to qualify for a reward, but they fixed the vulnerability anyways.

Update from 2021

After two and half years after reporting the issue, I asked the team to reconsider this issue. I stated the following reasons.

My reasons:

  • the attacker could insert almost arbitrary (must be valid JSON) files with a completely custom filename and extension
  • the attacker could modify the archive of every project ever created on the service (due to incremental IDs), therefore affecting all users

Consider an example:

  1. the attacker inserts a valid executable file into everyone’s archive
  2. a victim downloads their archive from the Preferences page, extracts the archive, knowing it contains a copy of their projects downloaded from

The archive has a structure like this:

└── Example Project/
    ├── projectData.esp
  1. the unsuspecting victim runs the file, thinking it is a file that will “initialize” the project

The content of the file is: "$(custom code here)", which is valid JSON. In my case, for example, double-clicking the file on Windows with Git Bash installed directly runs the file. This is just one example of how the attack could be executed. I believe it’d be possible to create different executable files, however, I’m not really familiar with that and I think this is sufficient as a proof of concept.

While getting the victim to execute the file might seem similar to typical social engineering attacks, normally the attacker would send the file to the victim via a delivery channel, however in this case the victim would directly download the “archive with a copy of all your projects” from a website they trust (, without the knowledge that the archive of their projects has been infected with malware by the attacker. And the attacker could apply this to all projects/users using the service, leaving the “Download Projects Archive” option infected with malicious files for the entire service.

After providing the additional information, the VRP panel decided to issue a reward for this report.

2019-01-30Vulnerability reported
2019-01-31Priority changed to P2
2019-02-05No reward issued
2021-07-28 Added more info and asked to reconsider reward
2021-08-03Reward issued

Written by Thomas Orlita
Follow me on Twitter: @ThomasOrlita / Mastodon: