Skip to content

Release 0.7.0 #264

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

Merged
merged 1,834 commits into from
Mar 20, 2025
Merged

Release 0.7.0 #264

merged 1,834 commits into from
Mar 20, 2025

Conversation

florian-jaeger
Copy link
Contributor

No description provided.

meffmadd and others added 30 commits September 6, 2024 10:59
fix!: changed wording of the configuration env vars for hostname and port
… recusrive flag for glob.glob to search in sub directories"

This reverts commit 5926837.
# set new login cookie
# because single-user cookie may have been cleared or incorrect
self.set_login_cookie(user)
self.redirect(self.get_next_url(user), permanent=False)

Check warning

Code scanning / CodeQL

URL redirection from remote source Medium

Untrusted URL redirection depends on a
user-provided value
.
Untrusted URL redirection depends on a
user-provided value
.

Copilot Autofix

AI about 2 months ago

To fix the problem, we need to ensure that the next URL parameter is properly validated to prevent open redirects. We can achieve this by maintaining a list of allowed redirect URLs and checking the user-provided URL against this list. If the URL is not in the list, we should redirect to a default safe URL.

  1. Define a list of allowed redirect URLs.
  2. Modify the _validate_next_url method to check if the user-provided URL is in the list of allowed URLs.
  3. If the URL is not in the list, return a default safe URL.
Suggested changeset 1
grader_service/handlers/base_handler.py
Outside changed files

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/grader_service/handlers/base_handler.py b/grader_service/handlers/base_handler.py
--- a/grader_service/handlers/base_handler.py
+++ b/grader_service/handlers/base_handler.py
@@ -670,2 +670,9 @@
         """
+        # List of allowed redirect URLs
+        allowed_urls = [
+            self.application.base_url,
+            self.settings['login_url'],
+            self.settings.get('home_url', '/')
+        ]
+
         # protect against some browsers' buggy handling of backslash as slash
@@ -708,2 +715,7 @@
             next_url = ''
+
+        # Check if the next_url is in the list of allowed URLs
+        if next_url not in allowed_urls:
+            self.log.warning("Disallowing redirect to untrusted URL: %r", next_url)
+            next_url = ''
 
EOF
@@ -670,2 +670,9 @@
"""
# List of allowed redirect URLs
allowed_urls = [
self.application.base_url,
self.settings['login_url'],
self.settings.get('home_url', '/')
]

# protect against some browsers' buggy handling of backslash as slash
@@ -708,2 +715,7 @@
next_url = ''

# Check if the next_url is in the list of allowed URLs
if next_url not in allowed_urls:
self.log.warning("Disallowing redirect to untrusted URL: %r", next_url)
next_url = ''

Copilot is powered by AI and may make mistakes. Always verify output.
# auto_login failed, just 403
raise web.HTTPError(403)
else:
self.redirect(self.get_next_url(user))

Check warning

Code scanning / CodeQL

URL redirection from remote source Medium

Untrusted URL redirection depends on a
user-provided value
.
Untrusted URL redirection depends on a
user-provided value
.

Copilot Autofix

AI about 2 months ago

To fix the problem, we need to ensure that the _validate_next_url method in BaseHandler is robust enough to prevent any untrusted URL redirection. We will enhance the validation logic to ensure that only relative URLs are allowed and that any potentially dangerous URLs are rejected.

  • Modify the _validate_next_url method in BaseHandler to include additional checks for URL safety.
  • Ensure that the get_next_url method in BaseHandler uses the enhanced _validate_next_url method to validate the URL before redirecting.
  • Update the LoginHandler class in grader_service/auth/login.py to use the validated URL for redirection.
Suggested changeset 2
grader_service/auth/login.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/grader_service/auth/login.py b/grader_service/auth/login.py
--- a/grader_service/auth/login.py
+++ b/grader_service/auth/login.py
@@ -116,3 +116,6 @@
                     else:
-                        self.redirect(self.get_next_url(user))
+                        next_url = self.get_next_url(user)
+                        if not next_url:
+                            next_url = '/'
+                        self.redirect(next_url)
                 else:
@@ -143,3 +146,6 @@
             self._grader_user = user
-            self.redirect(self.get_next_url(user))
+            next_url = self.get_next_url(user)
+            if not next_url:
+                next_url = '/'
+            self.redirect(next_url)
         else:
EOF
@@ -116,3 +116,6 @@
else:
self.redirect(self.get_next_url(user))
next_url = self.get_next_url(user)
if not next_url:
next_url = '/'
self.redirect(next_url)
else:
@@ -143,3 +146,6 @@
self._grader_user = user
self.redirect(self.get_next_url(user))
next_url = self.get_next_url(user)
if not next_url:
next_url = '/'
self.redirect(next_url)
else:
grader_service/handlers/base_handler.py
Outside changed files

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/grader_service/handlers/base_handler.py b/grader_service/handlers/base_handler.py
--- a/grader_service/handlers/base_handler.py
+++ b/grader_service/handlers/base_handler.py
@@ -709,2 +709,7 @@
 
+        # Ensure the URL is relative
+        if not next_url.startswith('/'):
+            self.log.warning("Disallowing non-relative redirect: %r", next_url)
+            next_url = ''
+
         return next_url
EOF
@@ -709,2 +709,7 @@

# Ensure the URL is relative
if not next_url.startswith('/'):
self.log.warning("Disallowing non-relative redirect: %r", next_url)
next_url = ''

return next_url
Copilot is powered by AI and may make mistakes. Always verify output.
if user:
# register current user for subsequent requests to user (e.g. logging the request)
self._grader_user = user
self.redirect(self.get_next_url(user))

Check warning

Code scanning / CodeQL

URL redirection from remote source Medium

Untrusted URL redirection depends on a
user-provided value
.
Untrusted URL redirection depends on a
user-provided value
.

Copilot Autofix

AI about 2 months ago

To fix the problem, we need to ensure that the next_url is properly validated before being used in a redirect. We can enhance the _validate_next_url method to be more robust and ensure that only safe URLs are allowed. Additionally, we should update the get_next_url method to use this enhanced validation.

  1. Enhance the _validate_next_url method to include stricter checks for allowed hosts and schemes.
  2. Update the get_next_url method to use the enhanced _validate_next_url method.
  3. Ensure that the redirect method in login.py uses the validated next_url.
Suggested changeset 2
grader_service/auth/login.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/grader_service/auth/login.py b/grader_service/auth/login.py
--- a/grader_service/auth/login.py
+++ b/grader_service/auth/login.py
@@ -143,3 +143,6 @@
             self._grader_user = user
-            self.redirect(self.get_next_url(user))
+            next_url = self.get_next_url(user)
+            if not next_url:
+                next_url = '/'
+            self.redirect(next_url)
         else:
EOF
@@ -143,3 +143,6 @@
self._grader_user = user
self.redirect(self.get_next_url(user))
next_url = self.get_next_url(user)
if not next_url:
next_url = '/'
self.redirect(next_url)
else:
grader_service/handlers/base_handler.py
Outside changed files

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/grader_service/handlers/base_handler.py b/grader_service/handlers/base_handler.py
--- a/grader_service/handlers/base_handler.py
+++ b/grader_service/handlers/base_handler.py
@@ -709,2 +709,7 @@
 
+        # Ensure the URL is relative and does not contain an explicit host
+        if parsed_next_url.netloc or parsed_next_url.scheme:
+            self.log.warning("Disallowing redirect with explicit host or scheme: %r", next_url)
+            next_url = ''
+
         return next_url
EOF
@@ -709,2 +709,7 @@

# Ensure the URL is relative and does not contain an explicit host
if parsed_next_url.netloc or parsed_next_url.scheme:
self.log.warning("Disallowing redirect with explicit host or scheme: %r", next_url)
next_url = ''

return next_url
Copilot is powered by AI and may make mistakes. Always verify output.
async def redirect_to_next_url(self, user):
"""Redirect user agent to next url that has been received in the login initiation request."""
next_url = self.get_next_url(user)
self.redirect(next_url)

Check warning

Code scanning / CodeQL

URL redirection from remote source Medium

Untrusted URL redirection depends on a
user-provided value
.
Untrusted URL redirection depends on a
user-provided value
.
Untrusted URL redirection depends on a
user-provided value
.
Untrusted URL redirection depends on a
user-provided value
.
Untrusted URL redirection depends on a
user-provided value
.

Copilot Autofix

AI about 2 months ago

To fix the problem, we need to ensure that the next_url is validated before it is used in the redirect function. We can achieve this by using the _validate_next_url method from the BaseHandler class to validate the next_url before redirecting.

  1. Modify the redirect_to_next_url method in grader_service/auth/lti13/handlers.py to validate the next_url using the _validate_next_url method.
  2. Ensure that the validated next_url is used in the redirect function.
Suggested changeset 1
grader_service/auth/lti13/handlers.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/grader_service/auth/lti13/handlers.py b/grader_service/auth/lti13/handlers.py
--- a/grader_service/auth/lti13/handlers.py
+++ b/grader_service/auth/lti13/handlers.py
@@ -399,2 +399,3 @@
         next_url = self.get_next_url(user)
+        next_url = self._validate_next_url(next_url)
         self.redirect(next_url)
EOF
@@ -399,2 +399,3 @@
next_url = self.get_next_url(user)
next_url = self._validate_next_url(next_url)
self.redirect(next_url)
Copilot is powered by AI and may make mistakes. Always verify output.
if user is None:
raise web.HTTPError(403, reason=self.authenticator.custom_403_message)

self.redirect(self.get_next_url(user))

Check warning

Code scanning / CodeQL

URL redirection from remote source Medium

Untrusted URL redirection depends on a
user-provided value
.
Untrusted URL redirection depends on a
user-provided value
.
Untrusted URL redirection depends on a
user-provided value
.
Untrusted URL redirection depends on a
user-provided value
.

Copilot Autofix

AI about 2 months ago

To fix the problem, we need to enhance the validation of the next_url to ensure it is safe for redirection. We can achieve this by using the _validate_next_url method from BaseHandler in the OAuthCallbackHandler class to validate the next_url before using it for redirection. This will ensure that the URL is within the same host and protocol, mitigating the risk of URL redirection attacks.

  1. Modify the get_next_url method in OAuthCallbackHandler to use _validate_next_url for validating the next_url.
  2. Ensure that the next_url is validated before it is used in the redirect method.
Suggested changeset 1
grader_service/auth/oauth2.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/grader_service/auth/oauth2.py b/grader_service/auth/oauth2.py
--- a/grader_service/auth/oauth2.py
+++ b/grader_service/auth/oauth2.py
@@ -194,3 +194,5 @@
             if next_url:
-                return next_url
+                next_url = self._validate_next_url(next_url)
+                if next_url:
+                    return next_url
         # JupyterHub 0.8 adds default .get_next_url for a fallback
EOF
@@ -194,3 +194,5 @@
if next_url:
return next_url
next_url = self._validate_next_url(next_url)
if next_url:
return next_url
# JupyterHub 0.8 adds default .get_next_url for a fallback
Copilot is powered by AI and may make mistakes. Always verify output.
self.gitbase,
lecture.code,
str(assignment.id),
assignment.settings.assignment_type,

Check failure

Code scanning / CodeQL

Uncontrolled data used in path expression High

This path depends on a
user-provided value
.

Copilot Autofix

AI about 2 months ago

To fix the problem, we need to ensure that the constructed file path is contained within a safe root folder. We can achieve this by normalizing the path using os.path.normpath and then checking that the normalized path starts with the expected base directory. This will prevent directory traversal attacks.

  1. Normalize the git_repo_path and submission_repo_path using os.path.normpath.
  2. Verify that the normalized paths start with the base directory (self.gitbase).
Suggested changeset 1
grader_service/handlers/submissions.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/grader_service/handlers/submissions.py b/grader_service/handlers/submissions.py
--- a/grader_service/handlers/submissions.py
+++ b/grader_service/handlers/submissions.py
@@ -643,3 +643,3 @@
         # Path to repository which will store edited submission files
-        git_repo_path = os.path.join(
+        git_repo_path = os.path.normpath(os.path.join(
             self.gitbase,
@@ -649,6 +649,6 @@
             str(submission_id),
-        )
+        ))
 
         # Path to repository of student which contains the submitted files
-        submission_repo_path = os.path.join(
+        submission_repo_path = os.path.normpath(os.path.join(
             self.gitbase,
@@ -658,3 +658,6 @@
             submission.username
-        )
+        ))
+
+        if not git_repo_path.startswith(self.gitbase) or not submission_repo_path.startswith(self.gitbase):
+            raise Exception("Invalid path")
 
EOF
@@ -643,3 +643,3 @@
# Path to repository which will store edited submission files
git_repo_path = os.path.join(
git_repo_path = os.path.normpath(os.path.join(
self.gitbase,
@@ -649,6 +649,6 @@
str(submission_id),
)
))

# Path to repository of student which contains the submitted files
submission_repo_path = os.path.join(
submission_repo_path = os.path.normpath(os.path.join(
self.gitbase,
@@ -658,3 +658,6 @@
submission.username
)
))

if not git_repo_path.startswith(self.gitbase) or not submission_repo_path.startswith(self.gitbase):
raise Exception("Invalid path")

Copilot is powered by AI and may make mistakes. Always verify output.
lecture.code,
str(assignment.id),
assignment.settings.assignment_type,
submission.username

Check failure

Code scanning / CodeQL

Uncontrolled data used in path expression High

This path depends on a
user-provided value
.

Copilot Autofix

AI about 2 months ago

To fix the problem, we need to ensure that the constructed file paths are safe and do not allow path traversal attacks. We can achieve this by normalizing the paths and ensuring they are contained within a safe root directory. Specifically, we will:

  1. Normalize the git_repo_path and submission_repo_path using os.path.normpath.
  2. Ensure that the normalized paths start with the expected base directory (self.gitbase).
Suggested changeset 1
grader_service/handlers/submissions.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/grader_service/handlers/submissions.py b/grader_service/handlers/submissions.py
--- a/grader_service/handlers/submissions.py
+++ b/grader_service/handlers/submissions.py
@@ -643,3 +643,3 @@
         # Path to repository which will store edited submission files
-        git_repo_path = os.path.join(
+        git_repo_path = os.path.normpath(os.path.join(
             self.gitbase,
@@ -649,6 +649,8 @@
             str(submission_id),
-        )
+        ))
+        if not git_repo_path.startswith(self.gitbase):
+            raise HTTPError(HTTPStatus.BAD_REQUEST, reason="Invalid path")
 
         # Path to repository of student which contains the submitted files
-        submission_repo_path = os.path.join(
+        submission_repo_path = os.path.normpath(os.path.join(
             self.gitbase,
@@ -658,3 +660,5 @@
             submission.username
-        )
+        ))
+        if not submission_repo_path.startswith(self.gitbase):
+            raise HTTPError(HTTPStatus.BAD_REQUEST, reason="Invalid path")
 
EOF
@@ -643,3 +643,3 @@
# Path to repository which will store edited submission files
git_repo_path = os.path.join(
git_repo_path = os.path.normpath(os.path.join(
self.gitbase,
@@ -649,6 +649,8 @@
str(submission_id),
)
))
if not git_repo_path.startswith(self.gitbase):
raise HTTPError(HTTPStatus.BAD_REQUEST, reason="Invalid path")

# Path to repository of student which contains the submitted files
submission_repo_path = os.path.join(
submission_repo_path = os.path.normpath(os.path.join(
self.gitbase,
@@ -658,3 +660,5 @@
submission.username
)
))
if not submission_repo_path.startswith(self.gitbase):
raise HTTPError(HTTPStatus.BAD_REQUEST, reason="Invalid path")

Copilot is powered by AI and may make mistakes. Always verify output.
submission.username
)

if os.path.exists(git_repo_path):

Check failure

Code scanning / CodeQL

Uncontrolled data used in path expression High

This path depends on a
user-provided value
.

Copilot Autofix

AI about 2 months ago

To fix the problem, we need to ensure that the constructed file paths are safe and do not allow directory traversal attacks. We can achieve this by normalizing the paths and ensuring they are contained within a designated root directory. Specifically, we will:

  1. Normalize the constructed paths using os.path.normpath.
  2. Verify that the normalized paths start with the expected base directory.
Suggested changeset 1
grader_service/handlers/submissions.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/grader_service/handlers/submissions.py b/grader_service/handlers/submissions.py
--- a/grader_service/handlers/submissions.py
+++ b/grader_service/handlers/submissions.py
@@ -643,3 +643,3 @@
         # Path to repository which will store edited submission files
-        git_repo_path = os.path.join(
+        git_repo_path = os.path.normpath(os.path.join(
             self.gitbase,
@@ -649,6 +649,8 @@
             str(submission_id),
-        )
+        ))
+        if not git_repo_path.startswith(self.gitbase):
+            raise HTTPError(HTTPStatus.BAD_REQUEST, reason="Invalid submission path")
 
         # Path to repository of student which contains the submitted files
-        submission_repo_path = os.path.join(
+        submission_repo_path = os.path.normpath(os.path.join(
             self.gitbase,
@@ -658,3 +660,5 @@
             submission.username
-        )
+        ))
+        if not submission_repo_path.startswith(self.gitbase):
+            raise HTTPError(HTTPStatus.BAD_REQUEST, reason="Invalid submission path")
 
EOF
@@ -643,3 +643,3 @@
# Path to repository which will store edited submission files
git_repo_path = os.path.join(
git_repo_path = os.path.normpath(os.path.join(
self.gitbase,
@@ -649,6 +649,8 @@
str(submission_id),
)
))
if not git_repo_path.startswith(self.gitbase):
raise HTTPError(HTTPStatus.BAD_REQUEST, reason="Invalid submission path")

# Path to repository of student which contains the submitted files
submission_repo_path = os.path.join(
submission_repo_path = os.path.normpath(os.path.join(
self.gitbase,
@@ -658,3 +660,5 @@
submission.username
)
))
if not submission_repo_path.startswith(self.gitbase):
raise HTTPError(HTTPStatus.BAD_REQUEST, reason="Invalid submission path")

Copilot is powered by AI and may make mistakes. Always verify output.
)

if os.path.exists(git_repo_path):
shutil.rmtree(git_repo_path)

Check failure

Code scanning / CodeQL

Uncontrolled data used in path expression High

This path depends on a
user-provided value
.

Copilot Autofix

AI about 2 months ago

To fix the problem, we need to ensure that the constructed file paths are safe and do not allow directory traversal attacks. This can be achieved by normalizing the paths and ensuring they are within a designated safe directory.

  1. Normalize the constructed paths using os.path.normpath.
  2. Verify that the normalized paths start with the expected base directory.

We will apply these changes to the construction of git_repo_path, submission_repo_path, and tmp_path.

Suggested changeset 1
grader_service/handlers/submissions.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/grader_service/handlers/submissions.py b/grader_service/handlers/submissions.py
--- a/grader_service/handlers/submissions.py
+++ b/grader_service/handlers/submissions.py
@@ -643,3 +643,3 @@
         # Path to repository which will store edited submission files
-        git_repo_path = os.path.join(
+        git_repo_path = os.path.normpath(os.path.join(
             self.gitbase,
@@ -649,6 +649,8 @@
             str(submission_id),
-        )
+        ))
+        if not git_repo_path.startswith(self.gitbase):
+            raise HTTPError(HTTPStatus.BAD_REQUEST, "Invalid submission ID")
 
         # Path to repository of student which contains the submitted files
-        submission_repo_path = os.path.join(
+        submission_repo_path = os.path.normpath(os.path.join(
             self.gitbase,
@@ -658,3 +660,5 @@
             submission.username
-        )
+        ))
+        if not submission_repo_path.startswith(self.gitbase):
+            raise HTTPError(HTTPStatus.BAD_REQUEST, "Invalid submission path")
 
@@ -671,3 +675,3 @@
         # files in the edit repository
-        tmp_path = os.path.join(
+        tmp_path = os.path.normpath(os.path.join(
             self.application.grader_service_dir,
@@ -678,3 +682,5 @@
             str(submission.id),
-        )
+        ))
+        if not tmp_path.startswith(self.application.grader_service_dir):
+            raise HTTPError(HTTPStatus.BAD_REQUEST, "Invalid temporary path")
 
EOF
@@ -643,3 +643,3 @@
# Path to repository which will store edited submission files
git_repo_path = os.path.join(
git_repo_path = os.path.normpath(os.path.join(
self.gitbase,
@@ -649,6 +649,8 @@
str(submission_id),
)
))
if not git_repo_path.startswith(self.gitbase):
raise HTTPError(HTTPStatus.BAD_REQUEST, "Invalid submission ID")

# Path to repository of student which contains the submitted files
submission_repo_path = os.path.join(
submission_repo_path = os.path.normpath(os.path.join(
self.gitbase,
@@ -658,3 +660,5 @@
submission.username
)
))
if not submission_repo_path.startswith(self.gitbase):
raise HTTPError(HTTPStatus.BAD_REQUEST, "Invalid submission path")

@@ -671,3 +675,3 @@
# files in the edit repository
tmp_path = os.path.join(
tmp_path = os.path.normpath(os.path.join(
self.application.grader_service_dir,
@@ -678,3 +682,5 @@
str(submission.id),
)
))
if not tmp_path.startswith(self.application.grader_service_dir):
raise HTTPError(HTTPStatus.BAD_REQUEST, "Invalid temporary path")

Copilot is powered by AI and may make mistakes. Always verify output.
def random_port():
"""Get a single random port."""
sock = socket.socket()
sock.bind(('', 0))

Check warning

Code scanning / CodeQL

Binding a socket to all network interfaces Medium

'' binds a socket to all interfaces.

Copilot Autofix

AI about 2 months ago

To fix the problem, we should bind the socket to the loopback interface (127.0.0.1) instead of all interfaces. This change will limit the socket's exposure to the local machine only, reducing the security risks associated with binding to all interfaces.

  • Update the random_port function in the grader_service/utils.py file.
  • Change the binding address from ('', 0) to ('127.0.0.1', 0).
Suggested changeset 1
grader_service/utils.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/grader_service/utils.py b/grader_service/utils.py
--- a/grader_service/utils.py
+++ b/grader_service/utils.py
@@ -55,3 +55,3 @@
     sock = socket.socket()
-    sock.bind(('', 0))
+    sock.bind(('127.0.0.1', 0))
     port = sock.getsockname()[1]
EOF
@@ -55,3 +55,3 @@
sock = socket.socket()
sock.bind(('', 0))
sock.bind(('127.0.0.1', 0))
port = sock.getsockname()[1]
Copilot is powered by AI and may make mistakes. Always verify output.
@florian-jaeger florian-jaeger merged commit 0157b8a into main Mar 20, 2025
25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants