Python: information-flow control prompt injection defense (#5331)

* 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>

* Python: follow up FIDES security flow (#5330)

* Python: follow up FIDES security flow

Refine the secure approval path, mark the security classes with the FIDES experimental feature label, and clean up the related docs/tests. Also fix workspace-level validation regressions uncovered while running the full Python check suite.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Python: remove FIDES GitHub MCP sample

Drop the GitHub MCP security sample from the FIDES follow-up branch while keeping the remaining security docs and samples intact.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address PR review: fix paths and update FIDES implementation (#5352)

* Python: updated import naming and comment from review (#5421)

* updated import naming and comment from review

* Add approval replay None call-id test

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Python: Address PR 5331 comments and track sesssion while calling Agent in email_security_example (#5446)

* Address PR review: fix paths and update FIDES implementation

* Address PR comments and add session tracking in email example in samples

* Fix session creation and resolve merge conflict in docstring example

* Resolve merge conflict in docstring example

* Python: add test for empty-message pruning in approval result replacement (#5617)

Adds test coverage for the second-pass logic in
`_replace_approval_contents_with_results` that removes messages whose
`contents` list becomes empty after first-pass content removal.

Addresses review comment on PR #5331:
https://github.com/microsoft/agent-framework/pull/5331#discussion_r3129039445

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: shrutitople <shruti.tople@gmail.com>
Co-authored-by: Aashish <t-akolluri@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Eduard van Valkenburg
2026-05-05 20:08:08 +02:00
committed by GitHub
Unverified
parent 806075ae61
commit ddfbdf5c7a
15 changed files with 7978 additions and 31 deletions
@@ -744,6 +744,15 @@ class AgentFrameworkExecutor:
)
continue
# Extract policy_violation info if present (from security middleware)
policy_violation_data = content_dict.get("policy_violation")
approval_additional_props: dict[str, Any] | None = None
if isinstance(policy_violation_data, dict):
approval_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 +765,16 @@ class AgentFrameworkExecutor:
approved,
id=request_id,
function_call=function_call,
additional_properties=approval_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"],
approval_additional_props is not None,
)
except ImportError:
logger.warning(
@@ -1747,7 +1747,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": {
@@ -1760,6 +1760,17 @@ class MessageMapper:
"sequence_number": self._next_sequence(context),
}
# Include policy violation details if present (from security middleware)
additional_props = cast(dict[str, Any] | None, getattr(content, "additional_properties", None))
if additional_props and isinstance(additional_props, dict) and 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."""
return {