Skip to content

🛡️ Sentinel: [HIGH] Fix XSS risk in folder names#134

Merged
abhimehro merged 1 commit intomainfrom
sentinel-folder-name-validation-2430422589834267156
Jan 27, 2026
Merged

🛡️ Sentinel: [HIGH] Fix XSS risk in folder names#134
abhimehro merged 1 commit intomainfrom
sentinel-folder-name-validation-2430422589834267156

Conversation

@google-labs-jules
Copy link

🛡️ 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:

  • Added is_valid_folder_name function to block dangerous characters (<, >, ", ', backtick) and ensure printability.
  • Updated validate_folder_data to enforce string type and apply is_valid_folder_name check on the folder name.
  • Added comprehensive tests in tests/test_folder_validation.py.

Verification:
Run pytest tests/test_folder_validation.py to verify that XSS payloads are now rejected (return False).
Run pytest to ensure no regressions.


PR created automatically by Jules for task 2430422589834267156 started by @abhimehro

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
@google-labs-jules
Copy link
Author

👋 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 @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@trunk-io
Copy link

trunk-io bot commented Jan 26, 2026

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

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

Use of assert detected. The enclosed code will be removed when compiling to optimised byte 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

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.

# 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

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

# 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

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
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

[no-undefined-references] Found reference to undefined definition
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

[no-shortcut-reference-link] Use the trailing [] on reference links
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

Use of assert detected. The enclosed code will be removed when compiling to optimised byte 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

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.

# 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

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

# 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

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
# 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

Use lazy % formatting in logging functions (logging-fstring-interpolation)
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

Use lazy % formatting in logging functions (logging-fstring-interpolation)
@@ -0,0 +1,32 @@
import pytest

Check warning

Code scanning / Prospector (reported by Codacy)

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

Unable to import 'pytest' (import-error)
@@ -0,0 +1,32 @@
import pytest

Check warning

Code scanning / Prospector (reported by Codacy)

Unused import pytest (unused-import) Warning test

Unused import pytest (unused-import)
@@ -0,0 +1,32 @@
import pytest

Check warning

Code scanning / Pylint (reported by Codacy)

Missing module docstring Warning test

Missing module docstring
@@ -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

standard import "from unittest.mock import MagicMock" should be placed before "import pytest"
@@ -0,0 +1,32 @@
import pytest

Check notice

Code scanning / Pylint (reported by Codacy)

Unused import pytest Note test

Unused import pytest
@@ -0,0 +1,32 @@
import pytest

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Missing module docstring Warning test

Missing module docstring
@@ -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

standard import "from unittest.mock import MagicMock" should be placed before "import pytest"
# 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

Use lazy % formatting in logging functions
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

Use lazy % formatting in logging functions
@@ -0,0 +1,32 @@
import pytest

Check notice

Code scanning / Pylintpython3 (reported by Codacy)

Unused import pytest Note test

Unused import pytest
@abhimehro abhimehro marked this pull request as ready for review January 27, 2026 07:30
Copilot AI review requested due to automatic review settings January 27, 2026 07:30
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

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_name function to validate folder names against XSS-dangerous characters
  • Updated validate_folder_data to 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.

Comment on lines +281 to +286
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):
Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

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

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.

Suggested change
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):

Copilot uses AI. Check for mistakes.
Comment on lines +5 to +32
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
Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
Comment on lines +19 to +29
# 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
Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,32 @@
import pytest
Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

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

Import of 'pytest' is not used.

Suggested change
import pytest

Copilot uses AI. Check for mistakes.
@abhimehro abhimehro merged commit 892db0f into main Jan 27, 2026
24 checks passed
@abhimehro abhimehro deleted the sentinel-folder-name-validation-2430422589834267156 branch January 27, 2026 12:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants