Skip to content

fix: enhance path traversal protection#321

Closed
LemonZuo wants to merge 3 commits intoBeehiveInnovations:mainfrom
LemonZuo:main
Closed

fix: enhance path traversal protection#321
LemonZuo wants to merge 3 commits intoBeehiveInnovations:mainfrom
LemonZuo:main

Conversation

@LemonZuo
Copy link
Copy Markdown

@LemonZuo LemonZuo commented Nov 8, 2025

Description

This PR addresses critical security vulnerabilities reported in #293. It implements comprehensive path traversal protection
using the relative_to() method as recommended by the security researcher.

Changes Made

  • Enhanced path traversal detection in utils/security_config.py using relative_to() method
  • Added multi-layer security validation (pattern detection, Windows path check, subdirectory validation)
  • Fixed Windows path detection for cross-platform security
  • Added safe path allowlist for /tmp, /home/* directories
  • Integrated security validation into all file operations (read_file_safely, load_json_file, etc.)
  • Enhanced image file path validation in utils/image_utils.py
  • Added comprehensive test suite for path traversal prevention

Testing

Code quality checks passed

./code_quality_checks.sh
✅ All linting and formatting checks passed

Unit tests

python -m unittest tests.test_path_traversal_security -v
✅ 12 tests passed

Security validation tests

✅ Subdirectory blocking validated
✅ Path traversal patterns detected
✅ Windows paths properly blocked
✅ Issue #293 PoC successfully prevented

  • All linting passes (ruff, black, isort)
  • All unit tests pass
  • For bug fixes: Tests added to prevent regression (tests/test_path_traversal_security.py)
  • Manual testing completed with PoC from Path travasal vulnerability #293

Related Issues

Additional Notes

Security Improvements:

  1. Multi-layer defense: Three validation layers ensure comprehensive protection
  2. Cross-platform support: Detects Windows paths even on Unix systems
  3. Follows security best practices: Implements defense in depth

Test Coverage:

  • Basic path traversal patterns (../, ..\)
  • URL encoded attacks (%2f, %5c)
  • Null byte injection
  • Subdirectory validation
  • Windows path detection
  • Symlink resolution

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @LemonZuo, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly bolsters the application's security posture by addressing a critical path traversal vulnerability. It introduces a sophisticated, multi-faceted validation mechanism for file paths, ensuring that all file system interactions are safe and confined to intended areas, thereby preventing unauthorized access to sensitive system files or directories.

Highlights

  • Enhanced Path Traversal Protection: Implemented comprehensive path traversal protection using the pathlib.Path.relative_to() method, as recommended by security researchers, to ensure paths are strictly within allowed directories.
  • Multi-Layered Security Validation: Introduced a robust, multi-layered security validation system that includes pattern detection for common traversal attempts (e.g., ../, URL-encoded sequences, null bytes), cross-platform Windows path checks, and subdirectory validation.
  • Expanded Dangerous Paths and Safe Allowlist: The DANGEROUS_PATHS list has been significantly expanded to include more sensitive Unix and Windows system directories, while a new safe_prefixes allowlist has been added for legitimate access to directories like /tmp and user home directories.
  • Integration into File Operations: The new security validation logic has been integrated into critical file operations such as read_file_safely and _validate_file_path (for images), ensuring that all file access attempts are first vetted for security risks.
  • Comprehensive Test Suite: A new, extensive test suite (tests/test_path_traversal_security.py) has been added to cover various path traversal attack vectors, including basic patterns, URL encoding, null byte injection, hex encoding, mixed separators, Unicode bypass attempts, and case sensitivity.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request significantly enhances path traversal protection, addressing a critical security vulnerability. The core logic in is_dangerous_path is now much more robust, using a multi-layered defense that includes pattern matching, null byte checks, and safe relative_to() checks against allow- and denylists. The new security validation is correctly integrated into file reading functions in file_utils.py and image_utils.py. The addition of a comprehensive test suite in test_path_traversal_security.py is excellent and covers a wide range of attack vectors.

I've identified a high-severity issue with the path traversal pattern matching that could lead to false positives, and a medium-severity performance issue due to repeated path resolutions in a loop. My feedback includes suggestions to address these points.

Comment on lines +119 to +137
# Check for path traversal patterns BEFORE resolution
# This prevents attacks that use symlinks or other techniques
traversal_patterns = [
"..", # Unix/Windows path traversal
"..%2f", # URL encoded forward slash
"..%2F", # URL encoded forward slash (uppercase)
"..%5c", # URL encoded backslash
"..%5C", # URL encoded backslash (uppercase)
"%2e%2e", # Double URL encoded dots
"%252e%252e", # Double URL encoded
"..;/", # Path traversal with semicolon
"..\\x2f", # Hex encoded slash
"..\\x5c", # Hex encoded backslash
]

# Check for any traversal patterns
for pattern in traversal_patterns:
if pattern in path_str.lower():
return True
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The current check for path traversal patterns using if ".." in path_str.lower() is too broad and can lead to false positives. For example, a valid filename like notes..txt or a directory version-1.0..beta would be incorrectly flagged as dangerous. The check for .. should be more specific to when it's used as a path component for traversal. A more robust approach is to check for .. in the path's components, reserving the substring search for encoded patterns.

        # Check for path traversal patterns BEFORE resolution
        # This prevents attacks that use symlinks or other techniques

        # Using `path.parts` is more robust for ".." and avoids false positives.
        if ".." in path.parts:
            return True

        traversal_patterns = [
            "..%2f",  # URL encoded forward slash
            "..%2F",  # URL encoded forward slash (uppercase)
            "..%5c",  # URL encoded backslash
            "..%5C",  # URL encoded backslash (uppercase)
            "%2e%2e",  # Double URL encoded dots
            "%252e%252e",  # Double URL encoded
            "..;/",  # Path traversal with semicolon
            "..\\x2f",  # Hex encoded slash
            "..\\x5c",  # Hex encoded backslash
        ]

        # Check for any encoded traversal patterns
        for pattern in traversal_patterns:
            if pattern in path_str.lower():
                return True

Comment on lines +189 to +209
for dangerous in DANGEROUS_PATHS:
try:
# Skip root directory check if path is in safe locations
if dangerous == "/":
# For root, only block if it's actually the root
if resolved == Path("/").resolve():
return True
# Skip the relative_to check for root
continue

# Try to create a relative path from the dangerous directory
danger_path = Path(dangerous).resolve()
resolved.relative_to(danger_path)
# If successful, the path is under a dangerous directory
return True
except ValueError:
# Path is not relative to this dangerous directory
continue
except Exception:
# Handle any other errors safely
continue
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The function repeatedly calls Path(dangerous).resolve() inside a loop for every path check. This is inefficient as the set of dangerous paths is constant. These paths can be resolved once at the module level to improve performance, especially since this function may be called frequently. A similar optimization can be applied to the safe_prefixes check.

You could define the resolved paths at the module level like this:

# At module level
_RESOLVED_DANGEROUS_PATHS = set()
for p in DANGEROUS_PATHS:
    if p == "/": continue
    try:
        _RESOLVED_DANGEROUS_PATHS.add(Path(p).resolve())
    except Exception:
        # Path might not exist on this OS (e.g., C:\\Windows on Linux), so we skip.
        pass

# And then use it in the loop:
for danger_path in _RESOLVED_DANGEROUS_PATHS:
    try:
        resolved.relative_to(danger_path)
        return True # It's a subpath of a dangerous one
    except ValueError:
        continue

@LemonZuo LemonZuo closed this Nov 8, 2025
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.

Path travasal vulnerability

2 participants