Skip to content

Authorization denials produce no audit events on the proxy runner path #5871

Description

@JAORMX

Summary

On the proxy runner middleware chain (both the operator/proxyrunner path used by MCPServer/MCPRemoteProxy and the thv run CLI path), a request denied by the authorization middleware returns HTTP 403 correctly but produces no audit event. Audit trails miss exactly the events they most need to record: denied requests.

Root cause

Both middleware chain builders in pkg/runner append the audit middleware after the authorization middleware:

  • PopulateMiddlewareConfigs (pkg/runner/middleware.go) — operator / proxyrunner path
  • WithMiddlewareFromFlags (pkg/runner/config_builder.go) — CLI path

The proxies wrap handlers in reverse slice order (applyMiddlewares), so earlier entries are the outermost wrappers. The effective request-time order is:

auth → telemetry → authorization → audit

Audit runs inside authorization. When Cedar denies, the authz middleware writes the 403 and returns without calling the inner handler — the audit middleware never executes, so no event is emitted.

The audit middleware already classifies these outcomes correctly (determineOutcome maps 401/403 → denied); it just never runs for denials.

Expected

Every request that reaches the audit middleware's position in the chain should produce an audit event, including policy denials (outcome denied). This is how the vMCP Serve path already behaves after #5841: its pre-dispatch authorization gate runs inside the audit middleware, so denied calls are audited.

Reproduction

  1. Run any MCP server through the proxy with --authz-config (policy that denies a tool) and --audit-config.
  2. Call the denied tool directly via tools/call.
  3. Observe: HTTP 403 returned, but no audit event is written; allowed calls produce events normally.

Fix

Move the audit middleware before authorization in both chain builders so audit wraps authz, and pin the ordering with tests (unit ordering tests plus a full-chain integration test asserting a denied tools/call yields 403 and an audit event with outcome denied).

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-triageIssue needs initial triage by a maintainer

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions