Skip to main content
Glama
test_security.py10.2 kB
"""Security tests for Gradle MCP server.""" import pytest from gradle_mcp.gradle import GradleWrapper class TestArgumentValidation: """Test suite for Gradle argument validation security.""" def test_safe_arguments_allowed(self): """Test that safe arguments from the allow-list are permitted.""" wrapper = GradleWrapper.__new__(GradleWrapper) # Test various safe arguments safe_args_examples = [ ['--info'], ['-i'], ['--debug', '--stacktrace'], ['-x', 'test'], ['--exclude-task', 'lint'], ['--parallel', '--max-workers', '4'], ['--max-workers=4'], ['--continue'], ['--dry-run'], ['--refresh-dependencies'], ['--no-build-cache'], ['--scan'], ] for args in safe_args_examples: # Should not raise any exception wrapper._validate_gradle_args(args) def test_dangerous_init_script_blocked(self): """Test that --init-script is blocked to prevent code execution.""" wrapper = GradleWrapper.__new__(GradleWrapper) # Test various forms of --init-script dangerous_args = [ ['--init-script', 'malicious.gradle'], ['--init-script=malicious.gradle'], ['-I', 'malicious.gradle'], ] for args in dangerous_args: with pytest.raises(ValueError, match="not allowed due to security concerns"): wrapper._validate_gradle_args(args) def test_dangerous_project_prop_blocked(self): """Test that -P/--project-prop is blocked.""" wrapper = GradleWrapper.__new__(GradleWrapper) dangerous_args = [ ['--project-prop', 'key=value'], ['--project-prop=key=value'], ['-P', 'key=value'], ['-Pkey=value'], ] for args in dangerous_args: with pytest.raises(ValueError, match="not allowed due to security concerns"): wrapper._validate_gradle_args(args) def test_dangerous_system_prop_blocked(self): """Test that -D is blocked.""" wrapper = GradleWrapper.__new__(GradleWrapper) dangerous_args = [ ['-D', 'prop=value'], ['-Dprop=value'], ['--system-prop', 'prop=value'], ] for args in dangerous_args: with pytest.raises(ValueError, match="not allowed due to security concerns"): wrapper._validate_gradle_args(args) def test_dangerous_settings_file_blocked(self): """Test that -c/--settings-file is blocked.""" wrapper = GradleWrapper.__new__(GradleWrapper) dangerous_args = [ ['--settings-file', 'malicious.gradle'], ['--settings-file=malicious.gradle'], ['-c', 'malicious.gradle'], ] for args in dangerous_args: with pytest.raises(ValueError, match="not allowed due to security concerns"): wrapper._validate_gradle_args(args) def test_dangerous_build_file_blocked(self): """Test that -b/--build-file is blocked.""" wrapper = GradleWrapper.__new__(GradleWrapper) dangerous_args = [ ['--build-file', 'malicious.gradle'], ['--build-file=malicious.gradle'], ['-b', 'malicious.gradle'], ] for args in dangerous_args: with pytest.raises(ValueError, match="not allowed due to security concerns"): wrapper._validate_gradle_args(args) def test_dangerous_gradle_user_home_blocked(self): """Test that -g/--gradle-user-home is blocked.""" wrapper = GradleWrapper.__new__(GradleWrapper) dangerous_args = [ ['--gradle-user-home', '/tmp/malicious'], ['--gradle-user-home=/tmp/malicious'], ['-g', '/tmp/malicious'], ] for args in dangerous_args: with pytest.raises(ValueError, match="not allowed due to security concerns"): wrapper._validate_gradle_args(args) def test_dangerous_project_dir_blocked(self): """Test that -p/--project-dir is blocked.""" wrapper = GradleWrapper.__new__(GradleWrapper) dangerous_args = [ ['--project-dir', '/tmp/malicious'], ['--project-dir=/tmp/malicious'], ['-p', '/tmp/malicious'], ] for args in dangerous_args: with pytest.raises(ValueError, match="not allowed due to security concerns"): wrapper._validate_gradle_args(args) def test_dangerous_include_build_blocked(self): """Test that --include-build is blocked.""" wrapper = GradleWrapper.__new__(GradleWrapper) dangerous_args = [ ['--include-build', '/tmp/malicious'], ['--include-build=/tmp/malicious'], ] for args in dangerous_args: with pytest.raises(ValueError, match="not allowed due to security concerns"): wrapper._validate_gradle_args(args) def test_dangerous_write_verification_metadata_blocked(self): """Test that --write-verification-metadata is blocked to prevent arbitrary file writes.""" wrapper = GradleWrapper.__new__(GradleWrapper) dangerous_args = [ ['--write-verification-metadata', 'sha256'], ['--write-verification-metadata', 'sha256', '--verification-metadata-file=/etc/passwd'], ] for args in dangerous_args: with pytest.raises(ValueError, match="not allowed due to security concerns"): wrapper._validate_gradle_args(args) def test_unknown_arguments_blocked(self): """Test that unknown/unlisted arguments are blocked by default.""" wrapper = GradleWrapper.__new__(GradleWrapper) unknown_args = [ ['--some-unknown-flag'], ['--random-option=value'], ['-z'], ] for args in unknown_args: with pytest.raises(ValueError, match="not in the allow-list"): wrapper._validate_gradle_args(args) def test_empty_args_allowed(self): """Test that empty or None args are handled correctly.""" wrapper = GradleWrapper.__new__(GradleWrapper) # Should not raise wrapper._validate_gradle_args(None) wrapper._validate_gradle_args([]) def test_mixed_safe_arguments(self): """Test combination of safe arguments.""" wrapper = GradleWrapper.__new__(GradleWrapper) # Complex but safe combination args = [ '--info', '--parallel', '--max-workers', '8', '-x', 'test', '--exclude-task', 'lint', '--continue', '--stacktrace', ] # Should not raise wrapper._validate_gradle_args(args) def test_safe_arg_followed_by_dangerous_blocked(self): """Test that dangerous args are blocked even when mixed with safe ones.""" wrapper = GradleWrapper.__new__(GradleWrapper) # Start with safe args, then add dangerous one args = ['--info', '--init-script', 'malicious.gradle'] with pytest.raises(ValueError, match="not allowed due to security concerns"): wrapper._validate_gradle_args(args) class TestCommandInjectionPrevention: """Test suite specifically for command injection attack prevention.""" def test_rce_via_init_script_prevented(self): """Test that the original RCE vector via --init-script is blocked.""" wrapper = GradleWrapper.__new__(GradleWrapper) # This was the original attack vector malicious_args = [ '--init-script', '/tmp/malicious.gradle' # Could contain arbitrary Groovy code ] with pytest.raises(ValueError, match="not allowed due to security concerns"): wrapper._validate_gradle_args(malicious_args) def test_rce_via_init_script_short_form_prevented(self): """Test that -I form is also blocked.""" wrapper = GradleWrapper.__new__(GradleWrapper) malicious_args = ['-I', '/tmp/evil.gradle'] with pytest.raises(ValueError, match="not allowed due to security concerns"): wrapper._validate_gradle_args(malicious_args) def test_property_injection_prevented(self): """Test that property injection attacks are prevented.""" wrapper = GradleWrapper.__new__(GradleWrapper) # Attacker trying to inject properties malicious_args = ['-P', 'systemProp.java.home=/tmp/malicious'] with pytest.raises(ValueError, match="not allowed due to security concerns"): wrapper._validate_gradle_args(malicious_args) def test_file_path_manipulation_prevented(self): """Test that file path manipulation is prevented.""" wrapper = GradleWrapper.__new__(GradleWrapper) # Various ways to manipulate file paths attacks = [ ['-b', '/etc/passwd'], ['-c', '/tmp/malicious.settings.gradle'], ['-g', '/tmp/malicious-gradle-home'], ['-p', '/tmp/other-project'], ] for attack in attacks: with pytest.raises(ValueError, match="not allowed due to security concerns"): wrapper._validate_gradle_args(attack) def test_arbitrary_file_write_prevented(self): """Test that arbitrary file write via --write-verification-metadata is prevented.""" wrapper = GradleWrapper.__new__(GradleWrapper) # Attacker trying to write to arbitrary locations attack = ['--write-verification-metadata', 'sha256'] with pytest.raises(ValueError, match="not allowed due to security concerns"): wrapper._validate_gradle_args(attack)

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jermeyyy/gradle-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server