Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,11 @@
**Learning:** Logic errors in security controls often lead to "fail-closed" states that break functionality entirely, or "fail-open" states that bypass security. Implicit returns in Python (`None`) can be dangerous when boolean validation is expected.

**Prevention:** Always use explicit return statements for both success and failure paths in validation functions. Use static analysis (linting) to catch unreachable code and implicit returns. Ensure unit tests cover positive cases (valid inputs) as rigorously as negative cases (attack vectors).

## 2026-10-24 - Missing Input Length Limits (DoS Risk)

**Vulnerability:** The application accepted unlimited length strings for folder names and rules. While validation checked for dangerous characters, extremely long strings could cause Denial of Service (DoS) or buffer issues in downstream systems/APIs.

**Learning:** Regex validation and character whitelisting are not enough; explicit length limits are required for complete input validation "Defense in Depth".

**Prevention:** Define explicit maximum constants (e.g., `MAX_FOLDER_NAME_LENGTH = 64`, `MAX_RULE_LENGTH = 255`) and enforce them in validation functions (`is_valid_folder_name`, `is_valid_rule`).
Comment on lines +65 to +71

Choose a reason for hiding this comment

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

medium

The addition of this section to the sentinel.md file is a good practice for documenting security vulnerabilities and their fixes. It clearly outlines the vulnerability, the learning, and the prevention steps, which is valuable for future reference and knowledge sharing.

17 changes: 14 additions & 3 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,11 @@
# Path separators (prevent confusion and directory traversal attempts)
_DANGEROUS_FOLDER_CHARS.update(["/", "\\"])

# Security: Input length limits
MAX_FOLDER_NAME_LENGTH = 64
MAX_RULE_LENGTH = 255
MAX_PROFILE_ID_LENGTH = 64
Comment on lines +211 to +214

Choose a reason for hiding this comment

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

medium

Introducing constants for maximum lengths is a good practice. It centralizes these values, making them easier to manage and update. This also improves readability and maintainability compared to hardcoding magic numbers directly in the validation logic.


# Security: Unicode Bidi control characters (prevent RTLO/homograph attacks)
# These characters can be used to mislead users about file extensions or content
# See: https://en.wikipedia.org/wiki/Right-to-left_override
Expand Down Expand Up @@ -993,7 +998,7 @@
"""
if not PROFILE_ID_PATTERN.match(profile_id):
return False
if len(profile_id) > 64:
if len(profile_id) > MAX_PROFILE_ID_LENGTH:
return False
return True

Expand All @@ -1009,8 +1014,8 @@
if log_errors:
if not PROFILE_ID_PATTERN.match(profile_id):
log.error("Invalid profile ID format (contains unsafe characters)")
elif len(profile_id) > 64:
log.error("Invalid profile ID length (max 64 chars)")
elif len(profile_id) > MAX_PROFILE_ID_LENGTH:
log.error(f"Invalid profile ID length (max {MAX_PROFILE_ID_LENGTH} chars)")

Check warning

Code scanning / Prospector (reported by Codacy)

Use lazy % formatting in logging functions (logging-fstring-interpolation) Warning

Use lazy % formatting in logging functions (logging-fstring-interpolation)

Check notice

Code scanning / Pylintpython3 (reported by Codacy)

Use lazy % formatting in logging functions Note

Use lazy % formatting in logging functions
return False
return True

Expand All @@ -1035,6 +1040,9 @@
if not rule:
return False

if len(rule) > MAX_RULE_LENGTH:
return False
Comment on lines +1043 to +1044

Choose a reason for hiding this comment

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

security-medium medium

The is_valid_rule function, which adds a length check for rule using MAX_RULE_LENGTH to prevent excessively long rule strings and address a Denial of Service (DoS) vulnerability, is currently not called in the production code. Specifically, the push_rules function (line 1967) bypasses this new length check by directly using RULE_PATTERN.match. This leaves the application vulnerable to DoS attacks from overly long rule inputs. To fully address this, push_rules should be updated to utilize is_valid_rule for rule validation (e.g., by changing line 1961 to match_rule = is_valid_rule).


# Strict whitelist to prevent injection
if not RULE_PATTERN.match(rule):
return False
Expand All @@ -1056,6 +1064,9 @@
if not name or not name.strip() or not name.isprintable():
return False

if len(name) > MAX_FOLDER_NAME_LENGTH:
return False

# Check for dangerous characters (pre-compiled at module level for performance)
if any(c in _DANGEROUS_FOLDER_CHARS or c in _BIDI_CONTROL_CHARS for c in name):
return False
Expand Down
50 changes: 50 additions & 0 deletions tests/test_security_limits.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import pytest

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Missing module docstring Warning test

Missing module docstring

Check warning

Code scanning / Prospector (reported by Codacy)

Unable to import 'pytest' (import-error) Warning test

Unable to import 'pytest' (import-error)

Check warning

Code scanning / Prospector (reported by Codacy)

Unused import pytest (unused-import) Warning test

Unused import pytest (unused-import)

Check notice

Code scanning / Pylintpython3 (reported by Codacy)

Unused import pytest Note test

Unused import pytest

Check warning

Code scanning / Pylint (reported by Codacy)

Missing module docstring Warning test

Missing module docstring

Check notice

Code scanning / Pylint (reported by Codacy)

Unused import pytest Note test

Unused import pytest
import main

def test_is_valid_folder_name_length_limit():
"""
Test that folder names exceeding the maximum length are rejected.
Current behavior: Accepts any length.
Expected behavior: Should reject length > 64.
"""
# Create a name with 65 characters
long_name = "a" * 65

# This should return False after the fix, but currently returns True
# We assert False to confirm the "failure" (vulnerability presence) or "success" (fix verification)

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Line too long (103/100) Warning test

Line too long (103/100)

Check warning

Code scanning / Pylint (reported by Codacy)

Line too long (103/100) Warning test

Line too long (103/100)
assert main.is_valid_folder_name(long_name) is False

Check notice

Code scanning / Bandit

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.

Check notice

Code scanning / Bandit (reported by Codacy)

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.

Comment on lines +5 to +16
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

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

Several docstrings/comments mention β€œcurrent behavior” and β€œcurrently returns True”, but once this PR is merged those statements will be false and can confuse future maintainers. Consider rewriting these tests to only describe the expected behavior being asserted.

Copilot uses AI. Check for mistakes.
def test_is_valid_folder_name_acceptable_length():
"""Test that folder names within limit are accepted."""
name = "a" * 64
assert main.is_valid_folder_name(name) is True

Check notice

Code scanning / Bandit

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.

Check notice

Code scanning / Bandit (reported by Codacy)

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.

def test_is_valid_rule_length_limit():
"""
Test that rules exceeding the maximum length are rejected.
Current behavior: Accepts any length (matching regex).
Expected behavior: Should reject length > 255.
"""
# Create a rule with 256 characters (valid chars)
long_rule = "a" * 256 + ".com"

# This should return False after the fix
assert main.is_valid_rule(long_rule) is False

Check notice

Code scanning / Bandit

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.

Check notice

Code scanning / Bandit (reported by Codacy)

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.

def test_is_valid_rule_acceptable_length():
"""Test that rules within limit are accepted."""
rule = "a" * 250 + ".com"
assert main.is_valid_rule(rule) is True

Check notice

Code scanning / Bandit

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
Comment on lines +28 to +37
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

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

The rule length test doesn’t actually hit the stated boundary: long_rule = "a" * 256 + ".com" is 260 chars, and the β€œacceptable” case is 254 chars. If the intent is to cover boundary conditions, adjust the test data to exercise exactly 255 (allowed) and 256 (rejected) characters (and update the comments accordingly).

Copilot generated this review using guidance from repository custom instructions.

Check notice

Code scanning / Bandit (reported by Codacy)

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.

def test_is_valid_profile_id_length_limit_constant():
"""
Test that profile ID validation respects the length limit.
Note: This function already had a length check, we are just formalizing it with a constant.
"""
# 65 chars
long_id = "a" * 65
assert main.validate_profile_id(long_id, log_errors=False) is False

Check notice

Code scanning / Bandit

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.

Check notice

Code scanning / Bandit (reported by Codacy)

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.

# 64 chars
valid_id = "a" * 64
assert main.validate_profile_id(valid_id, log_errors=False) is True

Check notice

Code scanning / Bandit

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.

Check notice

Code scanning / Bandit (reported by Codacy)

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
Comment on lines +1 to +50

Choose a reason for hiding this comment

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

medium

The addition of test_security_limits.py is excellent. It provides dedicated tests for the newly introduced length limits, ensuring that the fixes are working as expected and preventing regressions. The tests cover boundary conditions for folder names, rules, and profile IDs, which is comprehensive.

Loading