Skip to content

[BREAKING] Python: Harden AG-UI trust boundaries - #9316

Merged
Eduard van Valkenburg (eavanvalkenburg) merged 7 commits into
mainfrom
agui-icm-triage
Oct 13, 2026
Merged

Eduard van Valkenburg (eavanvalkenburg) merged 7 commits into
mainfrom
agui-icm-triage

Conversation

@eavanvalkenburg

@eavanvalkenburg Eduard van Valkenburg (eavanvalkenburg) commented Oct 12, 2026 •

Copy link
Copy Markdown
Member

Motivation & Context

AG-UI accepts client-controlled thread state, protocol events, A2UI context, approval identities, and multimodal inputs across several server-authority boundaries. This change centralizes fail-closed handling at those boundaries so request data cannot select another workflow continuation, activate backend capabilities without opt-in, gain system-message authority, or expose sensitive payloads through default logging.

Description & Review Guide

  • What are the major changes?
    • Bind workflow checkpoints from both endpoint-owned and builder-owned stores to the AG-UI scope/thread owner, including filtered load/list/latest/delete operations and fail-closed cold resume.
    • Treat client Shared State and forwarded A2UI context as untrusted user data; require backend opt-in before forwardedProps.injectA2UITool can activate A2UI.
    • Replace delimiter-based scoped approval keys with an injective encoding.
    • Map AG-UI RUN_ERROR after an exposed local client-tool call to ResponseInvalidatedException, while preserving provider-independent call completion semantics without requiring TOOL_CALL_END.
    • Reject non-web/data multimodal request URI schemes and unresolved client-owned id/file media references, migrate unsupported media in backend-loaded legacy snapshots to inert placeholders, and remove tool/run and approval payloads from default INFO logging.
  • What is the impact of these changes?
    • Breaking changes and migration guidance:
      • Threaded workflow checkpoints: Existing checkpoints created without AG-UI owner metadata can no longer be resumed by a threaded or scoped request. Start a fresh workflow lineage to create an owner-bound checkpoint. Legacy unthreaded checkpoint resumes remain supported.
      • Automatic A2UI injection: forwardedProps.injectA2UITool is now only a per-request selection signal. The backend must explicitly enable the capability with a2ui_config={"inject_a2ui_tool": true}. Manual enable_a2ui(...) integrations are unchanged.
      • Multimodal request content: Fresh inbound request content now accepts only http, https, and data schemes or inline binary data. Unresolved client-owned id/file references are rejected. Applications using file, FTP, relative, custom schemes, or protocol-level binary identifiers must fetch and authorize that resource in application code and pass HTTPS, data, or inline content to AG-UI. Previously persisted Thread Snapshots remain usable: unsupported legacy media parts are replaced with inert placeholder text before hydration or provider replay and are removed when the thread is next persisted.
      • Shared State and A2UI prompt authority: Client-supplied state, catalogs, and context are now modelled as untrusted user data instead of system messages. Applications that relied on those values having system priority must move trusted instructions and policy into server-owned agent instructions or configuration.
    • Other observable changes:
      • Complete client-tool calls continue to follow the shared function-loop contract and do not require provider-specific TOOL_CALL_END or finish markers. If AG-UI emits RUN_ERROR after exposing a local tool call, the response is invalidated and the call is discarded.
      • Default INFO logs no longer include full tool/run events or approval payloads; payload-level diagnostics require explicit debug instrumentation.
      • Scoped approval-state keys change only in the process-local store and require no durable-state migration.
  • What do you want reviewers to focus on?
    • Checkpoint compatibility and ownership enforcement across endpoint and WorkflowBuilder storage.
    • The provider-independent ResponseInvalidatedException behavior for AG-UI RUN_ERROR.
    • The intentional A2UI and multimodal-input compatibility changes and their migration guidance.

Related Issue

N/A - private security remediation tracked through the restricted Microsoft security-response process. This public PR intentionally does not link the restricted tracking record or expose its details.

AI Assistance

  • No material AI assistance was used.
  • This is an AI-assisted contribution. I reviewed, understood, and verified all submitted content and accept responsibility for it.

AI assistance details: Implementation, tests, security-boundary analysis, documentation, and this PR description were AI-assisted.

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR follows the Contribution Guidelines
  • This PR links to an agreed issue with no competing open PR, or the Related Issue section documents an applicable exception (trivial change, repository automation, or private security process).
  • This is not a breaking change. If it is a breaking change, add the breaking change label (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.

Copilot AI balanced review requested due to automatic review settings October 12, 2026 13:40
@agent-framework-automation agent-framework-automation Bot added documentation Usage: [Issues, PRs], Target: documentation in the code base and learn docs python Usage: [Issues, PRs], Target: Python breaking change Usage: [PRs], Target: all PRs that introduce changes that are not backward compatible labels Oct 12, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Approval-key collisions, stale checkpoint ownership, incomplete A2UI gating, and sensitive INFO logging leave security issues unresolved.

6 open findings
What changed in this PR

Hardens Python AG-UI boundaries around client-controlled state, capabilities, approvals, checkpoints, and multimodal content.

Changes:

  • Enforces checkpoint ownership and safer approval identity scoping.
  • Treats state/A2UI context as untrusted and restricts capability activation and URI schemes.
  • Adds response invalidation handling and reduces sensitive INFO logging.
File Description
python/​packages/​ag-ui/​AGENTS.md Documents hardened security contracts.
agent_framework_ag_ui/​_workflow.py Adds owned checkpoint filtering.
agent_framework_ag_ui/​_message_adapters.py Validates URIs and reduces approval logging.
agent_framework_ag_ui/​_endpoint.py Removes event payloads from INFO logs.
agent_framework_ag_ui/​_client.py Handles invalidated client-tool calls.
agent_framework_ag_ui/​_approval_state.py Introduces length-prefixed approval keys.
agent_framework_ag_ui/​_agent_run.py Injects state as untrusted user data.
agent_framework_ag_ui/​_a2ui/​_factory.py Requires backend A2UI opt-in.
agent_framework_ag_ui/​_a2ui/​_agent.py Downgrades client context authority.
tests/​ag_ui/​test_run.py Updates state and approval tests.
tests/​ag_ui/​test_message_adapters.py Tests rejected URI schemes.
tests/​ag_ui/​test_endpoint.py Tests ownership and A2UI configuration.
tests/​ag_ui/​test_approval_state.py Tests approval-key validation.
tests/​ag_ui/​test_ag_ui_client.py Tests invalidation and marker-independent completion.
tests/​ag_ui/​test_a2ui.py Tests untrusted context and opt-in behavior.

🧠 Review effort: Balanced


💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment thread python/packages/ag-ui/agent_framework_ag_ui/_approval_state.py
Comment thread python/packages/ag-ui/agent_framework_ag_ui/_workflow.py Outdated
Comment thread python/packages/ag-ui/agent_framework_ag_ui/_a2ui/_factory.py
Comment thread python/packages/ag-ui/agent_framework_ag_ui/_message_adapters.py
Comment thread python/packages/ag-ui/tests/ag_ui/test_ag_ui_client.py
Comment thread python/packages/ag-ui/tests/ag_ui/test_ag_ui_client.py
@github-code-quality

github-code-quality Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: Python

Python / code-coverage/python

The overall line coverage in commit db74497 in the agui-icm-triage branch remains at 92%, unchanged from commit a70a727 in the main branch.

Show a line coverage summary of the most impacted files.
File main a70a727 agui-icm-triage db74497 +/-
packages/ag-ui/...2ui/_factory.py 100% 97% -3%
packages/ag-ui/...i/_agent_run.py 90% 90% 0%
packages/ag-ui/...ui/_workflow.py 95% 95% 0%
packages/ag-ui/..._a2ui/_agent.py 91% 91% 0%
packages/ag-ui/...g_ui/_client.py 93% 93% 0%
packages/ag-ui/...age_adapters.py 94% 94% 0%
packages/ag-ui/...shot_session.py 99% 99% 0%
packages/ag-ui/...proval_state.py 100% 100% 0%
packages/ag-ui/...ui/_endpoint.py 95% 96% +1%

Updated October 13, 2026 11:45 UTC

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAF Automated Review — Iteration 1

Result: Findings reported
Scope: full PR (2 commit(s)): 62e4c56b9170, 911089ad2ef8
Model: gpt-5.6-sol

Overview

The PR adds meaningful fail-closed checks for checkpoint ownership, backend A2UI opt-in, untrusted state/context roles, local-tool response invalidation, and multimodal URI schemes, with focused regression coverage. The approval-key encoding is still non-injective across its scoped and unscoped branches, and the URI restriction makes persisted threads containing previously accepted URI schemes fail on every later turn. Those residual issues leave one approval-state isolation gap and one upgrade-time availability regression.

Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
2 verified findings remained after source verification (1 high, 1 medium) across 2 files. Details are attached to the affected lines below.

Affected areas: python/packages/ag-ui/agent_framework_ag_ui/_approval_state.py, python/packages/ag-ui/agent_framework_ag_ui/_message_adapters.py

Comment thread python/packages/ag-ui/agent_framework_ag_ui/_approval_state.py
Comment thread python/packages/ag-ui/agent_framework_ag_ui/_message_adapters.py

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAF Automated Review — Iteration 2

Result: Findings reported
Scope: 2 net-new commit(s): 71ee9f05ec83, 8739953b17c1
Model: gpt-5.6-sol

Overview

This incremental update closes the prior approval-key, stale checkpoint-storage, optional A2UI import, logging, streaming, and legacy-media review gaps with focused guards and regression coverage. The new legacy-snapshot sanitizer deep-copies stored history and safely replaces ordinary unsupported schemes, but malformed URL authority syntax can still escape its parser and make an affected persisted thread unusable.

Reviewed the supplied incremental change set across correctness, security/reliability, architecture, and failure behavior.
1 verified finding remained after source verification (1 medium) across 1 file. Details are attached to the affected lines below.

Affected areas: python/packages/ag-ui/agent_framework_ag_ui/_message_adapters.py

Comment thread python/packages/ag-ui/agent_framework_ag_ui/_message_adapters.py Outdated

@jpalvarezl Jose Alvarez (jpalvarezl) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One security-boundary issue remains inline. Separately, this is a non-trivial breaking change, but ### Related Issue is only N/A while the checklist says the PR links an agreed issue or documents a valid exception. Please link the agreed tracking item, or document the applicable private-security/process exception without exposing sensitive details, and make the checklist match.

Comment thread python/packages/ag-ui/agent_framework_ag_ui/_message_adapters.py
@eavanvalkenburg

Copy link
Copy Markdown
Member Author

Jose Alvarez (@jpalvarezl) Thanks — both points are addressed. The multimodal boundary fix is in d02442390, with fresh-input rejection and legacy-snapshot migration coverage. I also updated ### Related Issue to document the restricted private-security process exception without exposing the tracking record, and aligned the checklist item with that exception.

…clean

# Conflicts:
#	python/packages/ag-ui/agent_framework_ag_ui/_workflow.py

@jpalvarezl Jose Alvarez (jpalvarezl) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed the current head. The unresolved id/file media-reference path now fails before constructing provider-facing URI content, legacy snapshots sanitize those references before replay, and the regression coverage includes fresh and persisted forms. No further substantive issues found.

Merged via the queue into main with commit 4a90089 Oct 13, 2026
50 checks passed

This branch was previously deployed

1 inactive deployment
github-app-auth — db74497a Deployed Oct 13, 2026 by eavanvalkenburg via add_label #25124
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking change Usage: [PRs], Target: all PRs that introduce changes that are not backward compatible documentation Usage: [Issues, PRs], Target: documentation in the code base and learn docs python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants