Skip to main content

Command Palette

Search for a command to run...

Exposing JWT vulnerability in Neo4J's GraphQL(v3) Auth Layer

How a few lines of missing documentation might have led to unauthorized access to thousands of apps using Firebase Auth and Neo4j's GraphQL library.

Published
4 min read
Exposing JWT vulnerability in Neo4J's GraphQL(v3) Auth Layer
working-of-jwt

JWT: The key to your backend treasure

JWT's are widely used for Authentication and Authorization in the modern world of software engineering. It is easy to generate on the server-side and can store user's authorization information. However, it can also expose you to a wide variety of vulnerabilities (You can read more about the common JWT vulnerabilities here) They can be caused due to misconfiguration of JWT issuance and verification or half-ass understanding of 'how-it-works under the hood' or simply due to lack of documentation and these couple of missing lines in their documentation proved to be the reason for a potential unauthorized access to thousands of apps using Neo4J's GraphQL library with 3rd party auth providers such as Firebase.

From an accident to an incident

On a weekday evening, with an aromatic cup of filter coffee, we were stage-testing our maritime cybersecurity product where a weird scenario made me fall off my chair (No coffee was harmed during this!). I was running some tests on the GraphQL queries from the Apollo GraphiQL console and that needed me to pass a JWT token in the Authorization header. Nothing fancy here, standard Bearer token auth. I asked my colleague to log into our product's dashboard and pass me the JWT token from the network tab of his browser. Juggling between millions of his chrome tabs, he gave me the JWT token; I inserted it, ran the query, got the results. All good! A minute later, he says,

"Sorry, I handed you the JWT from another project. Please take this one."

Wait, WHAT?!?

He had no freaking idea that his previously shared JWT had passed through the SSL tunnels travelling millions of hops to our backend server, where it was happily accepted, providing me with the RESULT as an authorized user.

I knew our auth was broken! I and Shata, my teammate started looking at our code.

We were using Firebase Auth for implementing Authentication and Authorization. Firebase issues JWKs (keys found here) that developers can use to verify the JWTs issued via Firebase, and these keys are common across millions of tenants. However, their JWT payloads have additional information that helps you determine your project-specific information.

The aud and iss keys are the game changers here. They are unique to every project based on the projectId of your Firebase project. However, if there are no checks in your JWT verification logic to check for the values of aud (audience) or the iss (issuer) in the payload then any JWT issued by Firebase will be valid and your server will consider it to be an authenticated request and the authorization will flow as per the payload and your declared business logic.

I did a small PoC spinning up a simple Neo4j app with global authentication enabled:

With no checks for additional JWT payload values, any Firebase project's JWT token can be used to authenticate and gain access to the mentioned GraphQL types in the schema. The Neo4j's auth plugin had no provision to mention these values during configuration or had any checks in the JWT verification process. We informed this to the Neo4j's security team to which they responded:

While this is true, the JWT RFC also mentions: RFC 7519 - JSON Web Token (JWT) (ietf.org)

A very well-known GraphQL engine, Hasura, has this clearly mentioned in their documentation:

Shata had opened a PR with the fix that was reviewed by the Neo4j team, and they acknowledged that it is necessary to have an optional provision for the user to declare these values during project configuration and issued a new PR with updates to their code and documentation:

The checks are now a part of the latest Neo4j GraphQL library updates. Even though this was optional and wasn't a direct compulsion from JWT's RFC, such small yet important information can be easily missed out while we code that can lead to major security vulnerabilities. As you read this, in this very moment, there might be thousands of apps running on the internet using the same authentication mechanism and vulnerable to this issue. Hence, it is also important to constantly update the libraries used in your projects and closely monitor the changelog.

Stay aware, stay safe, keep programming!