CVE-2017-7266: URL Redirection to Untrusted Site ('Open Redirect') (CWE-601)
value: Netflix Security Monkey before 0.8.0 has an Open Redirect. The logout functionality accepted the "next" parameter which then redirects to any domain irrespective of the Host header.
CWE description: A web application accepts a user-controlled input that specifies a link to an external site, and uses that link in a Redirect. This simplifies phishing attacks.
CVSS v3 base score: 6.1
Published: 2017-03-26T05:59Z
Repository: https://github.com/Netflix/security_monkey
Language: Python
Files changed: security_monkey/auth/modules.py, security_monkey/sso/views.py, security_monkey/views/__init__.py, security_monkey/views/logout.py, setup.py
Commit date: 2016-12-30 00:33:29 -0700
Commit message: Replacing Flask-Security with Flask-Security-Fork. Removing some explicit dependencies to rely on flask-security-fork dependencies. SSO will use flask-security login_user instead of flask-login so that security_trackable works. Replacing current_user.is_authenticated() method with property so  we can use a newer version of flask-login. (#482)


Diff: diff --git a/security_monkey/auth/modules.py b/security_monkey/auth/modules.py
index d84e168..ec26b7e 100644
--- a/security_monkey/auth/modules.py
+++ b/security_monkey/auth/modules.py
@@ -238,21 +238,21 @@ class RBAC(object):
 
         return False
 
     def _deny_hook(self, resource=None):
         app = self.get_app()
-        if current_user.is_authenticated():
+        if current_user.is_authenticated:
             status = 403
         else:
             status = 401
         #abort(status)
 
         if app.config.get('FRONTED_BY_NGINX'):
                 url = "https://{}:{}{}".format(app.config.get('FQDN'), app.config.get('NGINX_PORT'), '/login')
         else:
                 url = "http://{}:{}{}".format(app.config.get('FQDN'), app.config.get('API_PORT'), '/login')
-        if current_user.is_authenticated():
+        if current_user.is_authenticated:
             auth_dict = {
                 "authenticated": True,
                 "user": current_user.email,
                 "roles": current_user.role,
             }
diff --git a/security_monkey/sso/views.py b/security_monkey/sso/views.py
index 165fcdc..aef04d5 100644
--- a/security_monkey/sso/views.py
+++ b/security_monkey/sso/views.py
@@ -11,11 +11,11 @@ import requests
 
 from flask import Blueprint, current_app, redirect, request
 
 from flask.ext.restful import reqparse, Resource, Api
 from flask.ext.principal import Identity, identity_changed
-from flask_login import login_user
+from flask_security.utils import login_user
 
 try:
     from onelogin.saml2.auth import OneLogin_Saml2_Auth
     from onelogin.saml2.utils import OneLogin_Saml2_Utils
     onelogin_import_success = True
@@ -262,11 +262,11 @@ class OneLogin(Resource):
 
     def _consumer(self, auth):
         auth.process_response()
         errors = auth.get_errors()
         if not errors:
-            if auth.is_authenticated():
+            if auth.is_authenticated:
                 return True
             else:
                 return False
         else:
             current_app.logger.error('Error processing %s' % (', '.join(errors)))
diff --git a/security_monkey/views/__init__.py b/security_monkey/views/__init__.py
index 0f32280..9d4a2e8 100644
--- a/security_monkey/views/__init__.py
+++ b/security_monkey/views/__init__.py
@@ -142,11 +142,11 @@ ITEM_LINK_FIELDS = {
 class AuthenticatedService(Resource):
     def __init__(self):
         self.reqparse = reqparse.RequestParser()
         super(AuthenticatedService, self).__init__()
         self.auth_dict = dict()
-        if current_user.is_authenticated():
+        if current_user.is_authenticated:
             roles_marshal = []
             for role in current_user.roles:
                 roles_marshal.append(marshal(role.__dict__, ROLE_FIELDS))
 
             roles_marshal.append({"name": current_user.role})
diff --git a/security_monkey/views/logout.py b/security_monkey/views/logout.py
index d8bc922..dd4df63 100644
--- a/security_monkey/views/logout.py
+++ b/security_monkey/views/logout.py
@@ -23,10 +23,10 @@ from security_monkey import rbac
 class Logout(Resource):
 
     decorators = [rbac.exempt]
 
     def get(self):
-        if not current_user.is_authenticated():
+        if not current_user.is_authenticated:
             return "Must be logged in to log out", 200
 
         logout_user()
         return "Logged Out", 200
diff --git a/setup.py b/setup.py
index 08d73b3..839c8bb 100644
--- a/setup.py
+++ b/setup.py
@@ -21,29 +21,28 @@ setup(
     include_package_data=True,
     zip_safe=False,
     install_requires=[
         'APScheduler==2.1.2',
         'Flask==0.10.1',
-        'Flask-Login==0.2.10',
         'Flask-Mail==0.9.0',
         'Flask-Migrate==1.3.1',
         'Flask-Principal==0.4.0',
         'Flask-RESTful==0.3.3',
         'Flask-SQLAlchemy==1.0',
         'Flask-Script==0.6.3',
-        'Flask-Security==1.7.4',
-        'Flask-WTF==0.9.5',
+        # 'Flask-Security==1.7.4',
+        'Flask-Security-Fork==1.8.2',
         'Jinja2==2.8',
         'SQLAlchemy==0.9.2',
         'boto>=2.41.0',
         'ipaddr==2.1.11',
         'itsdangerous==0.23',
-        'psycopg2==2.5.2',
-        'bcrypt==2.0.0',
+        'psycopg2==2.6.2',
+        'bcrypt==3.1.2',
         'Sphinx==1.2.2',
         'gunicorn==18.0',
-        'cryptography==1.3.2',
+        'cryptography==1.7.1',
         'boto3>=1.4.2',
         'botocore>=1.4.81',
         'dpath==1.3.2',
         'pyyaml==3.11',
         'jira==0.32',

Vulnerable code:         if current_user.is_authenticated():
        if current_user.is_authenticated():
from flask_login import login_user
            if auth.is_authenticated():
        if current_user.is_authenticated():
        if not current_user.is_authenticated():
        'Flask-Login==0.2.10',
        'Flask-Security==1.7.4',
        'Flask-WTF==0.9.5',
        'psycopg2==2.5.2',
        'bcrypt==2.0.0',
        'cryptography==1.3.2',
Fixed code:         if current_user.is_authenticated:
        if current_user.is_authenticated:
from flask_security.utils import login_user
            if auth.is_authenticated:
        if current_user.is_authenticated:
        if not current_user.is_authenticated:
        # 'Flask-Security==1.7.4',
        'Flask-Security-Fork==1.8.2',
        'psycopg2==2.6.2',
        'bcrypt==3.1.2',
        'cryptography==1.7.1',