DEV Community

correctover
correctover

Posted on • Originally published at correctover.github.io

CWE-636: The Silent Kill Switch in Every Major Agent Framework

CWE-636: The Silent Kill Switch in Every Major Agent Framework

How observer-pattern hooks create a systemic fail-open vulnerability that lets governance be bypassed — and what to do about it


The Vulnerability in One Paragraph

Every major AI agent framework — CrewAI, AutoGen, LangGraph, Microsoft Agent Governance Toolkit, Google ADK — uses the observer pattern (hooks) to implement governance, security checks, and policy enforcement. When a hook throws an exception, the framework's default behavior is to catch the exception and continue execution. This means: when your security check crashes, the tool runs anyway.

This is CWE-636: Not Failing Secure from Exceptional Conditions. It's not a bug in any single framework — it's an architectural flaw shared across the entire ecosystem.

CVSS 9.1 (Critical) | CWE-636 | CVE Pending (MSRC Coordinated Disclosure in Progress)


The Attack Pattern

Consider a typical agent tool execution flow with governance hooks:

Agent decides to call tool → Pre-execution hook fires → Hook checks policy
                                                          ↓
                                              Exception thrown
                                                          ↓
                                              Exception caught by framework
                                                          ↓
                                              hook_blocked = False
                                                          ↓
                                              Tool EXECUTES anyway ❌
Enter fullscreen mode Exit fullscreen mode

The critical failure mode: a governance system that fails open is indistinguishable from having no governance at all.

Concrete Example

# Typical framework governance hook (simplified)
def pre_tool_hook(tool_name, args, context):
    try:
        policy = load_governance_policy()
        if not policy.is_allowed(tool_name, args):
            return Block(reason="policy violation")
        return Allow()
    except Exception as e:
        logger.error(f"Governance check failed: {e}")
        return Allow()  # ← This is the vulnerability
Enter fullscreen mode Exit fullscreen mode

An attacker who can trigger an exception in the governance layer (e.g., by crafting tool arguments that cause a policy parser to crash) can bypass all security controls.

Attack Vectors

  1. Malformed tool arguments — Craft inputs that cause policy evaluation to throw
  2. Policy store failure — Trigger timeout in remote policy fetch → exception → allow
  3. Resource exhaustion — Memory/CPU pressure during governance check → crash → allow
  4. Dependency failure — Auth service down → governance can't authenticate → exception → allow

Scope: Who Is Affected?

We audited 6 major frameworks and found the same CWE-636 pattern in all of them:

Framework Governance Pattern Fail Behavior Severity
CrewAI Observer hooks Fail-open (allow) Critical
AutoGen Observer hooks Fail-open (allow) Critical
LangGraph Observer hooks Fail-open (allow) Critical
Microsoft AGT Toolkit Advisory hooks Fail-open (allow) High
Google ADK (MCP) Pre-execution hooks Fail-open (allow) Critical
Semantic Kernel Advisory hooks Fail-open (allow) High

Full audit reports with evidence:


Why This Happens: The Observer Pattern Trap

The observer pattern is the wrong abstraction for security-critical governance. Here's why:

Observer pattern semantics:

  • Observers are side effects — they observe state changes but don't control them
  • If an observer fails, the core flow continues (by design)
  • The framework owner controls whether the observer is "mandatory" or "advisory"

What governance actually needs:

  • Security checks are gates, not observations
  • A failed gate must block the flow (fail-closed)
  • The caller should not be able to proceed without passing the gate

This mismatch between what governance needs (interceptor/blocker semantics) and what hooks provide (observer/advisory semantics) is the root cause of CWE-636 across the ecosystem.


The Fix: Interceptor Architecture

The solution is not to patch each framework's hooks individually — it's to change the architectural layer at which governance operates.

CCS (Correctover Conformance Standard) Approach

Instead of observer hooks, CCS uses interceptor decorators that wrap tool functions at the code level:

# CCS interceptor pattern
from ccs import govern

@govern(policy="default")
def execute_payment(recipient, amount, currency):
    # Business logic — only runs if governance passes
    return process_payment(recipient, amount, currency)
Enter fullscreen mode Exit fullscreen mode

Why this is structurally different:

CCS Interceptor: tool_call → intercept → governance_check
                                          ↓
                                   Exception thrown
                                          ↓
                                   Exception caught by interceptor
                                          ↓
                                   tool NEVER CALLED ✅
Enter fullscreen mode Exit fullscreen mode

The interceptor wraps the function itself. If governance throws, the function body never executes. There is no "framework catches and continues" path because the interception happens inside the function call boundary, not in an external observer.

Key properties:

  • Fail-closed by construction: Exception → function not called. Period.
  • Framework-agnostic: Works with any Python framework (CrewAI, AutoGen, LangGraph, etc.)
  • Minimal overhead: P50 = 0.13µs, P99 = 0.22µs (validated benchmark)
  • No framework modifications needed: Decorator pattern, drop-in integration

The Bigger Picture

This isn't just about one vulnerability class. The MCP ecosystem is rapidly expanding — 78% of enterprise AI teams now have MCP-backed agents in production, with ~97 million monthly SDK downloads. Yet the security architecture underpinning agent governance remains fundamentally broken at the structural level.

The CISA Five Eyes alliance published the Agentic AI Security Adoption Guide in May 2026, highlighting exactly this class of governance failure as a top-priority risk for enterprise deployments.

The industry needs:

  1. Awareness: Framework users need to know their governance layer has a structural fail-open flaw
  2. Standards: A protocol-level specification for fail-closed governance (not ad-hoc patches)
  3. Tooling: Drop-in implementations that work across frameworks

CCS is our contribution to all three.


For Security Researchers

If you're auditing agent frameworks, here's what to look for:

  1. Check the hook execution path: Does the framework catch exceptions from governance hooks? If yes → fail-open.
  2. Check the default behavior: When a hook raises, does the tool execute? If yes → CWE-636.
  3. Check for "advisory" vs "mandatory" distinction: Advisory hooks are inherently fail-open by design.
  4. Verify with a crash test: Inject a hook that always throws. Can the tool still execute? If yes → confirmed.

We've published a reproduction methodology in our cross-framework audit.


Resources


Published: July 2026 | Author: Correctover | License: CC BY 4.0

Top comments (0)