From 1931bce82dd6f9d9b694466da30f5734e85cf111 Mon Sep 17 00:00:00 2001 From: Rohan Date: Sat, 3 Oct 2026 18:48:25 +0530 Subject: [PATCH] fix(guardrails): check Akto attachments in both messages and input --- .../guardrail_hooks/akto/akto_attachments.py | 7 +++---- .../akto/test_akto_attachments.py | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/litellm/proxy/guardrails/guardrail_hooks/akto/akto_attachments.py b/litellm/proxy/guardrails/guardrail_hooks/akto/akto_attachments.py index 6adb0839bfa..c0db27acdfc 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/akto/akto_attachments.py +++ b/litellm/proxy/guardrails/guardrail_hooks/akto/akto_attachments.py @@ -159,10 +159,9 @@ _UNSENDABLE: Final[_Classified] = (None, True) def request_attachments(request_data: Mapping[str, object]) -> RequestAttachments: - messages: Final = _parse(_ITEMS_ADAPTER, request_data.get("messages")) or _parse( - _ITEMS_ADAPTER, request_data.get("input") - ) - blocks: Final = chain.from_iterable(_message_blocks(message) for message in messages or ()) + # Both, so a decoy "messages" can't hide attachments in a Responses API "input" + containers: Final = (_parse(_ITEMS_ADAPTER, request_data.get(key)) or () for key in ("messages", "input")) + blocks: Final = chain.from_iterable(_message_blocks(message) for message in chain.from_iterable(containers)) classified: Final = tuple(_classify_block(block, index) for index, block in enumerate(blocks)) return RequestAttachments( attachments=tuple(attachment for attachment, _ in classified if attachment is not None), diff --git a/tests/unit/proxy/guardrails/guardrail_hooks/akto/test_akto_attachments.py b/tests/unit/proxy/guardrails/guardrail_hooks/akto/test_akto_attachments.py index 24abad55181..9e3766351c2 100644 --- a/tests/unit/proxy/guardrails/guardrail_hooks/akto/test_akto_attachments.py +++ b/tests/unit/proxy/guardrails/guardrail_hooks/akto/test_akto_attachments.py @@ -85,6 +85,22 @@ def test_request_attachments_reads_responses_api_input(): ) +def test_a_decoy_messages_list_does_not_hide_responses_api_input_attachments(): + request_data = { + "messages": [{"role": "user", "content": "hello"}], + "input": [ + { + "role": "user", + "content": [ + {"type": "input_file", "file_data": f"data:application/pdf;base64,{PDF_B64}", "filename": "r.pdf"} + ], + } + ], + } + + assert request_attachments(request_data).attachments == (Attachment("r.pdf", "file", content=PDF_B64),) + + def test_request_attachments_names_files_by_their_type(): request_data = { "messages": [