-
-
Notifications
You must be signed in to change notification settings - Fork 239
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
VULN: Auth Bypass in jwt_required
Decorator
#565
Comments
This is not a vulnerability, it's simply how decorators work. A decorator is a function that takes another function as an argument, and returns a new function based on whatever the decorator is doing and the original function passed in as an argument. For example, lets say you had a route that looked like this: @app.route("/foo", methods=["GET"])
@jwt_required()
def foo():
return jsonify(foo="bar"), 200 If we remove the decorator syntactic sugar and write this same code without decorators, it would look like this: def foo():
return jsonify(foo="bar"), 200
protected_foo = jwt_required()(foo)
app.route("/foo", methods=["GET"])(protected_foo) As you can see, in this case we are passing a function that has been protected via So what happens when we reverse the order of the decorators? @jwt_required()
@app.route("/foo", methods=["GET"])
def foo():
return jsonify(foo="bar"), 200 Desugaring it, it would look like this: def foo():
return jsonify(foo="bar"), 200
routed_foo = app.route("/foo", methods=["GET"])(foo)
jwt_required()(routed_foo) When written out this way, it should be clear what is happening. You are binding the unprotected function to the route, so whenever a request comes in that matches that route, it will use the function that was not protected. Then you created a protected function, but this protected function is never being called anywhere, because it was not bound to the route. As a side note, if you did have the orders of the decorators reversed, and tried to call any of the flask-jwt-extended helpers inside your view function, you would run into an error. For example, if you tried to hit this endpoint: @jwt_required()
@app.route("/protected", methods=["GET"])
def protected():
return jsonify(logged_in_as=get_jwt_identity()), 200 You would get the following error:
tl;dr - there is nothing wrong here. Just make sure you understand how decorators work and use them correctly in your application. |
I'm using
jwt_required()
to ensure my API endpoints are protected. Here is my common usage patternThe above works as intended, but if the decorators are in another order the JWT token isn't validated whatsoever.
In the above, a user can still call this endpoint with an invalid JWT or no JWT at all. This presents a major authentication bypass security issue that is bound to affect many users. I wish to responsibly disclose but I couldn't find where else to report this.
The text was updated successfully, but these errors were encountered: