From 3d265a12d8a49d8b8539f4355192ec1bc2ffd612 Mon Sep 17 00:00:00 2001 From: deacon Date: Sun, 15 Mar 2026 13:21:21 -0400 Subject: [PATCH 1/3] fix: add magic-byte and extension validation to payload_api POST Block dangerous file types (PHP, JSP, ASPX) and restrict extensions. --- app/api/v2/handlers/payload_api.py | 32 +++++++++++++++++ tests/security/test_payload_validation.py | 43 +++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 tests/security/test_payload_validation.py diff --git a/app/api/v2/handlers/payload_api.py b/app/api/v2/handlers/payload_api.py index 1b034a332..28f62c5da 100644 --- a/app/api/v2/handlers/payload_api.py +++ b/app/api/v2/handlers/payload_api.py @@ -13,6 +13,31 @@ PayloadDeleteRequestSchema +ALLOWED_EXTENSIONS = [ + '.ps1', '.sh', '.py', '.exe', '.elf', '.bat', '.vbs', '.js', '.go', '.c', + '.zip', '.tar', '.gz', '.dll', '.bin', '.yaml', '.yml', '.txt', '.json', +] + +DANGEROUS_MAGIC_BYTES = [ + b' Date: Mon, 16 Mar 2026 00:55:24 -0400 Subject: [PATCH 2/3] fix: address Copilot review feedback on payload-magic-byte-validation - Convert ALLOWED_EXTENSIONS list to frozenset for O(1) lookup and immutability - Remove redundant b'<%@ Page' magic bytes entry (b'<%@' already covers it) - Sanitize filename before validation so extension/null-byte checks use the same name that will be used for storage, closing potential bypass gap - Remove sys.path.insert() from test file; import module directly - Remove __main__ runner block from test module - Add test confirming b'<%@ Page' is still rejected through b'<%@' prefix match --- app/api/v2/handlers/payload_api.py | 19 +++++++++++-------- tests/security/test_payload_validation.py | 18 ++++++------------ 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/app/api/v2/handlers/payload_api.py b/app/api/v2/handlers/payload_api.py index 28f62c5da..c579b9ebf 100644 --- a/app/api/v2/handlers/payload_api.py +++ b/app/api/v2/handlers/payload_api.py @@ -13,13 +13,14 @@ PayloadDeleteRequestSchema -ALLOWED_EXTENSIONS = [ +ALLOWED_EXTENSIONS = frozenset([ '.ps1', '.sh', '.py', '.exe', '.elf', '.bat', '.vbs', '.js', '.go', '.c', '.zip', '.tar', '.gz', '.dll', '.bin', '.yaml', '.yml', '.txt', '.json', -] +]) +# b'<%@ Page' is redundant because b'<%@' already matches it via startswith(). DANGEROUS_MAGIC_BYTES = [ - b' Date: Mon, 16 Mar 2026 09:58:20 -0400 Subject: [PATCH 3/3] Use case-insensitive assertion for magic byte error message The assertion was case-sensitive and coupled to exact capitalization of the error message. Use msg.lower() to make the test stable against formatting changes. --- tests/security/test_payload_validation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/security/test_payload_validation.py b/tests/security/test_payload_validation.py index 033f0e864..9b856ee13 100644 --- a/tests/security/test_payload_validation.py +++ b/tests/security/test_payload_validation.py @@ -16,7 +16,7 @@ def test_invalid_extension(self): def test_dangerous_magic_bytes_php(self): ok, msg = _validate_payload_file('test.txt', b'