From 6bfd1f04cc75f3cc74a82365231ee7db14aa9633 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 22 May 2026 16:55:58 +0000 Subject: [PATCH] fix(purview_dlp): fail closed when stream_chunk_builder returns None stream_chunk_builder can return None (e.g., when ChunkProcessor filters all chunks), causing both isinstance checks to fail and the buffered chunks to be released without DLP scanning. Explicitly fail closed in that case by raising an HTTPException so the streaming DLP guardrail does not bypass policy enforcement. Co-authored-by: Yassin Kortam --- .../microsoft_purview/purview_dlp.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/litellm/proxy/guardrails/guardrail_hooks/microsoft_purview/purview_dlp.py b/litellm/proxy/guardrails/guardrail_hooks/microsoft_purview/purview_dlp.py index 09a572c0a18..eeee76b731e 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/microsoft_purview/purview_dlp.py +++ b/litellm/proxy/guardrails/guardrail_hooks/microsoft_purview/purview_dlp.py @@ -402,6 +402,19 @@ class MicrosoftPurviewDLPGuardrail(PurviewGuardrailBase, CustomGuardrail): user_id = self._resolve_user_id_for_blocking(request_data, user_api_key_dict) + if assembled_response is None and all_chunks: + # Fail closed: stream_chunk_builder dropped all chunks, so we cannot + # scan the content. Refuse to release the buffered chunks. + raise HTTPException( + status_code=400, + detail={ + "error": ( + "Microsoft Purview DLP: Unable to assemble streamed " + "response for scanning; blocking response." + ), + }, + ) + if isinstance(assembled_response, TextCompletionResponse): parts = self._completion_response_text_parts(assembled_response) if parts: