🛡️ Sentinel: [HIGH] Fix XSS risk in folder names#134
Conversation
Add strict validation for folder names parsed from external JSON files to prevent potential Stored XSS vulnerabilities. - Implement `is_valid_folder_name` to block XSS characters (< > " ' `) - Update `validate_folder_data` to check folder names - Add tests in `tests/test_folder_validation.py` covering XSS payloads and invalid types - Add journal entry for incomplete input validation scope
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
|
Merging to
|
| try: | ||
| # Case 1: Valid Folder Name | ||
| valid_data = {"group": {"group": "Safe Folder Name (Work)"}} | ||
| assert main.validate_folder_data(valid_data, "http://valid.com") 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
|
|
||
| # Case 2: XSS Payload | ||
| xss_data = {"group": {"group": "<script>alert(1)</script>"}} | ||
| assert main.validate_folder_data(xss_data, "http://evil.com") 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
|
|
||
| # Case 3: Invalid Type | ||
| invalid_type_data = {"group": {"group": 123}} | ||
| assert main.validate_folder_data(invalid_type_data, "http://badtype.com") 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
|
|
||
| # Case 4: Dangerous characters | ||
| dangerous_data = {"group": {"group": "Folder\"Name"}} | ||
| assert main.validate_folder_data(dangerous_data, "http://dangerous.com") 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
| 1. Implement strict validation on all data items from external lists (`is_valid_rule`). | ||
| 2. Filter out items containing dangerous characters (`<`, `>`, `"` etc.) or control codes. | ||
|
|
||
| ## 2026-06-01 - [Incomplete Input Validation Scope] |
Check notice
Code scanning / Remark-lint (reported by Codacy)
Warn when references to undefined definitions are found. Note
| 1. Implement strict validation on all data items from external lists (`is_valid_rule`). | ||
| 2. Filter out items containing dangerous characters (`<`, `>`, `"` etc.) or control codes. | ||
|
|
||
| ## 2026-06-01 - [Incomplete Input Validation Scope] |
Check notice
Code scanning / Remark-lint (reported by Codacy)
Warn when shortcut reference links are used. Note
| try: | ||
| # Case 1: Valid Folder Name | ||
| valid_data = {"group": {"group": "Safe Folder Name (Work)"}} | ||
| assert main.validate_folder_data(valid_data, "http://valid.com") is True |
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
|
|
||
| # Case 2: XSS Payload | ||
| xss_data = {"group": {"group": "<script>alert(1)</script>"}} | ||
| assert main.validate_folder_data(xss_data, "http://evil.com") is False |
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
|
|
||
| # Case 3: Invalid Type | ||
| invalid_type_data = {"group": {"group": 123}} | ||
| assert main.validate_folder_data(invalid_type_data, "http://badtype.com") is False |
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
|
|
||
| # Case 4: Dangerous characters | ||
| dangerous_data = {"group": {"group": "Folder\"Name"}} | ||
| assert main.validate_folder_data(dangerous_data, "http://dangerous.com") is False |
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
| # Security: Validate folder name | ||
| folder_name = data["group"]["group"] | ||
| if not isinstance(folder_name, str): | ||
| log.error(f"Invalid data from {sanitize_for_log(url)}: Folder name must be a string.") |
Check warning
Code scanning / Prospector (reported by Codacy)
Use lazy % formatting in logging functions (logging-fstring-interpolation) Warning
| return False | ||
|
|
||
| if not is_valid_folder_name(folder_name): | ||
| log.error(f"Invalid data from {sanitize_for_log(url)}: Unsafe folder name detected.") |
Check warning
Code scanning / Prospector (reported by Codacy)
Use lazy % formatting in logging functions (logging-fstring-interpolation) Warning
| @@ -0,0 +1,32 @@ | |||
| import pytest | |||
Check warning
Code scanning / Prospector (reported by Codacy)
Unable to import 'pytest' (import-error) Warning test
| @@ -0,0 +1,32 @@ | |||
| import pytest | |||
Check warning
Code scanning / Prospector (reported by Codacy)
Unused import pytest (unused-import) Warning test
| @@ -0,0 +1,32 @@ | |||
| import pytest | |||
Check warning
Code scanning / Pylint (reported by Codacy)
Missing module docstring Warning test
| @@ -0,0 +1,32 @@ | |||
| import pytest | |||
| from unittest.mock import MagicMock | |||
Check warning
Code scanning / Pylint (reported by Codacy)
standard import "from unittest.mock import MagicMock" should be placed before "import pytest" Warning test
| @@ -0,0 +1,32 @@ | |||
| import pytest | |||
Check notice
Code scanning / Pylint (reported by Codacy)
Unused import pytest Note test
| @@ -0,0 +1,32 @@ | |||
| import pytest | |||
Check warning
Code scanning / Pylintpython3 (reported by Codacy)
Missing module docstring Warning test
| @@ -0,0 +1,32 @@ | |||
| import pytest | |||
| from unittest.mock import MagicMock | |||
Check warning
Code scanning / Pylintpython3 (reported by Codacy)
standard import "from unittest.mock import MagicMock" should be placed before "import pytest" Warning test
| # Security: Validate folder name | ||
| folder_name = data["group"]["group"] | ||
| if not isinstance(folder_name, str): | ||
| log.error(f"Invalid data from {sanitize_for_log(url)}: Folder name must be a string.") |
Check notice
Code scanning / Pylintpython3 (reported by Codacy)
Use lazy % formatting in logging functions Note
| return False | ||
|
|
||
| if not is_valid_folder_name(folder_name): | ||
| log.error(f"Invalid data from {sanitize_for_log(url)}: Unsafe folder name detected.") |
Check notice
Code scanning / Pylintpython3 (reported by Codacy)
Use lazy % formatting in logging functions Note
| @@ -0,0 +1,32 @@ | |||
| import pytest | |||
Check notice
Code scanning / Pylintpython3 (reported by Codacy)
Unused import pytest Note test
There was a problem hiding this comment.
Pull request overview
This PR fixes a stored XSS vulnerability in folder names by adding validation to prevent malicious characters from being injected through external JSON sources. The vulnerability existed because while rule content was validated, folder names (metadata) were not, allowing XSS payloads to be stored and potentially executed in the UI.
Changes:
- Added
is_valid_folder_namefunction to validate folder names against XSS-dangerous characters - Updated
validate_folder_datato enforce string type checking and apply folder name validation - Added security tests to verify XSS payloads are rejected
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| main.py | Added is_valid_folder_name validation function and integrated it into validate_folder_data to reject dangerous characters in folder names |
| tests/test_folder_validation.py | Added comprehensive test cases for folder name security validation including XSS payloads, type validation, and dangerous characters |
| .jules/sentinel.md | Documented the vulnerability, learning, and prevention measures for incomplete input validation scope |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if not name or not name.isprintable(): | ||
| return False | ||
|
|
||
| # Block XSS and HTML injection characters | ||
| dangerous_chars = set("<>\"'`") | ||
| if any(c in dangerous_chars for c in name): |
There was a problem hiding this comment.
The validation in is_valid_folder_name checks the folder name before it's stripped, but the actual usage throughout the codebase (lines 721, 841, 872 in main.py) strips the folder name with .strip() before using it. This creates a validation bypass: a folder name consisting only of whitespace characters or one that becomes empty after stripping could pass validation but then cause issues or unexpected behavior when processed. The validation should either strip the name before checking, or explicitly reject names that would become empty after stripping. Consider modifying the function to: strip the name first, then check if it's empty.
| if not name or not name.isprintable(): | |
| return False | |
| # Block XSS and HTML injection characters | |
| dangerous_chars = set("<>\"'`") | |
| if any(c in dangerous_chars for c in name): | |
| # Normalize the folder name the same way it is used elsewhere | |
| stripped = name.strip() | |
| # Reject names that are empty or only whitespace after stripping | |
| if not stripped or not stripped.isprintable(): | |
| return False | |
| # Block XSS and HTML injection characters | |
| dangerous_chars = set("<>\"'`") | |
| if any(c in dangerous_chars for c in stripped): |
| def test_folder_name_security(): | ||
| """ | ||
| Verify that validate_folder_data enforces security checks on folder names. | ||
| """ | ||
| # Mock logger to verify errors | ||
| mock_log = MagicMock() | ||
| original_log = main.log | ||
| main.log = mock_log | ||
|
|
||
| try: | ||
| # Case 1: Valid Folder Name | ||
| valid_data = {"group": {"group": "Safe Folder Name (Work)"}} | ||
| assert main.validate_folder_data(valid_data, "http://valid.com") is True | ||
|
|
||
| # Case 2: XSS Payload | ||
| xss_data = {"group": {"group": "<script>alert(1)</script>"}} | ||
| assert main.validate_folder_data(xss_data, "http://evil.com") is False | ||
|
|
||
| # Case 3: Invalid Type | ||
| invalid_type_data = {"group": {"group": 123}} | ||
| assert main.validate_folder_data(invalid_type_data, "http://badtype.com") is False | ||
|
|
||
| # Case 4: Dangerous characters | ||
| dangerous_data = {"group": {"group": "Folder\"Name"}} | ||
| assert main.validate_folder_data(dangerous_data, "http://dangerous.com") is False | ||
|
|
||
| finally: | ||
| main.log = original_log |
There was a problem hiding this comment.
The test cases should include edge cases for whitespace handling since the actual code usage strips folder names with .strip(). Consider adding test cases for: folder names with leading/trailing whitespace (e.g., " Valid Name "), folder names that are only whitespace (e.g., " "), and folder names that become empty after stripping. These edge cases are important to verify that the validation properly handles the stripping behavior seen in the main code.
| # Case 2: XSS Payload | ||
| xss_data = {"group": {"group": "<script>alert(1)</script>"}} | ||
| assert main.validate_folder_data(xss_data, "http://evil.com") is False | ||
|
|
||
| # Case 3: Invalid Type | ||
| invalid_type_data = {"group": {"group": 123}} | ||
| assert main.validate_folder_data(invalid_type_data, "http://badtype.com") is False | ||
|
|
||
| # Case 4: Dangerous characters | ||
| dangerous_data = {"group": {"group": "Folder\"Name"}} | ||
| assert main.validate_folder_data(dangerous_data, "http://dangerous.com") is False |
There was a problem hiding this comment.
The test should verify additional XSS vectors and edge cases beyond the basic script tag. Consider adding tests for: HTML event handlers without script tags (e.g., "onload=alert(1)"), HTML entities (e.g., "<script>"), mixed case attempts (though these may not bypass the character check), and Unicode normalization attacks if applicable. Also consider testing the backtick character explicitly since it's in the dangerous_chars set but not tested.
| @@ -0,0 +1,32 @@ | |||
| import pytest | |||
There was a problem hiding this comment.
Import of 'pytest' is not used.
| import pytest |
🛡️ Sentinel: [HIGH] Fix XSS risk in folder names
Vulnerability:
The application parses folder names from external JSON files (
group.group) but failed to validate them against XSS payloads. While rules were validated, folder names were not, allowing a malicious list provider to inject Stored XSS via crafted folder names (e.g.,<script>alert(1)</script>).Fix:
is_valid_folder_namefunction to block dangerous characters (<,>,",', backtick) and ensure printability.validate_folder_datato enforce string type and applyis_valid_folder_namecheck on the folder name.tests/test_folder_validation.py.Verification:
Run
pytest tests/test_folder_validation.pyto verify that XSS payloads are now rejected (return False).Run
pytestto ensure no regressions.PR created automatically by Jules for task 2430422589834267156 started by @abhimehro