Skip to content

Audit plugin mutations under CPEX hook payload policy enforcement #90

@lucarlig

Description

@lucarlig

Problem

CPEX now enforces hook payload mutation policies more strictly. For each hook, HOOK_PAYLOAD_POLICIES defines which top-level payload fields a plugin may change. Example: tool_post_invoke allows only result changes.

This enforcement is a useful guardrail, but it changes how plugin mutations are observed and merged. Plugins that mutate nested payload objects in-place, or that do not correctly handle CPEX copy-on-write isolation wrappers, can appear to make no allowed top-level change. In that case CPEX returns modified_payload=None or drops the effective update, and gateway continues with the original payload.

Concrete Example

PII filter exposed this on tool_post_invoke:

  • policy allows result
  • gateway result shape may be nested, e.g. result["content"][0]["text"]
  • CPEX wraps payload data for isolation when policy is active
  • PII scanning missed the wrapped mapping shape and returned no modified payload
  • gateway kept the original tool result, so masked content did not survive policy filtering

PR #89 fixes this for pii_filter by making the Rust scanner process Python mappings through the mapping protocol, and adds a regression test using real CPEX isolation + apply_policy().

Work Needed

Audit every plugin that mutates hook payloads under CPEX policy enforcement.

For each plugin/hook combination:

  • identify which payload fields the plugin intends to mutate
  • verify the hook has the expected writable fields in policy
  • verify nested mutations survive CPEX isolation and apply_policy()
  • prefer returning a new payload/new top-level field value rather than mutating nested structures in-place
  • add regression tests that exercise real CPEX policy filtering, not only direct plugin method calls

Hooks To Prioritize

  • tool_post_invoke, especially plugins rewriting nested result content
  • tool_pre_invoke, especially plugins rewriting nested args
  • prompt_post_fetch and resource_post_fetch, where result/content objects are often nested

Acceptance Criteria

  • all mutation-capable plugins have tests covering CPEX policy/isolation behavior
  • any plugin relying on in-place nested mutation is updated to return a policy-visible payload change
  • no plugin silently loses an allowed mutation when explicit hook policy is present
  • PR Fix PII result copy regression #89 covers the PII filter case; remaining plugins are tracked and fixed separately

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions