Skip to content
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

Fixed rebuild_safe_url function #3832

Open
wants to merge 16 commits into
base: main
Choose a base branch
from

Conversation

gojo-satorou-v7
Copy link
Contributor

@gojo-satorou-v7 gojo-satorou-v7 commented Mar 6, 2025

User description

Now the rebuild_safe_url checks for potential ssrf payload and returns None in case such url is provided, also I have made the path sanitization better since the previous one only removed the query and fragment part from the path but now it checks furtherfor carriage return and line feed and other misused paths and normalizes them.

fixes #3797
fixes #3923


PR Type

Bug fix, Tests


Description

  • Enhanced rebuild_safe_url to sanitize URLs against SSRF vulnerabilities.

  • Added is_dns_safe function to validate DNS safety of URLs.

  • Introduced comprehensive test cases for rebuild_safe_url function.

  • Removed deprecated is_safe_url function to streamline URL validation.


Changes walkthrough 📝

Relevant files
Tests
test_api.py
Add test cases for `rebuild_safe_url` function                     

website/test_api.py

  • Added a new test case class RebuildSafeUrlTestCase.
  • Included multiple test scenarios for rebuild_safe_url.
  • Validated URL sanitization against encoded characters, CRLF, and path
    traversal.
  • +28/-0   
    Bug fix
    utils.py
    Improve URL sanitization and add DNS safety checks             

    website/utils.py

  • Enhanced rebuild_safe_url to sanitize URLs against SSRF
    vulnerabilities.
  • Added is_dns_safe function to validate DNS safety of hostnames.
  • Improved path normalization and encoding in rebuild_safe_url.
  • Removed deprecated is_safe_url function.
  • +53/-17 

    Need help?
  • Type /help how to ... in the comments thread for any questions about PR-Agent usage.
  • Check out the documentation for more information.
  • Copy link
    Contributor

    github-actions bot commented Mar 6, 2025

    PR Reviewer Guide 🔍

    (Review updated until commit 0ae056d)

    Here are some key observations to aid the review process:

    🎫 Ticket compliance analysis 🔶

    3797 - Partially compliant

    Compliant requirements:

    • Ensure rebuild_safe_url function sanitizes URLs to prevent SSRF vulnerabilities.
    • Validate DNS safety of URLs to block internal, loopback, and other unsafe addresses.
    • Normalize and sanitize paths to prevent misuse (e.g., CRLF injection, path traversal).
    • Remove deprecated or redundant functions related to URL validation.

    Non-compliant requirements:

    []

    Requires further human verification:

    []

    ⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
    🧪 PR contains tests
    🔒 No security concerns identified
    ⚡ Recommended focus areas for review

    Possible Issue

    The path.replace logic in rebuild_safe_url might not handle all edge cases of path traversal or CRLF injection. Ensure comprehensive testing and validation.

    path = parsed_url.path
    path = path.replace("\r", "").replace("\n", "")
    path = path.replace("/..", "").replace("/", "/")
    
    # Collapse multiple slashes into a single slash
    path = re.sub(r"/{2,}", "/", path)
    if path in ("", "."):
        path = "/"
    # Ensure the path starts with a slash
    elif not path.startswith("/"):
        path = "/" + path
    encoded_path = quote(path, safe="/")
    DNS Safety Validation

    The is_dns_safe function might not account for all edge cases of unsafe DNS resolution. Verify its robustness against potential bypass techniques.

    def is_dns_safe(hostname):
        try:
            resolved = socket.getaddrinfo(hostname, None)
        except socket.gaierror:
            return False  # Unable to resolve hostname; treat as unsafe.
        for result in resolved:
            ip_str = result[4][0]
            try:
                ip = ip_address(ip_str)
                if ip.is_private or ip.is_loopback or ip.is_reserved or ip.is_link_local:
                    return False
            except ValueError:
                continue
        return True

    Copy link
    Contributor

    github-actions bot commented Mar 6, 2025

    PR Code Suggestions ✨

    @gojo-satorou-v7 gojo-satorou-v7 marked this pull request as ready for review March 7, 2025 08:32
    Copy link
    Contributor

    github-actions bot commented Mar 7, 2025

    Persistent review updated to latest commit 0ae056d

    Copy link
    Contributor

    github-actions bot commented Mar 7, 2025

    PR Code Suggestions ✨

    @gojo-satorou-v7
    Copy link
    Contributor Author

    gojo-satorou-v7 commented Mar 7, 2025

    This fixes the issue for the rebuild_safe_url which was introducing SSRF vulnerabilities in the /website/views/issue.py at file issues.py and company.py by improperly sanitizing the url. My changes to the code bring enhanced protection from SSRF, CRLF and path traversal vulnerabilities by properly sanitizing and blocking requests to internal ip address.

    The dns_safe is another function added which first resolves the input url from the user and then resolves it's ip address before processing it any further [Protects from dns rebinding] . It is advisable to use this version of rebuild_safe_url wherever there;s a need to take user input.

    @gojo-satorou-v7
    Copy link
    Contributor Author

    @DonnieBLT I have added the test case, please check if any improvements are needed or edge case I might've missed.

    @gojo-satorou-v7
    Copy link
    Contributor Author

    gojo-satorou-v7 commented Mar 12, 2025

    Since the fix for #3923 was small I have included it in this PR.
    fixes #3923

    @gojo-satorou-v7
    Copy link
    Contributor Author

    Can this be merged? @DonnieBLT

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Projects
    None yet
    2 participants