ADVISORIES
Personal Access Token Disclosure in Asana Desktop Application
- 5 minutes read - 908 wordsThis post gives an insight into a sensitive data exposure vulnerability in Asana for Mac that was rated as P1 and was awarded a bounty.
This was the very first report of that kind for me. Still, I think this type of deployment and build chain issue is more common than one may think.
The issue was reported to Asana via their Bugcrowd program on June 16th and addressed within a few hours. In fact, the initial triage by Bugcrowd was lightning fast so that the leaked secret could be revoked within hours after it was reported.
Table of Contents
- Approaching Electron-based applications
- Disclosure of Secrets
- Proving Impact
- Responsible Disclosure Timeline
- Learnings for Application Developers
- Learnings for Security Researchers
Approaching Electron-based applications
Asana’s desktop application is based on Electron, a framework to build “native applications” based on websites using web technologies such as HTML, Javascript and CSS.
Electron applications are packed using the asar (Electron Archive) format. The asar
command-line utility can be used to extract files from a packed asar bundle.
Therefore, we need to install asar
first, before we can start our actual analysis:
$ npm install -g asar
Afterward, we obtain the subject of our analysis from https://desktop-downloads.asana.com/darwin_universal/prod/latest/Asana.dmg
:
$ cd /tmp
$ wget https://desktop-downloads.asana.com/darwin_universal/prod/latest/Asana.dmg
On macOS, the disk image (*.dmg file) can be mounted using the open
command. Afterward, we can copy the application itself (Asana.app
) to an arbitrary destination:
$ open Asana.dmg
$ cp -r /Volumes/Asana/Asana.app /tmp/Asana.app
Running the file
command reveals that the copied Asana.app
is actually a folder. Using the asar extract
command, we can aim to extract the actual “web application” sources from the wrapper bundle:
$ file /tmp/Asana.app
/tmp/Asana.app: directory
$ asar extract /tmp/Asana.app/Contents/Resources/app.asar /tmp/sources
The sources can then be opened in a text editor or IDE of your choice:
Disclosure of Secrets
After browsing a bit around and trying to get a first impression of the folder structure and bundled contents, I almost could not believe my eyes. Within a folder named release_notes_bot
, there was a file named .env
that immediately aroused my interest. And indeed, the contents looked a bit odd:
$ cat /tmp/sourcecode/release_notes_bot/.env
DESKTOP_RELEASE_NOTES_PERSONAL_ACCESS_TOKEN='0/a7f89e98g007e0s07da763a'
As the variable name indicates, the value appears to be a Personal Access Token (the above example uses the default one from the documentation 😉). Hardcoding or bundling secrets is definitely a bad practice. The Asana documentation advises, for good reasons:
Remember to keep your tokens secret; treat them just like passwords! They act on your behalf when interacting with the API. Don’t hardcode them into your programs. Instead, opt to use them as environment variables.
But: The token could for instance be bound to a limited service account without access to anything from interest, or be invalid anyway.
Proving Impact
Thus, to determine whether the obtained token inherits sensitive privileges, we need to consult the API documentation, again. This almost immediately nudges us to the following request:
GET /api/1.0/users/me HTTP/1.1
Host: app.asana.com
Authorization: Bearer [PERSONAL-ACCESS-TOKEN]
If we send this request with the obtained token, we receive something like this in response:
HTTP/1.1 200 OK
Content-Type: application/json; charset=UTF-8
[...]
{
"data":{
"gid":"[REDACTED]",
"email":"[john.smith]@asana.com",
"name":"[john.smith]@asana.com",
"photo":{
"image_21x21":"https://s3.amazonaws.com/profile_photos/[REDACTED].png",
[...]
},"resource_type":"user",
"workspaces":[{
"gid":"[REDACTED]",
"name":"[REDACTED]",
"resource_type":"workspace"
},{
"gid":"[REDACTED]",
"name":"Asana, Inc",
"resource_type":"workspace"
}]
}
}
Bingo! The token is valid, bound to a real user account (not just a limited service account), and has access to multiple workspaces.
One of these workspaces appears to be the internal Asana workspace for their employees. 😮
To finally prove the impact, after consulting the documentation again, I obtained the limited outputs of the request to https://app.asana.com/api/1.0/projects?limit=10&workspace=[REDACTED]
which included the names of some internal Asana projects, and then filed the report at Bugcrowd.
Responsible Disclosure Timeline
- 16th June 2022: [LH] Initial Report via Bugcrowd: https://bugcrowd.com/disclosures/caf10f76-f1fb-4dea-8434-9ed2c56a40bb/asana-desktop-application-includes-personal-access-token
- 16th June 2022: [Bugcrowd] Report passes triage and is marked as P3.
- 17th June 2022: [Asana] Asana notifies that the report is fixed, the severity is elevated to P1 and a $6,100 bounty is awarded.
Learnings for Application Developers
Make sure that development artifacts do not make their way to production builds. Build processes are often fragile chains of multiple tools - regularly evaluate if each component really acts as expected.
More generally, handle sensitive secrets like personal access tokens or API tokens with care. Limit their scope to their intended use case and regularly rotate and revoke your secrets to limit the impact of leakage.
Learnings for Security Researchers
Many bug bounty programs include native applications such as Android, iOS, or desktop apps. For Asana, there was even a promotion for their desktop application. Still, this relatively trivial to identify issue made its way to production - I have to admit that I do not know how long the build process was broken, though.
This leads me to the conclusion, that probably fewer researchers spend time looking at these native assets. Thus, do not fear native applications. Give them a shot, you do not have much to lose 🙂
Thank you for reading this post! If you have any feedback, feel free to reach out via Mastodon, Twitter or LinkedIn. 🙂
If there is any interest in more educational posts, I could go for a post explaining how to debug Electron applications using Chrome with a hands-on example. In case you are interested, ping me on Twitter or LinkedIn.
You can directly tweet about this post using this link. 🤓