Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

Python: Should an empty `netloc` count as a `py/url-redirection` sanitizer when `///evil.com` passes the check?

Đang mở
#22,846 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
52/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
python
Lĩnh vực
security, testing-qa

Hướng nghiên cứu

Read python/ql/lib/semmle/python/frameworks/Stdlib/Urllib.qll around NetlocCheck, then inspect python/ql/src/Security/CWE-601/UrlRedirect.qhelp, redirect_good2.py, and the ok8 case in python/ql/test/query-tests/Security/CWE-601-UrlRedirect/test.py. Reproduce the three-slash case and run the URL redirect query tests; done means the sanitizer, help example, and test annotations consistently account for the demonstrated bypass.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

question

Description of the issue

py/url-redirection treats a check that urlparse(target).netloc is empty as a sanitizer, and the query help recommends this check, together with an empty scheme, as a way to validate redirect targets. I'm wondering whether the check is meant to be complete, because for ///evil.com or ////evil.com, urlparse returns an empty scheme and an empty netloc, so the check passes, while browsers resolve the redirect to https://evil.com/.

Affected sanitizer

NetlocCheck treats a read of urlparse(...).netloc used as a condition, or compared with anything, as a barrier guard for the NoBackslashes state. The query help recommends it in redirect_good2.py, and ok8 in the query test annotates it # OK.

Steps to reproduce

The help example, unchanged:

from flask import Flask, request, redirect
from urllib.parse import urlparse

app = Flask(__name__)

@app.route('/')
def hello():
    target = request.args.get('target', '')
    target = target.replace('\\', '')
    if not urlparse(target).netloc and not urlparse(target).scheme:
        # relative path, safe to redirect
        return redirect(target, code=302)
    # ignore the target and redirect to the home page
    return redirect('/', code=302)

The check from ok8, plus an unchecked redirect for comparison:

# Same check as `ok8` in python/ql/test/query-tests/Security/CWE-601-UrlRedirect/test.py
from flask import Flask, request, redirect
from urllib.parse import urlparse

app = Flask(__name__)

@app.route('/ok8')
def ok8():
    untrusted = request.args.get('target', '')
    untrusted = untrusted.replace("\\", "/")
    if not urlparse(untrusted).netloc:
        return redirect(untrusted, code=302) # OK
    return redirect("/", code=302)


@app.route('/bad')
def bad():
    return redirect(request.args.get('target', ''), code=302)  # control: reported

py/url-redirection (and python-security-extended.qls) reports only /bad. With Flask's test client, the help example produces these Location headers, and ok8 produces the same ones:

target Location
/home /home
https://evil.com /
//evil.com /
///evil.com ///evil.com
////evil.com ////evil.com

new URL("///evil.com", "https://example.com/login") and new URL("////evil.com", "https://example.com/login") both give https://evil.com/ (WHATWG URL parser, as used by browsers).

This looks related to #16041: #16646 added the scheme check to the help example for https:/example.com, but URLs without a scheme that start with three or more slashes still pass. Django's url_has_allowed_host_and_scheme, which the help recommends for Django, rejects them explicitly (django/utils/http.py: "Chrome considers any URL with more than two slashes to be absolute, but urlsplit is not so flexible. Treat any url with three slashes as unsafe.").

The check also occurs in real code: KindleEar#734 used the same netloc/scheme check as the help example (url_for(...) if parts.netloc or parts.scheme else nextUrl), and ////evil.com bypassed it. DeepBI#169 describes the same bypass of a urlsplit scheme/netloc check.

Question

Is NetlocCheck intended to treat scheme-less URLs that start with three or more slashes as safe? Would it be reasonable to keep the taint unless such URLs are also rejected, as Django does, and to update the help example and the ok8 annotation accordingly?

Environment

  • CodeQL CLI 2.27.2 (codeql/python-queries 1.8.12)
  • CodeQL repository commit for the links above: 781e068896eb7a1a104f1378e8f3f68a1074a015 (the files are unchanged since 2.27.2)
  • Python 3.10.12, Flask 3.0.0, Werkzeug 3.0.1; Node.js v24.18.0 for the URL resolution; Linux/amd64
Ngôn ngữ chính
CodeQL
Star
10.2k
Fork
2.1k
Merge trung bình
2 ngày 18 giờ
Pull request đã merge (30 ngày)
142

Chuẩn bị môi trường

Mở trong Codespaces

Khởi chạy dev container của dự án ngay trên trình duyệt, bằng tài khoản GitHub của bạn.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của github/codeql

Tất cả issue của github/codeql

Issue tương tự

Thêm issue về Security

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.