Skip to content

Python: fail closed when approval binding is unavailable (#8761) - #8780

Merged
Eduard van Valkenburg (eavanvalkenburg) merged 4 commits into
microsoft:mainfrom
leilei3167:fix/issue-8761-approval-fail-closed-22d6
Sep 28, 2026
Merged

Eduard van Valkenburg (eavanvalkenburg) merged 4 commits into
microsoft:mainfrom
leilei3167:fix/issue-8761-approval-fail-closed-22d6

Conversation

@leilei3167

Copy link
Copy Markdown
Contributor

Motivation & Context

When PolicyEnforcementFunctionMiddleware is configured with approval_on_violation=True, a detected policy violation must not execute if an approval binding cannot be established. If _pending_record fails and _block_unsafe_approval_binding does not terminate the middleware chain, the ladder falls through with binding is None and block_on_violation=False, reaching the permissive allow path.

Closes #8761

Description & Review Guide

  • What are the major changes?
    • Treat unresolved approval_on_violation flows as a block (same as block_on_violation) instead of logging (allowed) and calling call_next().
    • Add regression tests covering the legacy USER_IDENTITY source without principals plus a fail-closed test when approval binding construction is unsafe.
  • What is the impact of these changes?
    • Violating tool calls are blocked when approval cannot be requested or bound; safer default for approval_on_violation=True.
  • What do you want reviewers to focus on?
    • Whether blocking via _block_policy_violation is the right surface when approval binding fails, versus only raising from _block_unsafe_approval_binding.

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 is linked to an issue and there is no other open PR for this issue (see Related Issue above).
  • This is not a breaking change.

Evidence

  • Old red (without ladder fix, _block_unsafe_approval_binding no-op): pytest packages/core/tests/test_security.py::TestPolicyEnforcementMiddleware::test_approval_on_violation_fail_closed_when_binding_record_fails fails with tool execution allowed.
  • New green: pytest packages/core/tests/test_security.py::TestPolicyEnforcementMiddleware::test_legacy_user_identity_violation_with_approval_does_not_execute_tool packages/core/tests/test_security.py::TestPolicyEnforcementMiddleware::test_approval_on_violation_fail_closed_when_binding_record_fails

Fail closed when approval_on_violation is enabled but no approval binding
is available, instead of falling through to the permissive allow path.

Add regression tests for microsoft#8761.

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.

Copilot review overview

🟡 Changes recommended

The fallback can still be bypassed by an AttributeError when an unavailable binding is matched against an existing pending approval.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
What changed in this PR

Adds fail-closed handling when policy-violation approval binding cannot be established.

Changes:

  • Blocks unresolved approval flows instead of allowing tool execution.
  • Adds regression tests for unsafe and legacy identity bindings.
File Description
python/​packages/​core/​agent_framework/​security.py Adds approval-mode fallback blocking.
python/​packages/​core/​tests/​test_security.py Adds fail-closed regression coverage.

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

Only call _matches_pending_approval after _pending_record succeeds so a
mocked or non-terminating unsafe-binding handler cannot hit None binding.
If _block_unsafe_approval_binding returns despite its NoReturn
annotation, fail at the call site instead of continuing into the
policy ladder.
@leilei3167

Copy link
Copy Markdown
Contributor Author

Evan Mattson (@moonbox3) the call site now raises MiddlewareFailure if _block_unsafe_approval_binding() returns. Could you take another look at 5c54273 when you have a moment?

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.

leilei3167 Looks good to me.

Merged via the queue into microsoft:main with commit 20c4045 Sep 28, 2026
45 checks passed

This branch was previously deployed

1 inactive deployment
github-app-auth — 5c54273e Deployed Sep 28, 2026 by leilei3167 via add_label #23841
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: [Bug]: A confidentiality violation whose approval binding cannot be built is ALLOWED, not blocked, when approval_on_violation=True

4 participants