Python: Information-flow control based prompt injection defense (#5024)

* fides integration

* documentation

* documentation

* documentation

* human-approval on policy violation

* numenous hyena 'works'

* IFC based implementation

* minor edits in documentation

* rebasing the branch and running the email example

* Add security tests for IFC middleware

* Fix Role.TOOL NameError in approval handling

* tiered labelling scheme

* 3 tier labelling scheme in middleware

* Adapt security middleware to list[Content] tool results

* Refactor SecureAgentConfig as context provider and address Copilot review comments

* Update FIDES docs to reflect context provider pattern and update code for ContextProvider rename

* Fix security examples: use OpenAIChatClient instead of non-existent AzureOpenAIChatClient

* Address PR review: consolidate security modules, remove ContentLineage, update docs

* remove unrelated files

* remove comment from _tools.py and rename decision file

* Fix CI failures: Bandit B110, broken md links, hosted approval passthrough

* apply template to decision doc 0024

* minor fixes to decision doc 0024

---------

Co-authored-by: Aashish <t-akolluri@microsoft.com>
This commit is contained in:
shrutitople
2026-04-16 12:15:15 +01:00
committed by eavanvalkenburg
Unverified
parent 6582926af5
commit 8a08776a32
13 changed files with 9112 additions and 17 deletions
@@ -744,6 +744,12 @@ class AgentFrameworkExecutor:
)
continue
# Extract policy_violation info if present (from security middleware)
policy_violation_data = content_dict.get("policy_violation")
additional_props: dict[str, Any] | None = None
if isinstance(policy_violation_data, dict):
additional_props = {"policy_violation": True, **policy_violation_data}
# Reconstruct function_call from server-stored data
function_call = Content.from_function_call(
call_id=stored_fc["call_id"],
@@ -756,14 +762,16 @@ class AgentFrameworkExecutor:
approved,
id=request_id,
function_call=function_call,
additional_properties=additional_props,
)
contents.append(approval_response)
logger.info(
"Validated FunctionApprovalResponseContent: id=%s, "
"approved=%s, function=%s",
"approved=%s, function=%s, policy_violation=%s",
request_id,
approved,
stored_fc["name"],
additional_props is not None,
)
except ImportError:
logger.warning(
@@ -1744,7 +1744,7 @@ class MessageMapper:
# Fallback to direct access if parse_arguments doesn't exist
arguments = getattr(content.function_call, "arguments", {})
return {
result = {
"type": "response.function_approval.requested",
"request_id": getattr(content, "id", "unknown"),
"function_call": {
@@ -1756,6 +1756,18 @@ class MessageMapper:
"output_index": context["output_index"],
"sequence_number": self._next_sequence(context),
}
# Include policy violation details if present (from security middleware)
additional_props = getattr(content, "additional_properties", None)
if additional_props and isinstance(additional_props, dict):
if additional_props.get("policy_violation"):
result["policy_violation"] = {
"reason": additional_props.get("reason", "Policy violation detected"),
"violation_type": additional_props.get("violation_type"),
"context_label": additional_props.get("context_label"),
}
return result
async def _map_approval_response_content(self, content: Any, context: dict[str, Any]) -> dict[str, Any]:
"""Map FunctionApprovalResponseContent to custom event."""