Skip to content
Open
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
24 changes: 11 additions & 13 deletions backend/secuscan/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,19 +254,17 @@ def _verify_plugin_integrity(self, plugin: PluginMetadata, plugin_dir: Path) ->

if has_signature:
if not settings.plugin_signature_key:
if settings.enforce_plugin_signatures:
logger.error("SECUSCAN_PLUGIN_SIGNATURE_KEY required for verifying %s", plugin.id)
return False
logger.warning("Skipping signature verification for %s: key not configured", plugin.id)
else:
expected_sig = hmac.new(
settings.plugin_signature_key.encode("utf-8"),
combined_digest.encode("utf-8"),
hashlib.sha256,
).hexdigest()
if not hmac.compare_digest(expected_sig, plugin.signature):
logger.error("Signature mismatch for plugin %s", plugin.id)
return False
logger.error("SECUSCAN_PLUGIN_SIGNATURE_KEY required for verifying %s", plugin.id)
return False

expected_sig = hmac.new(
settings.plugin_signature_key.encode("utf-8"),
combined_digest.encode("utf-8"),
hashlib.sha256,
).hexdigest()
if not hmac.compare_digest(expected_sig, plugin.signature):
logger.error("Signature mismatch for plugin %s", plugin.id)
return False

return True

Expand Down
32 changes: 30 additions & 2 deletions testing/backend/unit/test_plugin_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -681,8 +681,6 @@ def test_integrity_check_fails_on_checksum_mismatch(self, tmp_path):
"""PluginManager._verify_plugin_integrity should return False if checksum mismatches."""
from backend.secuscan.plugins import PluginManager
from backend.secuscan.models import PluginMetadata

# 1. Create a valid metadata but with wrong checksum
data = _minimal_valid()
data["checksum"] = "b" * 64 # wrong checksum
data["presets"] = {}
Expand All @@ -696,6 +694,36 @@ def test_integrity_check_fails_on_checksum_mismatch(self, tmp_path):

assert mgr._verify_plugin_integrity(plugin, plugin_dir) is False

def test_declared_signature_requires_key_even_when_enforcement_off(self, tmp_path, monkeypatch):
"""A plugin with a signature must not load when the signing key is missing."""
from backend.secuscan.plugins import PluginManager
from backend.secuscan.config import settings
from backend.secuscan.models import PluginMetadata

monkeypatch.setattr(settings, "enforce_plugin_signatures", False)
monkeypatch.setattr(settings, "plugin_signature_key", None)

data = _minimal_valid()
data["presets"] = {}
for field in data["fields"]:
if field["type"] == "number":
field["type"] = "integer"

plugin_dir = _write_metadata(tmp_path, data)
metadata_file = plugin_dir / "metadata.json"
parser_file = plugin_dir / "parser.py"
parser_file.write_text("def parse(output):\n return {'findings': []}\n", encoding="utf-8")

digest = PluginManager.compute_plugin_digest(metadata_file, parser_file)
data["checksum"] = digest
data["signature"] = "a" * 64
metadata_file.write_text(json.dumps(data), encoding="utf-8")

plugin = PluginMetadata(**data)
mgr = PluginManager(plugins_dir=str(tmp_path))

assert mgr._verify_plugin_integrity(plugin, plugin_dir) is False

def test_sandbox_exec_fails_on_exec_statement(self):
"""Parser sandbox should raise ParserSandboxError when parser execution encounters exec()."""
from backend.secuscan.parser_sandbox import run_parser_in_sandbox, ParserSandboxError
Expand Down
Loading