The vulnerability to be detected for this challenge was an access control flaw due to improper handling of case sensitivity and improper validation of path equivalence.
The challenge resolution required knowledge of the Node.js web framework Express.

Note: This article is also available in french 🇫🇷. The challenge was announced in this tweet 🐦.

Explanation

By default, the routing of the Express framework is not case-sensitive. Let’s look at what the documentation is saying:

app.set(name, value)

Application Settings

Property Type Description Default
case-sensitive routing Boolean Enable case sensitivity. When enabled, "/Foo" and "/foo" are different routes. When disabled, "/Foo" and "/foo" are treated the same. NOTE: Sub-apps will inherit the value of this setting. N/A (undefined)

express.Router([options])

Property Description Default Availability
caseSensitive Enable case sensitivity. Disabled by default, treating “/Foo” and “/foo” as the same.

Reference – 4.x API – Express documentation

Therefore, routing to /secret, /SECRET, /SeCrEt, etc. will have the same endpoint. On the other hand, the authentication middleware that is supposed to protect the /secret endpoint is case-sensitive and only checks the token when the route starts exactly with /secret. So contacting /secret, or any other form with a different case, is enough to bypass the access control, because Express will still route the request correctly even though authentication will not be performed.

Fixed code

Here is the corrected code:

Fixed code

Here, the global settings of the application have been changed so that the routes are case-sensitive.

Another solution would have been to keep the application case-insensitive and only do a case-insensitive check for the /secret route, but the same blunder could happen elsewhere in the code.

Diff

The source code is available on the Github repository Acceis/vulnerable-code-snippets.

About the author

Article written by Alexandre ZANNI aka noraj, Penetration Testing Engineer at ACCEIS.