Skip to content

feat(policy): add exact external-extension and remote-MCP egress profiles with artifact-bound receipts #240

Description

@seonghobae

Problem

CWL is building a governed path for external Agent capabilities discovered through sources such as anthropics/claude-plugins-community. Noema #545 owns admission and activation, AppGuardrail #1099 owns static package findings, and quarantine-sandbox-runtime #17 owns credential-free dynamic analysis.

Extensions and MCP integrations can attempt arbitrary network access, fetch mutable code, contact model providers directly, send secrets/product data, or connect to undeclared remote services. A generic network: true flag is not an acceptable boundary. Noema needs an EgressWeave-owned policy decision and receipt tied to exact artifact, activation, destination and operation.

This repository owns outbound HTTP authority and evidence. It does not own extension admission/activation, package scanning, sandbox execution, model routing, local installation, product-domain truth, or formal merge/release decisions.

Required architectural decision

Evaluate and record the smallest canonical integration shape:

  1. Trusted-host library enforcement — the quarantine/runtime host uses the released EgressWeave package before any outbound socket can be opened;
  2. Independent egress gateway service — non-Python runtimes call a released EgressWeave policy/gateway API and have no direct network path;
  3. Network-disabled developer assist — where complete mediation cannot be proven, external plugins remain offline and remote MCP is unavailable;
  4. ADR exclusion — if a specific local client cannot route extension egress through a trustworthy boundary, mark that activation unsupported rather than documenting unenforceable policy.

Do not create a policy-only fiction while the extension can still open direct sockets outside EgressWeave.

Policy profile

Add a versioned external_extension_egress profile that binds at least:

egress_policy_id
policy_version
policy_sha256
external_extension_artifact_sha256
noema_activation_reference
purpose_code
allowed_destination_authorities
allowed_http_methods
allowed_path_templates
allowed_request_media_types
allowed_response_media_types
maximum_request_bytes
maximum_response_bytes
maximum_redirect_count
connect_timeout
read_timeout
write_timeout
pool_timeout
tls_policy_reference
dns_policy_reference
credential_handle_policy
request_field_policy
response_field_policy
valid_from
valid_to

allowed_destination_authorities use exact normalized scheme/host/port and explicit DNS/TLS identity. Wildcard domains, implicit default ports, redirects to undeclared authorities, user-info URLs, IP-literal surprises, Unix sockets, proxies, CONNECT tunnels and caller-controlled DNS are rejected unless separately modeled and justified.

Remote MCP profile

For HTTP/SSE/streamable remote MCP, require a bounded contract containing:

mcp_server_identity
mcp_protocol_version
transport_code
exact_origin
allowed_endpoint_paths
expected_server_identity
authentication_mode
allowed_secret_handle_references
tool_schema_digest
maximum_tool_count
maximum_request_bytes
maximum_response_bytes
maximum_stream_duration
allowed_content_types
retry_policy
cancellation_policy

The tool schema is untrusted input and cannot add destinations, secret handles, provider routes or capabilities. Schema drift creates a new observed candidate and suspends activation until rescanned/readmitted.

For stdio MCP, EgressWeave does not pretend to mediate process or filesystem authority; quarantine runtime #17 owns the process boundary. Any network from the stdio child still requires complete egress mediation or stays denied.

Explicit denials

Default external-extension policy rejects:

  • direct OPENAI_API_KEY, NVIDIA_NIM_API_KEY*, BYTEZ_API_KEY, OPENROUTER_API_KEY, provider endpoints, model discovery or fallback outside contextual-orchestrator;
  • GitHub API write/review/merge/release/deployment calls unless a separate product-owned least-privilege capability explicitly exists; developer-assist plugins receive none;
  • package registries, release assets, curl|wget, dynamic installers and executable downloads during normal activation;
  • arbitrary webhooks, paste sites, telemetry/analytics endpoints, URL shorteners, DNS-over-HTTPS, generic cloud metadata endpoints, localhost/host-gateway/private-network access and cross-tenant destinations;
  • cookies, raw tokens, prompts/responses, source files, product records, PII, secrets or unrestricted logs in request bodies/headers/query parameters;
  • redirects, DNS rebinding, certificate/hostname mismatch, response smuggling, oversized/compressed-bomb bodies and unsupported MIME;
  • plugin-controlled proxy, CA bundle, socket, resolver, timeout or retry settings.

A product-runtime adapter that legitimately needs an external provider uses its canonical product-owned port and secret handle. It does not inherit a Claude plugin's destination list.

Credential boundary

Raw secret values never enter Noema activation documents, AppGuardrail/quarantine receipts, plugin prompts, logs or caller-visible EgressWeave decisions. The trusted host resolves an approved opaque secret handle only for the exact destination/operation and injects it after model/plugin-visible request construction. Response and error surfaces must not reveal the credential, authorization header, signed URL, cookies or provider body.

Decision and execution receipts

Emit distinct bounded evidence:

policy_decision_receipt
- decision_id
- policy_id / policy_sha256
- activation_reference
- artifact_sha256
- destination_authority
- method
- normalized_path_class
- credential_handle_class
- decision_code
- denial_reason_code
- decided_at

execution_receipt
- decision_id
- request_digest
- response_digest
- response_status_class
- request_bytes
- response_bytes
- dns_identity_digest
- tls_identity_digest
- redirect_count
- timing_summary
- cancellation_or_timeout_class
- completed_at

Receipts contain no raw URL secrets, headers, cookies, request/response bodies, plugin text, product payload or hidden reasoning. Digests are not authorization by themselves.

TDD acceptance

RED/GREEN tests must cover at least:

  1. exact allowed origin/method/path/media/size succeeds through the real transport boundary;
  2. wildcard/mutable/implicit destination and undeclared port/path/method fail before network I/O;
  3. DNS rebinding, alternate address, private/loopback/link-local/metadata target and TLS mismatch;
  4. redirect to undeclared authority and redirect loops;
  5. direct model-provider and broad GitHub destination denial;
  6. package registry/dynamic executable download denial;
  7. remote MCP exact origin/schema digest positive path and schema drift suspension;
  8. secret-handle destination/operation mismatch and proof raw secret is absent from caller/log/receipt;
  9. oversized/compressed/malformed/unsupported-MIME response and bounded cleanup;
  10. timeout/cancellation/retry semantics without duplicate side effects;
  11. caller attempts to set proxy/resolver/CA/socket/timeout policy;
  12. sync/async or service/library parity for every supported execution path;
  13. response-extension/network-stream handles remain hidden;
  14. activation expiry/revocation/supersession invalidates future decisions;
  15. wrong artifact, wrong policy, replayed or forged receipt rejection;
  16. extension/plugin content cannot modify the policy or add a destination;
  17. complete mediation test proving direct socket bypass is impossible in the selected deployment shape;
  18. rollback removes the policy and leaves no residual route/credential/cache.

Use synthetic endpoints and credentials. Production statement/branch coverage and public docstrings remain 100%, with property/fuzz tests on authority/URL/header/MIME/receipt parsing and realistic integration tests.

Documentation and release

Update PRD/TRD/ARCHITECTURE/Context Map/Threat Model/SECURITY/OPERABILITY/TEST_STRATEGY/UML/ADR/CHANGELOG and docs/product-technical-gap-baseline.md alongside executable behavior. Record why the selected mediation shape is enforceable and why rejected alternatives were not.

Release acceptance requires exact protected source, wheel/service/image as applicable, SBOM, provenance, dependency/security evidence, real network isolation canaries, and compatible released Context Graph Contracts #27/Noema #545 references. Open PR heads and self-asserted policy files are not consumer authority.

Provide two canaries:

  1. quarantine-sandbox-runtime security: canonicalize hostname identity with IDNA #17 proves an external plugin network attempt is denied and recorded without credentials;
  2. one explicitly approved synthetic remote MCP endpoint succeeds only through the selected EgressWeave boundary and fails on origin/schema/activation drift.

Non-goals

  • no generic internet proxy for untrusted plugins;
  • no direct provider/model routing;
  • no local-client policy claim without complete mediation;
  • no plugin installation or package scanning;
  • no process/filesystem sandbox claim;
  • no authorization from a policy document alone;
  • no weakening existing DNS/TLS/response-boundary controls.

Related: ContextualWisdomLab/noema#545, ContextualWisdomLab/context-graph-contracts#27, ContextualWisdomLab/appguardrail#1099, ContextualWisdomLab/quarantine-sandbox-runtime#17, ContextualWisdomLab/macos_utility_packs#5, ContextualWisdomLab/.github#1795, ContextualWisdomLab/enterprise-architecture-core#45.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions