Top 6 Most Notorious OAuth Attacks
This post outlines six of the most common techniques, commonly used by attackers and how they were utilized over the last few years.
Slack’s permission model lets apps read and preview any link shared anywhere in the workspace, including in private channels and conversations. This can be used to collect sensitive information and carry targeted phishing attacks.
tl;dr - Slack’s permission model lets apps read and preview any link shared anywhere in the workspace, including in private channels and conversations. This can be used to collect sensitive information and carry targeted phishing attacks.
Slack’s ecosystem of third-party apps and integrations is said to include more than 2,400+ in its directory, with possibly tens of thousands of others that haven’t made it to the Slack marketplace. Apps permissions are managed through OAuth scopes, much like other app ecosystems (e.g. Google Workspace, Microsoft 365, etc). Just like any access claim, it may be challenging to restrict a third-party application’s access to resources it is entitled to – especially if these resources are external. This post is about one example: what could it mean for a Slack app to have access to URLs the app provider isn’t necessarily entitled to?
Before we dive in, let’s recap how Slack models app permissions. In general, an installed application can have two types of permissions:
It is worth noting that as a user in a Slack workspace, I should be able to grant an app access to my conversations, but neither I nor the apps I installed should be able to access private conversations of other users. This principle holds true both for bot and user-based apps. Even for workspace owners, accessing users’ private conversations is limited to a special permission available only for enterprise organizations.
So imagine my surprise when, last week, I sent a link to a Jira ticket to a colleague and got a reply from Jira bot. This link was sent in a private channel, and I don’t recall ever adding Jira bot to this channel. Checking the members list of the channel confirmed that indeed, Jira bot wasn’t a member. This contradicted everything I knew about Slack’s permissions model, so I investigated.
I opened the Jira app in Slack’s apps directory and noticed it has a permission called links:read. According to Slack’s documentation, in order to enhance functionality, applications can subscribe to links that refer to their domain. However, unlike other permissions, links:read allows the application to be notified whenever a link is shared anywhere in the workspace - including public channels, private channels, one-to-one messages, and even messages users send to themselves.
It turns out that one of the developers installed Jira bot in our Slack workspace, and Jira bot happens to subscribe to the domain `atlassian.net`. Every time someone sends a link to that domain, Slack sends an event to Jira bot. It makes sense: both Bot and Domain are owned by the same entity. But does Slack verify domain ownership?
Sadly, no. According to Slack’s own documentation, as an app developer you should own the domains your app subscribes to; If you don’t own them, at least respect the terms and conditions, and be “courteous, kind and helpful”.
Seriously?
By default, any user in the workspace can install apps, and any app with the permission links:read can subscribe to up to five domains, including all their subdomains and paths. Whenever a user sends a link to the domain an app is subscribed to, Slack will send an HTTP request to the application’s designated endpoint with the following information:
In fact, what we have here is a bit of a security leak. A non-privileged user can create and install an app, essentially getting access to any link shared across the entire Slack workspace. The affected users don’t even have a way of knowing that their links are read. This capability can be abused by an insider, a malicious app or inadvertently by an app/developer with over-provisioned access to sensitive URLs (=data leak). How big of an issue can that be? So, any system that relies on ‘unguessable’ URLs for access or passes sensitive information in the URL itself (bad practice regardless) is now at risk. Let's consider a few examples off the top of my head:
However, collecting sensitive information from links is only half the problem. In addition to links:read, applications can ask for its evil twin, links:write. This one’s powerful. It lets the app replace the link preview with an app owner's chosen content. Following the Jira example, the app uses this capability to add a greeting text, primary button, and three secondary buttons.
This one opens the door to a whole plethora of additional threats. One attack scenario might look like this:
Of course, there are many other possible scenarios for stealing credentials for Google/LinkedIn/Salesforce, installation of malware, chrome extensions etc.
To demonstrate this issue, I’ve created a Slack app that monitors links to Docusign and adds a button that sends users to the beloved clip of “Never gonna give you up” by Rick Astley. You can find the code on GitHub.
I contacted Slack for responsible disclosure, and they wrote that “the behavior described is intended”. Why Slack intended to let one user read and modify links sent in a private message to another user is beyond my understanding. Here are a few recommendations I would suggest to make things better:
As for that last point, see if you can find the list of subscribed domains in Jira’s app consent page. Even with the drop-downs open I bet it took you at least a few seconds (and whoever opens them anyway?)
I would recommend taking the following steps: