You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by br...@apache.org on 2026/09/10 17:05:57 UTC

(allura) 01/06: [#8621] test for FTP redirect bypassing internal-host protection

This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/allura.git

commit b71f771a1ddcdc80bcd96b2000133b6d55b43f97
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Tue Aug 25 17:03:37 2026 -0400

    [#8621] test for FTP redirect bypassing internal-host protection
    
    NonPrivateUrl is only checked by our http/https handlers. A redirect
    to ftp:// reaches urllib's default FTPHandler, which has no such
    check, so it can reach internal/private hosts unvalidated.
    
    Co-Authored-By: Claude Sonnet 5 <no...@anthropic.com>
---
 Allura/allura/tests/test_helpers.py | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/Allura/allura/tests/test_helpers.py b/Allura/allura/tests/test_helpers.py
index 5ea729e59..fbee314fe 100644
--- a/Allura/allura/tests/test_helpers.py
+++ b/Allura/allura/tests/test_helpers.py
@@ -16,6 +16,7 @@
 #       under the License.
 
 import io
+import urllib.request
 from unittest import skipIf
 from os import path
 from datetime import datetime, timedelta
@@ -535,6 +536,19 @@ def test_internal_invalid(self, url):
     def test_ok(self, url):
         h.urlopen(url)
 
+    @pytest.mark.parametrize('url', [
+        f'https://{httpbin_domain}/redirect-to?url=ftp://127.0.0.1/',
+        f'https://{httpbin_domain}/redirect-to?url=ftp://localhost/',
+    ])
+    def test_internal_invalid_ftp_redirect(self, url):
+        # our opener has no ftp handler at all, so a redirect to ftp:// can't be used to bypass NonPrivateUrl
+        with pytest.raises(urllib.error.URLError, match='unknown url type'):
+            h.urlopen(url)
+
+    def test_ftp_not_supported(self):
+        with pytest.raises(urllib.error.URLError, match='unknown url type'):
+            urllib.request.urlopen('ftp://127.0.0.1/some/file')  # noqa: S310
+
     @patch('urllib.request.urlopen')
     @patch.dict(config, {'urlopen_allow_internal_hostnames': 'true'})
     def test_no_error(self, urlopen):