From 12757197c2c736fa77461e725636c9df84dd3bcc Mon Sep 17 00:00:00 2001 From: Bolor Date: Thu, 26 Mar 2026 13:48:45 -0700 Subject: [PATCH 1/3] fix for file names for media on disk --- pyrit/backend/services/attack_service.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pyrit/backend/services/attack_service.py b/pyrit/backend/services/attack_service.py index 16a8fb7047..28a7d60a2f 100644 --- a/pyrit/backend/services/attack_service.py +++ b/pyrit/backend/services/attack_service.py @@ -858,8 +858,13 @@ async def _persist_base64_pieces_async(request: AddMessageRequest) -> None: piece.converted_value = file_path continue - # Already an existing file on disk — keep as-is - if Path(piece.original_value).is_file(): + # Already an existing file on disk — keep as-is. + # Guard against base64 strings that would exceed OS path length limits. + try: + is_existing_file = len(piece.original_value) < 4096 and Path(piece.original_value).is_file() + except OSError: + is_existing_file = False + if is_existing_file: if piece.converted_value is None: piece.converted_value = piece.original_value continue From 2234c7291870ddbf30d230f0166c07349db4ddb4 Mon Sep 17 00:00:00 2001 From: jbolor21 <86250273+jbolor21@users.noreply.github.com> Date: Wed, 8 Apr 2026 13:31:16 -0700 Subject: [PATCH 2/3] add unit test --- tests/unit/backend/test_attack_service.py | 29 +++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/unit/backend/test_attack_service.py b/tests/unit/backend/test_attack_service.py index f3e2e91a0c..11da01effe 100644 --- a/tests/unit/backend/test_attack_service.py +++ b/tests/unit/backend/test_attack_service.py @@ -1596,6 +1596,35 @@ async def test_non_path_data_types_are_skipped(self, attack_service) -> None: assert request.pieces[0].original_value == "thinking step" + @pytest.mark.asyncio + async def test_long_base64_audio_does_not_crash(self, attack_service) -> None: + """Base64 audio data longer than OS path limits should be saved, not crash with OSError.""" + # Simulate a base64-encoded WAV file (>4096 chars, exceeds Linux filename limit of 255) + long_b64 = "UklGRiQ" + "A" * 5000 # fake WAV header + padding + request = AddMessageRequest( + role="user", + pieces=[ + MessagePieceRequest( + data_type="audio_path", + original_value=long_b64, + mime_type="audio/wav", + ) + ], + send=False, + target_conversation_id="test-id", + ) + + with patch("pyrit.backend.services.attack_service.data_serializer_factory") as mock_factory: + mock_serializer = AsyncMock() + mock_serializer.value = "/tmp/saved_audio.wav" + mock_factory.return_value = mock_serializer + + await AttackService._persist_base64_pieces_async(request) + + mock_factory.assert_called_once() + mock_serializer.save_b64_image.assert_called_once_with(data=long_b64) + assert request.pieces[0].original_value == "/tmp/saved_audio.wav" + # ============================================================================ # Related Conversations Tests From 2fda94d3952437340b4e307d5e6a94765fb5fc7f Mon Sep 17 00:00:00 2001 From: jbolor21 <86250273+jbolor21@users.noreply.github.com> Date: Thu, 9 Apr 2026 02:27:48 -0700 Subject: [PATCH 3/3] minor feedback --- pyrit/backend/services/attack_service.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/pyrit/backend/services/attack_service.py b/pyrit/backend/services/attack_service.py index 03b6d8a312..9437632392 100644 --- a/pyrit/backend/services/attack_service.py +++ b/pyrit/backend/services/attack_service.py @@ -871,15 +871,13 @@ async def _persist_base64_pieces_async(request: AddMessageRequest) -> None: continue # Already an existing file on disk — keep as-is. - # Guard against base64 strings that would exceed OS path length limits. try: - is_existing_file = len(piece.original_value) < 4096 and Path(piece.original_value).is_file() - except OSError: - is_existing_file = False - if is_existing_file: - if piece.converted_value is None: - piece.converted_value = piece.original_value - continue + if Path(piece.original_value).is_file(): + if piece.converted_value is None: + piece.converted_value = piece.original_value + continue + except (OSError, ValueError): + pass # Derive file extension from the MIME type sent by the frontend ext = None