From d8a0f078b88d2a0c0f6ac8c69c0fea5da1f31eda Mon Sep 17 00:00:00 2001 From: Branden Bonaby Date: Tue, 11 Aug 2026 13:47:28 -0700 Subject: [PATCH 01/23] docs: document ProcessContainer proxy deployment Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 789939a6-ae1c-4fb7-9729-5988d3657e7b --- .../examples/0.8.0-schema.md | 74 ++++++++++++++++++- docs/process-container/networking.md | 16 ++++ 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/docs/process-container/examples/0.8.0-schema.md b/docs/process-container/examples/0.8.0-schema.md index 0b1217155..98b409e38 100644 --- a/docs/process-container/examples/0.8.0-schema.md +++ b/docs/process-container/examples/0.8.0-schema.md @@ -45,4 +45,76 @@ ProcessContainer requires `ingress.default: "allow"` for private-network communi Windows implements this with the bidirectional `privateNetworkClientServer` capability, so the setting also permits private-network server traffic. `egress.default: "deny"` continues to block direct internet traffic. -See [Process Container Networking Configuration](../networking.md) for Windows enforcement details. +Valid endpoints use `localhost`, `127.0.0.1`, or `[::1]` with an explicit +port. The proxy-specific `network` block above is required on ProcessContainer. + +The proxy must already be running. A packaged AppContainer proxy needs `privateNetworkClientServer`, `internetClient` +for external destinations, and inbound firewall authorization. + +### Minimal packaged-proxy manifest + +```xml + + + + + Agent Proxy + Contoso + Assets\Logo.png + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +Replace the identity, publisher, architecture, executable, display strings, +and logo. The publisher must match the signing certificate. `runFullTrust` is +required by the firewall extension; `TrustLevel="appContainer"` still runs the +proxy in an AppContainer. + +See [Process Container Networking Configuration](../networking.md) for Windows enforcement and firewall details. diff --git a/docs/process-container/networking.md b/docs/process-container/networking.md index 960344297..841624e89 100644 --- a/docs/process-container/networking.md +++ b/docs/process-container/networking.md @@ -102,6 +102,22 @@ The caller must: - keep it alive until the client exits; and - leave egress deny-default with no direct allow or deny rules. +#### Proxy identity and firewall authorization + +A packaged AppContainer proxy is recommended. Supported deployment options are: + +| Proxy deployment | `allowedProxyPeer` | Enforcement | +|---|---|---| +| Packaged AppContainer | Package family name | AppContainer isolation and package firewall rule | +| Unpackaged AppContainer | AppContainer profile name | AppContainer isolation and administrator firewall rule | + +The scoped peer rule and `privateNetworkClientServer` do not bypass Windows +Firewall's block-inbound-to-non-allowed-apps policy. A packaged proxy uses the package-owned firewall declaration shown +in the [schema 0.8 examples](examples/0.8.0-schema.md); a packaged AppContainer also needs AppContainer trust. An +unpackaged AppContainer proxy requires its installer or administrator to own the equivalent firewall rule. See +[CreateAppContainerProfile](https://learn.microsoft.com/windows/win32/api/userenv/nf-userenv-createappcontainerprofile) +for unpackaged profile creation. + ### Model 3: externally blocked (most restrictive) - **Capabilities:** none; no host or peer loopback exemptions. From 17adc4c8f1d90db1eab55bf5277795b7342de428 Mon Sep 17 00:00:00 2001 From: Branden Bonaby Date: Tue, 11 Aug 2026 15:26:56 -0700 Subject: [PATCH 02/23] docs: document packaged full-trust proxy Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 789939a6-ae1c-4fb7-9729-5988d3657e7b --- .../examples/0.8.0-schema.md | 33 ++++++------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/docs/process-container/examples/0.8.0-schema.md b/docs/process-container/examples/0.8.0-schema.md index 98b409e38..0001e0e96 100644 --- a/docs/process-container/examples/0.8.0-schema.md +++ b/docs/process-container/examples/0.8.0-schema.md @@ -51,7 +51,7 @@ port. The proxy-specific `network` block above is required on ProcessContainer. The proxy must already be running. A packaged AppContainer proxy needs `privateNetworkClientServer`, `internetClient` for external destinations, and inbound firewall authorization. -### Minimal packaged-proxy manifest +### Minimal packaged AppContainer proxy manifest ```xml @@ -62,11 +62,7 @@ for external destinations, and inbound firewall authorization. xmlns:desktop2="http://schemas.microsoft.com/appx/manifest/desktop/windows10/2" xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" IgnorableNamespaces="uap uap10 desktop2 rescap"> - + Agent Proxy Contoso @@ -76,10 +72,7 @@ for external destinations, and inbound firewall authorization. - + @@ -87,18 +80,11 @@ for external destinations, and inbound firewall authorization. - - + @@ -117,4 +103,5 @@ and logo. The publisher must match the signing certificate. `runFullTrust` is required by the firewall extension; `TrustLevel="appContainer"` still runs the proxy in an AppContainer. -See [Process Container Networking Configuration](../networking.md) for Windows enforcement and firewall details. +See [Proxy identity and firewall authorization](../networking.md#proxy-identity-and-firewall-authorization) +for Windows enforcement and firewall details. From 022ae9b9239c8cebc9f101b66bb2e484fc81be87 Mon Sep 17 00:00:00 2001 From: Branden Bonaby Date: Tue, 11 Aug 2026 17:17:21 -0700 Subject: [PATCH 03/23] docs: constrain packaged proxy listener Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 789939a6-ae1c-4fb7-9729-5988d3657e7b --- docs/process-container/examples/0.8.0-schema.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/process-container/examples/0.8.0-schema.md b/docs/process-container/examples/0.8.0-schema.md index 0001e0e96..8ddb5c9f3 100644 --- a/docs/process-container/examples/0.8.0-schema.md +++ b/docs/process-container/examples/0.8.0-schema.md @@ -49,7 +49,9 @@ Valid endpoints use `localhost`, `127.0.0.1`, or `[::1]` with an explicit port. The proxy-specific `network` block above is required on ProcessContainer. The proxy must already be running. A packaged AppContainer proxy needs `privateNetworkClientServer`, `internetClient` -for external destinations, and inbound firewall authorization. +for external destinations, and inbound firewall authorization. The proxy must bind its listener only to the configured +loopback address, never to wildcard addresses such as `0.0.0.0` or `[::]`; the loopback URL does not enforce the +listener binding. ### Minimal packaged AppContainer proxy manifest @@ -91,7 +93,8 @@ for external destinations, and inbound firewall authorization. - + @@ -101,7 +104,8 @@ for external destinations, and inbound firewall authorization. Replace the identity, publisher, architecture, executable, display strings, and logo. The publisher must match the signing certificate. `runFullTrust` is required by the firewall extension; `TrustLevel="appContainer"` still runs the -proxy in an AppContainer. +proxy in an AppContainer. Replace both firewall-rule port values with the port +from `runtimeConfig.networkProxy`. See [Proxy identity and firewall authorization](../networking.md#proxy-identity-and-firewall-authorization) for Windows enforcement and firewall details. From d050d787b2a0a876a79947d31b95c5b03574457e Mon Sep 17 00:00:00 2001 From: Branden Bonaby Date: Tue, 11 Aug 2026 19:17:25 -0700 Subject: [PATCH 04/23] docs: make packaged proxy example complete Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 789939a6-ae1c-4fb7-9729-5988d3657e7b --- .../examples/0.8.0-schema.md | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/docs/process-container/examples/0.8.0-schema.md b/docs/process-container/examples/0.8.0-schema.md index 8ddb5c9f3..6ea730f04 100644 --- a/docs/process-container/examples/0.8.0-schema.md +++ b/docs/process-container/examples/0.8.0-schema.md @@ -39,7 +39,7 @@ Package identity can scope a packaged proxy whether or not that proxy uses AppCo | Field | Value | |---|---| | `runtimeConfig.networkProxy` | HTTP/S loopback URL with an explicit port | -| `processContainer.network.allowedProxyPeer` | Package family name or AppContainer profile name | +| `processContainer.network.allowedProxyPeer` | Installed Package Family Name or AppContainer profile name | ProcessContainer requires `ingress.default: "allow"` for private-network communication with an identity-scoped proxy. Windows implements this with the bidirectional `privateNetworkClientServer` capability, so the setting also permits @@ -81,6 +81,14 @@ listener binding. + + + + + + + @@ -90,14 +98,6 @@ listener binding. AppListEntry="none" /> - - - - - - - ``` @@ -107,5 +107,17 @@ required by the firewall extension; `TrustLevel="appContainer"` still runs the proxy in an AppContainer. Replace both firewall-rule port values with the port from `runtimeConfig.networkProxy`. +After installing the package, retrieve its exact Package Family Name: + +```powershell +Get-AppxPackage -Name Contoso.AgentProxy | + Select-Object -ExpandProperty PackageFamilyName +``` + +Use that value verbatim for `allowedProxyPeer`. The Package Family Name is +derived from the manifest identity name and publisher; it is not the display +name or application ID. A bare profile name such as `agent-proxy` is valid +only for an unpackaged AppContainer proxy. + See [Proxy identity and firewall authorization](../networking.md#proxy-identity-and-firewall-authorization) for Windows enforcement and firewall details. From 4e0561a6213d5b0bac0c9999a1f9c5c56d560f2d Mon Sep 17 00:00:00 2001 From: Branden Bonaby Date: Tue, 11 Aug 2026 19:32:04 -0700 Subject: [PATCH 05/23] docs: clarify proxy listener ownership Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 789939a6-ae1c-4fb7-9729-5988d3657e7b --- .../examples/0.8.0-schema.md | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/docs/process-container/examples/0.8.0-schema.md b/docs/process-container/examples/0.8.0-schema.md index 6ea730f04..556329e98 100644 --- a/docs/process-container/examples/0.8.0-schema.md +++ b/docs/process-container/examples/0.8.0-schema.md @@ -48,10 +48,12 @@ private-network server traffic. `egress.default: "deny"` continues to block dire Valid endpoints use `localhost`, `127.0.0.1`, or `[::1]` with an explicit port. The proxy-specific `network` block above is required on ProcessContainer. -The proxy must already be running. A packaged AppContainer proxy needs `privateNetworkClientServer`, `internetClient` -for external destinations, and inbound firewall authorization. The proxy must bind its listener only to the configured -loopback address, never to wildcard addresses such as `0.0.0.0` or `[::]`; the loopback URL does not enforce the -listener binding. +The proxy must already be running and listening on the loopback address and +port configured by `runtimeConfig.networkProxy`. MXC validates that the +configured endpoint is loopback but does not constrain the proxy's other +listeners. A packaged AppContainer proxy needs `privateNetworkClientServer`, +`internetClient` for external destinations, and inbound firewall +authorization. ### Minimal packaged AppContainer proxy manifest @@ -84,8 +86,7 @@ listener binding. - + @@ -101,11 +102,17 @@ listener binding. ``` -Replace the identity, publisher, architecture, executable, display strings, -and logo. The publisher must match the signing certificate. `runFullTrust` is -required by the firewall extension; `TrustLevel="appContainer"` still runs the -proxy in an AppContainer. Replace both firewall-rule port values with the port -from `runtimeConfig.networkProxy`. +See the Microsoft Learn +[package manifest schema reference](https://learn.microsoft.com/uwp/schemas/appxpackage/uapmanifestschema/schema-root) +for package identity, signing, assets, and application metadata. +`runFullTrust` is required by the firewall extension; +`TrustLevel="appContainer"` still runs the proxy in an AppContainer. + +The firewall declaration intentionally does not restrict the local port. The +proxy may request an OS-assigned port, then provide the selected loopback +address and port to the caller for `runtimeConfig.networkProxy`. A proxy that +uses a fixed port can instead add matching `LocalPortMin` and `LocalPortMax` +values. After installing the package, retrieve its exact Package Family Name: From 5e2024156cd9972c983dea1eb017ae9a737b34fb Mon Sep 17 00:00:00 2001 From: Branden Bonaby <105318831+bbonaby@users.noreply.github.com> Date: Wed, 12 Aug 2026 18:11:58 -0700 Subject: [PATCH 06/23] Harden proxy firewall manifest guidance Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2449dac1-feb7-4da5-a249-9df137cc5360 --- .../examples/0.8.0-schema.md | 19 ++++++++----------- docs/process-container/networking.md | 5 +++-- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/docs/process-container/examples/0.8.0-schema.md b/docs/process-container/examples/0.8.0-schema.md index 556329e98..687e46364 100644 --- a/docs/process-container/examples/0.8.0-schema.md +++ b/docs/process-container/examples/0.8.0-schema.md @@ -49,11 +49,9 @@ Valid endpoints use `localhost`, `127.0.0.1`, or `[::1]` with an explicit port. The proxy-specific `network` block above is required on ProcessContainer. The proxy must already be running and listening on the loopback address and -port configured by `runtimeConfig.networkProxy`. MXC validates that the -configured endpoint is loopback but does not constrain the proxy's other -listeners. A packaged AppContainer proxy needs `privateNetworkClientServer`, -`internetClient` for external destinations, and inbound firewall -authorization. +port configured by `runtimeConfig.networkProxy`. MXC's schema 0.8 implementation must validate that the configured +endpoint is loopback. The proxy must bind only the configured loopback listener. A packaged AppContainer proxy needs +`privateNetworkClientServer`, `internetClient` for external destinations, and inbound firewall authorization. ### Minimal packaged AppContainer proxy manifest @@ -86,7 +84,8 @@ authorization. - + @@ -108,11 +107,9 @@ for package identity, signing, assets, and application metadata. `runFullTrust` is required by the firewall extension; `TrustLevel="appContainer"` still runs the proxy in an AppContainer. -The firewall declaration intentionally does not restrict the local port. The -proxy may request an OS-assigned port, then provide the selected loopback -address and port to the caller for `runtimeConfig.networkProxy`. A proxy that -uses a fixed port can instead add matching `LocalPortMin` and `LocalPortMax` -values. +The firewall declaration is scoped to the configured port. A deployment that uses a dynamic port must create or +update an equivalently executable- and port-scoped firewall rule before launching the client. Do not use an +unrestricted package firewall rule to accommodate an OS-assigned port. After installing the package, retrieve its exact Package Family Name: diff --git a/docs/process-container/networking.md b/docs/process-container/networking.md index 841624e89..927f211e1 100644 --- a/docs/process-container/networking.md +++ b/docs/process-container/networking.md @@ -113,8 +113,9 @@ A packaged AppContainer proxy is recommended. Supported deployment options are: The scoped peer rule and `privateNetworkClientServer` do not bypass Windows Firewall's block-inbound-to-non-allowed-apps policy. A packaged proxy uses the package-owned firewall declaration shown -in the [schema 0.8 examples](examples/0.8.0-schema.md); a packaged AppContainer also needs AppContainer trust. An -unpackaged AppContainer proxy requires its installer or administrator to own the equivalent firewall rule. See +in the [schema 0.8 examples](examples/0.8.0-schema.md); its application entry uses +`uap10:RuntimeBehavior="packagedClassicApp"` with `uap10:TrustLevel="appContainer"`. An unpackaged AppContainer proxy +requires its installer or administrator to own an equivalent rule scoped to the proxy executable and configured port. See [CreateAppContainerProfile](https://learn.microsoft.com/windows/win32/api/userenv/nf-userenv-createappcontainerprofile) for unpackaged profile creation. From ecd20fd99ff42bb28c1582190c8fb1b3ed699b21 Mon Sep 17 00:00:00 2001 From: Branden Bonaby <105318831+bbonaby@users.noreply.github.com> Date: Wed, 12 Aug 2026 18:52:03 -0700 Subject: [PATCH 07/23] Restore non-AppContainer proxy paths Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2449dac1-feb7-4da5-a249-9df137cc5360 --- docs/process-container/networking.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/process-container/networking.md b/docs/process-container/networking.md index 927f211e1..2bad04ff1 100644 --- a/docs/process-container/networking.md +++ b/docs/process-container/networking.md @@ -104,21 +104,28 @@ The caller must: #### Proxy identity and firewall authorization -A packaged AppContainer proxy is recommended. Supported deployment options are: +An AppContainer proxy is recommended. Supported deployment options are: | Proxy deployment | `allowedProxyPeer` | Enforcement | |---|---|---| | Packaged AppContainer | Package family name | AppContainer isolation and package firewall rule | | Unpackaged AppContainer | AppContainer profile name | AppContainer isolation and administrator firewall rule | +| Packaged non-AppContainer | Omit | Host-loopback access and package firewall rule | +| Unpackaged non-AppContainer | Omit | Host-loopback access and administrator firewall rule | The scoped peer rule and `privateNetworkClientServer` do not bypass Windows -Firewall's block-inbound-to-non-allowed-apps policy. A packaged proxy uses the package-owned firewall declaration shown -in the [schema 0.8 examples](examples/0.8.0-schema.md); its application entry uses +Firewall's block-inbound-to-non-allowed-apps policy. A packaged AppContainer proxy uses the package-owned firewall +declaration shown in the [schema 0.8 examples](examples/0.8.0-schema.md); its application entry uses `uap10:RuntimeBehavior="packagedClassicApp"` with `uap10:TrustLevel="appContainer"`. An unpackaged AppContainer proxy requires its installer or administrator to own an equivalent rule scoped to the proxy executable and configured port. See [CreateAppContainerProfile](https://learn.microsoft.com/windows/win32/api/userenv/nf-userenv-createappcontainerprofile) for unpackaged profile creation. +For a non-AppContainer proxy, omit `processContainer.network.allowedProxyPeer` and set +`ingress.hostLoopback: "allow"`. Packaged deployments can own the port-scoped firewall rule in the package; unpackaged +deployments require the installer or administrator to own it. These paths do not provide AppContainer isolation or +proxy-peer identity scoping and are intended primarily for development and debugging. + ### Model 3: externally blocked (most restrictive) - **Capabilities:** none; no host or peer loopback exemptions. From 89a3edc0d1f510963c01770fee4ea3808ff657a9 Mon Sep 17 00:00:00 2001 From: Branden Bonaby <105318831+bbonaby@users.noreply.github.com> Date: Wed, 12 Aug 2026 18:52:52 -0700 Subject: [PATCH 08/23] Restore non-AppContainer proxy example Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2449dac1-feb7-4da5-a249-9df137cc5360 --- docs/process-container/networking.md | 29 +++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/docs/process-container/networking.md b/docs/process-container/networking.md index 2bad04ff1..8c587b689 100644 --- a/docs/process-container/networking.md +++ b/docs/process-container/networking.md @@ -77,6 +77,30 @@ communication must set `ingress.default` to `"allow"` and accept that Windows en server behavior. On an enforcing BaseContainer path, per-container WFP permits the MXC client container to connect only to the configured loopback address and port and blocks direct public and private destinations. +#### Non-AppContainer proxy (explicit opt-in) + +Packaged and unpackaged non-AppContainer proxies use the host-loopback path instead of an identity-scoped peer: + +```jsonc +{ + "network": { + "egress": { "default": "deny" }, + "ingress": { + "default": "deny", + "hostLoopback": "allow" + } + }, + "runtimeConfig": { + "networkProxy": "http://127.0.0.1:8080" + } + // No processContainer.network.allowedProxyPeer. +} +``` + +MXC does not grant `privateNetworkClientServer` for this path. The proxy is not isolated or authorized by an +AppContainer identity, so it is intended primarily for development and debugging. Packaged deployments can own the +port-scoped firewall rule in the package; unpackaged deployments require an installer- or administrator-owned rule. + #### HTTP client guidance Code inside the ProcessContainer should use WinHTTP or an HTTP library that queries the system for proxy information. @@ -121,11 +145,6 @@ requires its installer or administrator to own an equivalent rule scoped to the [CreateAppContainerProfile](https://learn.microsoft.com/windows/win32/api/userenv/nf-userenv-createappcontainerprofile) for unpackaged profile creation. -For a non-AppContainer proxy, omit `processContainer.network.allowedProxyPeer` and set -`ingress.hostLoopback: "allow"`. Packaged deployments can own the port-scoped firewall rule in the package; unpackaged -deployments require the installer or administrator to own it. These paths do not provide AppContainer isolation or -proxy-peer identity scoping and are intended primarily for development and debugging. - ### Model 3: externally blocked (most restrictive) - **Capabilities:** none; no host or peer loopback exemptions. From 2634b5de2df4487d0aeade9f8f6a2dd268dc587a Mon Sep 17 00:00:00 2001 From: Branden Bonaby <105318831+bbonaby@users.noreply.github.com> Date: Wed, 12 Aug 2026 19:11:13 -0700 Subject: [PATCH 09/23] Clarify host-loopback proxy limitation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2449dac1-feb7-4da5-a249-9df137cc5360 --- docs/process-container/networking.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/process-container/networking.md b/docs/process-container/networking.md index 8c587b689..f9517f460 100644 --- a/docs/process-container/networking.md +++ b/docs/process-container/networking.md @@ -97,9 +97,11 @@ Packaged and unpackaged non-AppContainer proxies use the host-loopback path inst } ``` -MXC does not grant `privateNetworkClientServer` for this path. The proxy is not isolated or authorized by an -AppContainer identity, so it is intended primarily for development and debugging. Packaged deployments can own the -port-scoped firewall rule in the package; unpackaged deployments require an installer- or administrator-owned rule. +MXC does not grant `privateNetworkClientServer` for this path. `ingress.hostLoopback: "allow"` selects the Windows +loopback exemption, which is bidirectional and cannot be scoped to only the configured proxy endpoint. The proxy is not +isolated or authorized by an AppContainer identity, so this compatibility path is intended primarily for development +and debugging. Packaged deployments can own the port-scoped firewall rule in the package; unpackaged deployments +require an installer- or administrator-owned rule. #### HTTP client guidance From c87fa2e4fc040c2d60c462619f23b7cf6f3b2966 Mon Sep 17 00:00:00 2001 From: Branden Bonaby <105318831+bbonaby@users.noreply.github.com> Date: Wed, 12 Aug 2026 19:24:51 -0700 Subject: [PATCH 10/23] Clarify ProcessContainer proxy actors Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2449dac1-feb7-4da5-a249-9df137cc5360 --- docs/process-container/networking.md | 49 +++++++++++++++++++++------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/docs/process-container/networking.md b/docs/process-container/networking.md index f9517f460..c251d1b6a 100644 --- a/docs/process-container/networking.md +++ b/docs/process-container/networking.md @@ -77,17 +77,44 @@ communication must set `ingress.default` to `"allow"` and accept that Windows en server behavior. On an enforcing BaseContainer path, per-container WFP permits the MXC client container to connect only to the configured loopback address and port and blocks direct public and private destinations. -#### Non-AppContainer proxy (explicit opt-in) +#### Proxy deployment choices -Packaged and unpackaged non-AppContainer proxies use the host-loopback path instead of an identity-scoped peer: +Model 2 involves two separate processes: + +- **MXC client container:** the BaseContainer created by MXC, which runs the caller's workload and initiates HTTP/S + connections to the proxy. +- **Proxy process:** a caller-created process that is already running outside the MXC client container. It may run in an + AppContainer or without AppContainer isolation. + +| Proxy process | `allowedProxyPeer` | Client-container ingress | Proxy binding | +|---|---|---|---| +| AppContainer | Package family/profile | `default: "allow"`; `hostLoopback: "deny"` | Identity and endpoint | +| Non-AppContainer | Omit | `default: "allow"`; `hostLoopback: "deny"` | Endpoint only | + +Both deployments use `ingress.default: "allow"` because ProcessContainer uses it as the capability gate for +`privateNetworkClientServer`. This is a Windows capability requirement, not a statement that the proxy connection +enters the MXC client container; the client initiates that connection. The capability is bidirectional, so it also +permits private-network server traffic. + +`ingress.hostLoopback` retains its shared-policy meaning: host-initiated connections entering a listener in the MXC +client container. The proxy does not require that inbound path, so it remains `"deny"` for both deployments. + +#### Contained AppContainer proxy + +Use the canonical [ProcessContainer schema 0.8 configuration](examples/0.8.0-schema.md), which shows +`runtimeConfig.networkProxy`, `processContainer.network.allowedProxyPeer`, and their relationship in one place. + +#### Non-AppContainer proxy + +Packaged and unpackaged non-AppContainer proxies omit the AppContainer peer identity: ```jsonc { "network": { "egress": { "default": "deny" }, "ingress": { - "default": "deny", - "hostLoopback": "allow" + "default": "allow", + "hostLoopback": "deny" } }, "runtimeConfig": { @@ -97,11 +124,11 @@ Packaged and unpackaged non-AppContainer proxies use the host-loopback path inst } ``` -MXC does not grant `privateNetworkClientServer` for this path. `ingress.hostLoopback: "allow"` selects the Windows -loopback exemption, which is bidirectional and cannot be scoped to only the configured proxy endpoint. The proxy is not -isolated or authorized by an AppContainer identity, so this compatibility path is intended primarily for development -and debugging. Packaged deployments can own the port-scoped firewall rule in the package; unpackaged deployments -require an installer- or administrator-owned rule. +MXC grants the client container `privateNetworkClientServer` through `ingress.default: "allow"`, just as it does for an +AppContainer proxy. The difference is that MXC identifies the proxy only by the configured endpoint, not by an +AppContainer identity. This weaker option is intended primarily for development and debugging. Packaged deployments +can own the port-scoped firewall rule in the package; unpackaged deployments require an installer- or +administrator-owned rule. #### HTTP client guidance @@ -136,8 +163,8 @@ An AppContainer proxy is recommended. Supported deployment options are: |---|---|---| | Packaged AppContainer | Package family name | AppContainer isolation and package firewall rule | | Unpackaged AppContainer | AppContainer profile name | AppContainer isolation and administrator firewall rule | -| Packaged non-AppContainer | Omit | Host-loopback access and package firewall rule | -| Unpackaged non-AppContainer | Omit | Host-loopback access and administrator firewall rule | +| Packaged non-AppContainer | Omit | Endpoint-only binding and package firewall rule | +| Unpackaged non-AppContainer | Omit | Endpoint-only binding and administrator firewall rule | The scoped peer rule and `privateNetworkClientServer` do not bypass Windows Firewall's block-inbound-to-non-allowed-apps policy. A packaged AppContainer proxy uses the package-owned firewall From e9fb9ff14e78680f1d2fe90140c06b6ece7dc0dd Mon Sep 17 00:00:00 2001 From: Branden Bonaby <105318831+bbonaby@users.noreply.github.com> Date: Wed, 12 Aug 2026 19:31:14 -0700 Subject: [PATCH 11/23] Align proxy paths with bidirectional loopback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2449dac1-feb7-4da5-a249-9df137cc5360 --- docs/process-container/networking.md | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/docs/process-container/networking.md b/docs/process-container/networking.md index c251d1b6a..dc64744b1 100644 --- a/docs/process-container/networking.md +++ b/docs/process-container/networking.md @@ -86,18 +86,20 @@ Model 2 involves two separate processes: - **Proxy process:** a caller-created process that is already running outside the MXC client container. It may run in an AppContainer or without AppContainer isolation. -| Proxy process | `allowedProxyPeer` | Client-container ingress | Proxy binding | +| External proxy | `allowedProxyPeer` | MXC client policy | Proxy binding | |---|---|---|---| | AppContainer | Package family/profile | `default: "allow"`; `hostLoopback: "deny"` | Identity and endpoint | -| Non-AppContainer | Omit | `default: "allow"`; `hostLoopback: "deny"` | Endpoint only | +| Non-AppContainer | Omit | `default: "allow"`; `hostLoopback: "allow"` | Host loopback and endpoint | Both deployments use `ingress.default: "allow"` because ProcessContainer uses it as the capability gate for `privateNetworkClientServer`. This is a Windows capability requirement, not a statement that the proxy connection enters the MXC client container; the client initiates that connection. The capability is bidirectional, so it also permits private-network server traffic. -`ingress.hostLoopback` retains its shared-policy meaning: host-initiated connections entering a listener in the MXC -client container. The proxy does not require that inbound path, so it remains `"deny"` for both deployments. +`ingress.hostLoopback` is bidirectional. `allowedProxyPeer` authorizes the AppContainer peer without opening general +host-loopback access, so that path keeps `hostLoopback: "deny"`. A non-AppContainer proxy has no peer identity, so its +endpoint requires `hostLoopback: "allow"`. That also permits the MXC client container to reach other host-loopback +services and permits host-loopback clients to reach listeners in the MXC client container. #### Contained AppContainer proxy @@ -114,7 +116,7 @@ Packaged and unpackaged non-AppContainer proxies omit the AppContainer peer iden "egress": { "default": "deny" }, "ingress": { "default": "allow", - "hostLoopback": "deny" + "hostLoopback": "allow" } }, "runtimeConfig": { @@ -126,9 +128,9 @@ Packaged and unpackaged non-AppContainer proxies omit the AppContainer peer iden MXC grants the client container `privateNetworkClientServer` through `ingress.default: "allow"`, just as it does for an AppContainer proxy. The difference is that MXC identifies the proxy only by the configured endpoint, not by an -AppContainer identity. This weaker option is intended primarily for development and debugging. Packaged deployments -can own the port-scoped firewall rule in the package; unpackaged deployments require an installer- or -administrator-owned rule. +AppContainer identity, and enables bidirectional host-loopback access. This weaker option is intended primarily for +development and debugging. Packaged deployments can own the port-scoped firewall rule in the package; unpackaged +deployments require an installer- or administrator-owned rule. #### HTTP client guidance @@ -148,6 +150,12 @@ apply when `runtimeConfig.networkProxy` is present. The proxy endpoint is runtime metadata, not shared network policy. MXC configures the per-container WinHTTP proxy, applies WFP endpoint scoping, and grants the private-network capability selected by `ingress.default`. +The two proxy identity paths are mutually exclusive. When +`allowedProxyPeer` is present, MXC resolves the peer and grants the private-network capability selected by +`ingress.default`. When it is omitted, MXC uses the configured proxy endpoint without binding that endpoint to an +AppContainer identity and requires bidirectional host-loopback access. MXC configures the per-container WinHTTP proxy +for either path. + The caller must: - create and authorize the proxy; @@ -163,8 +171,8 @@ An AppContainer proxy is recommended. Supported deployment options are: |---|---|---| | Packaged AppContainer | Package family name | AppContainer isolation and package firewall rule | | Unpackaged AppContainer | AppContainer profile name | AppContainer isolation and administrator firewall rule | -| Packaged non-AppContainer | Omit | Endpoint-only binding and package firewall rule | -| Unpackaged non-AppContainer | Omit | Endpoint-only binding and administrator firewall rule | +| Packaged non-AppContainer | Omit | Host-loopback access and package firewall rule | +| Unpackaged non-AppContainer | Omit | Host-loopback access and administrator firewall rule | The scoped peer rule and `privateNetworkClientServer` do not bypass Windows Firewall's block-inbound-to-non-allowed-apps policy. A packaged AppContainer proxy uses the package-owned firewall From 0601b1d4f1e41f118d4e3fbb2e074e71b43a19ef Mon Sep 17 00:00:00 2001 From: Branden Bonaby <105318831+bbonaby@users.noreply.github.com> Date: Wed, 12 Aug 2026 19:32:39 -0700 Subject: [PATCH 12/23] Key proxy binding by package identity Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2449dac1-feb7-4da5-a249-9df137cc5360 --- .../examples/0.8.0-schema.md | 7 ++- docs/process-container/networking.md | 47 ++++++++++--------- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/docs/process-container/examples/0.8.0-schema.md b/docs/process-container/examples/0.8.0-schema.md index 687e46364..1367851ad 100644 --- a/docs/process-container/examples/0.8.0-schema.md +++ b/docs/process-container/examples/0.8.0-schema.md @@ -118,10 +118,9 @@ Get-AppxPackage -Name Contoso.AgentProxy | Select-Object -ExpandProperty PackageFamilyName ``` -Use that value verbatim for `allowedProxyPeer`. The Package Family Name is -derived from the manifest identity name and publisher; it is not the display -name or application ID. A bare profile name such as `agent-proxy` is valid -only for an unpackaged AppContainer proxy. +Use that value verbatim for `allowedProxyPeer` for any packaged proxy. The Package Family Name is derived from the +manifest identity name and publisher; it is not the display name or application ID. A bare profile name such as +`agent-proxy` is valid only for an unpackaged AppContainer proxy. See [Proxy identity and firewall authorization](../networking.md#proxy-identity-and-firewall-authorization) for Windows enforcement and firewall details. diff --git a/docs/process-container/networking.md b/docs/process-container/networking.md index dc64744b1..ea85c59d5 100644 --- a/docs/process-container/networking.md +++ b/docs/process-container/networking.md @@ -83,32 +83,36 @@ Model 2 involves two separate processes: - **MXC client container:** the BaseContainer created by MXC, which runs the caller's workload and initiates HTTP/S connections to the proxy. -- **Proxy process:** a caller-created process that is already running outside the MXC client container. It may run in an - AppContainer or without AppContainer isolation. +- **Proxy process:** a caller-created process that is already running outside the MXC client container. It may be + packaged or unpackaged, with or without AppContainer isolation. | External proxy | `allowedProxyPeer` | MXC client policy | Proxy binding | |---|---|---|---| -| AppContainer | Package family/profile | `default: "allow"`; `hostLoopback: "deny"` | Identity and endpoint | -| Non-AppContainer | Omit | `default: "allow"`; `hostLoopback: "allow"` | Host loopback and endpoint | +| Packaged proxy | PFN | `default: "allow"`; `hostLoopback: "deny"` | Identity and endpoint | +| Unpackaged AppContainer | Profile | `default: "allow"`; `hostLoopback: "deny"` | Identity and endpoint | +| Unpackaged non-AppContainer | Omit | `default: "allow"`; `hostLoopback: "allow"` | Host loopback and endpoint | -Both deployments use `ingress.default: "allow"` because ProcessContainer uses it as the capability gate for +All deployments use `ingress.default: "allow"` because ProcessContainer uses it as the capability gate for `privateNetworkClientServer`. This is a Windows capability requirement, not a statement that the proxy connection enters the MXC client container; the client initiates that connection. The capability is bidirectional, so it also permits private-network server traffic. -`ingress.hostLoopback` is bidirectional. `allowedProxyPeer` authorizes the AppContainer peer without opening general -host-loopback access, so that path keeps `hostLoopback: "deny"`. A non-AppContainer proxy has no peer identity, so its -endpoint requires `hostLoopback: "allow"`. That also permits the MXC client container to reach other host-loopback -services and permits host-loopback clients to reach listeners in the MXC client container. +`ingress.hostLoopback` is bidirectional. `allowedProxyPeer` authorizes a package family or AppContainer profile without +opening general host-loopback access, so identity-scoped paths keep `hostLoopback: "deny"`. Only an unpackaged +non-AppContainer proxy lacks an accepted peer identity and requires `hostLoopback: "allow"`. That also permits the MXC +client container to reach other host-loopback services and permits host-loopback clients to reach listeners in the MXC +client container. -#### Contained AppContainer proxy +#### Identity-scoped proxy Use the canonical [ProcessContainer schema 0.8 configuration](examples/0.8.0-schema.md), which shows `runtimeConfig.networkProxy`, `processContainer.network.allowedProxyPeer`, and their relationship in one place. +Use the installed Package Family Name for a packaged proxy, regardless of whether it has AppContainer isolation. Use +the AppContainer profile name for an unpackaged AppContainer proxy. -#### Non-AppContainer proxy +#### Unpackaged non-AppContainer proxy -Packaged and unpackaged non-AppContainer proxies omit the AppContainer peer identity: +An unpackaged non-AppContainer proxy has no package family or AppContainer profile identity: ```jsonc { @@ -127,10 +131,9 @@ Packaged and unpackaged non-AppContainer proxies omit the AppContainer peer iden ``` MXC grants the client container `privateNetworkClientServer` through `ingress.default: "allow"`, just as it does for an -AppContainer proxy. The difference is that MXC identifies the proxy only by the configured endpoint, not by an -AppContainer identity, and enables bidirectional host-loopback access. This weaker option is intended primarily for -development and debugging. Packaged deployments can own the port-scoped firewall rule in the package; unpackaged -deployments require an installer- or administrator-owned rule. +identity-scoped proxy. The difference is that MXC identifies this proxy only by the configured endpoint and enables +bidirectional host-loopback access. This weaker option is intended primarily for development and debugging and requires +an installer- or administrator-owned firewall rule. #### HTTP client guidance @@ -150,11 +153,11 @@ apply when `runtimeConfig.networkProxy` is present. The proxy endpoint is runtime metadata, not shared network policy. MXC configures the per-container WinHTTP proxy, applies WFP endpoint scoping, and grants the private-network capability selected by `ingress.default`. -The two proxy identity paths are mutually exclusive. When -`allowedProxyPeer` is present, MXC resolves the peer and grants the private-network capability selected by -`ingress.default`. When it is omitted, MXC uses the configured proxy endpoint without binding that endpoint to an -AppContainer identity and requires bidirectional host-loopback access. MXC configures the per-container WinHTTP proxy -for either path. +The identity-scoped and host-loopback paths are +mutually exclusive. When `allowedProxyPeer` is present, MXC resolves the package family or AppContainer profile and +grants the private-network capability selected by `ingress.default`. When it is omitted, MXC uses the configured proxy +endpoint without peer identity binding and requires bidirectional host-loopback access. MXC configures the per-container +WinHTTP proxy for either path. The caller must: @@ -171,7 +174,7 @@ An AppContainer proxy is recommended. Supported deployment options are: |---|---|---| | Packaged AppContainer | Package family name | AppContainer isolation and package firewall rule | | Unpackaged AppContainer | AppContainer profile name | AppContainer isolation and administrator firewall rule | -| Packaged non-AppContainer | Omit | Host-loopback access and package firewall rule | +| Packaged non-AppContainer | Package family name | Package identity and package firewall rule | | Unpackaged non-AppContainer | Omit | Host-loopback access and administrator firewall rule | The scoped peer rule and `privateNetworkClientServer` do not bypass Windows From 40802d8248a4c6164b0b4fd2f7b84728a56863f6 Mon Sep 17 00:00:00 2001 From: Branden Bonaby <105318831+bbonaby@users.noreply.github.com> Date: Wed, 12 Aug 2026 19:33:39 -0700 Subject: [PATCH 13/23] Document lowest-enforcement proxy option Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2449dac1-feb7-4da5-a249-9df137cc5360 --- docs/process-container/networking.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/process-container/networking.md b/docs/process-container/networking.md index ea85c59d5..5ccb93489 100644 --- a/docs/process-container/networking.md +++ b/docs/process-container/networking.md @@ -132,8 +132,10 @@ An unpackaged non-AppContainer proxy has no package family or AppContainer profi MXC grants the client container `privateNetworkClientServer` through `ingress.default: "allow"`, just as it does for an identity-scoped proxy. The difference is that MXC identifies this proxy only by the configured endpoint and enables -bidirectional host-loopback access. This weaker option is intended primarily for development and debugging and requires -an installer- or administrator-owned firewall rule. +bidirectional host-loopback access. This is the lowest-enforcement deployment option. On an enforcing BaseContainer +path, WFP still restricts the MXC client container's egress to the configured loopback address and port, but Windows +cannot verify which host process owns that endpoint. It is intended primarily for development and debugging and +requires an installer- or administrator-owned firewall rule. #### HTTP client guidance @@ -175,7 +177,7 @@ An AppContainer proxy is recommended. Supported deployment options are: | Packaged AppContainer | Package family name | AppContainer isolation and package firewall rule | | Unpackaged AppContainer | AppContainer profile name | AppContainer isolation and administrator firewall rule | | Packaged non-AppContainer | Package family name | Package identity and package firewall rule | -| Unpackaged non-AppContainer | Omit | Host-loopback access and administrator firewall rule | +| Unpackaged non-AppContainer | Omit | Endpoint-only WFP and administrator firewall rule | The scoped peer rule and `privateNetworkClientServer` do not bypass Windows Firewall's block-inbound-to-non-allowed-apps policy. A packaged AppContainer proxy uses the package-owned firewall From a1e2f6dd3e6159c7e55ae9379034dcd161bfab94 Mon Sep 17 00:00:00 2001 From: Branden Bonaby <105318831+bbonaby@users.noreply.github.com> Date: Wed, 12 Aug 2026 20:56:44 -0700 Subject: [PATCH 14/23] Rank proxy deployment enforcement Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2449dac1-feb7-4da5-a249-9df137cc5360 --- docs/process-container/networking.md | 30 ++++++++++++++++------------ 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/docs/process-container/networking.md b/docs/process-container/networking.md index 5ccb93489..80486ddd6 100644 --- a/docs/process-container/networking.md +++ b/docs/process-container/networking.md @@ -86,11 +86,15 @@ Model 2 involves two separate processes: - **Proxy process:** a caller-created process that is already running outside the MXC client container. It may be packaged or unpackaged, with or without AppContainer isolation. -| External proxy | `allowedProxyPeer` | MXC client policy | Proxy binding | +| External proxy | `allowedProxyPeer` | MXC client policy | Additional proxy identity | |---|---|---|---| -| Packaged proxy | PFN | `default: "allow"`; `hostLoopback: "deny"` | Identity and endpoint | -| Unpackaged AppContainer | Profile | `default: "allow"`; `hostLoopback: "deny"` | Identity and endpoint | -| Unpackaged non-AppContainer | Omit | `default: "allow"`; `hostLoopback: "allow"` | Host loopback and endpoint | +| Packaged proxy | PFN | `default: "allow"`; `hostLoopback: "deny"` | Package identity | +| Unpackaged AppContainer | Profile | `default: "allow"`; `hostLoopback: "deny"` | AppContainer profile | +| Unpackaged non-AppContainer | Omit | `default: "allow"`; `hostLoopback: "allow"` | None | + +Regardless of proxy type, an enforcing BaseContainer path applies per-container WFP rules that permit the MXC client +container to connect only to the configured loopback address and port. `allowedProxyPeer` adds proxy identity binding +on top of that common endpoint enforcement. All deployments use `ingress.default: "allow"` because ProcessContainer uses it as the capability gate for `privateNetworkClientServer`. This is a Windows capability requirement, not a statement that the proxy connection @@ -132,10 +136,9 @@ An unpackaged non-AppContainer proxy has no package family or AppContainer profi MXC grants the client container `privateNetworkClientServer` through `ingress.default: "allow"`, just as it does for an identity-scoped proxy. The difference is that MXC identifies this proxy only by the configured endpoint and enables -bidirectional host-loopback access. This is the lowest-enforcement deployment option. On an enforcing BaseContainer -path, WFP still restricts the MXC client container's egress to the configured loopback address and port, but Windows -cannot verify which host process owns that endpoint. It is intended primarily for development and debugging and -requires an installer- or administrator-owned firewall rule. +bidirectional host-loopback access. This is the lowest-enforcement deployment option because common WFP endpoint +scoping remains, but Windows cannot verify which host process owns that endpoint. It is intended primarily for +development and debugging and requires an installer- or administrator-owned firewall rule. #### HTTP client guidance @@ -170,14 +173,15 @@ The caller must: #### Proxy identity and firewall authorization -An AppContainer proxy is recommended. Supported deployment options are: +The WFP loopback-address-and-port restriction described above applies to every row. The table compares the additional +OS enforcement provided for the external proxy. A packaged AppContainer proxy provides the best enforcement. -| Proxy deployment | `allowedProxyPeer` | Enforcement | +| Proxy deployment | `allowedProxyPeer` | Additional OS enforcement | |---|---|---| -| Packaged AppContainer | Package family name | AppContainer isolation and package firewall rule | +| Packaged AppContainer | Package family name | **Best:** AppContainer isolation, package identity, package firewall | | Unpackaged AppContainer | AppContainer profile name | AppContainer isolation and administrator firewall rule | -| Packaged non-AppContainer | Package family name | Package identity and package firewall rule | -| Unpackaged non-AppContainer | Omit | Endpoint-only WFP and administrator firewall rule | +| Packaged non-AppContainer | Package family name | Package identity and package firewall; no AppContainer isolation | +| Unpackaged non-AppContainer | Omit | **Least:** no proxy identity or isolation; administrator firewall | The scoped peer rule and `privateNetworkClientServer` do not bypass Windows Firewall's block-inbound-to-non-allowed-apps policy. A packaged AppContainer proxy uses the package-owned firewall From 25eccf2ec623ac81be0deabf8547841655de6b83 Mon Sep 17 00:00:00 2001 From: Branden Bonaby <105318831+bbonaby@users.noreply.github.com> Date: Wed, 12 Aug 2026 20:58:35 -0700 Subject: [PATCH 15/23] Wrap proxy profile documentation link Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2449dac1-feb7-4da5-a249-9df137cc5360 --- docs/process-container/networking.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/process-container/networking.md b/docs/process-container/networking.md index 80486ddd6..00a5e76d5 100644 --- a/docs/process-container/networking.md +++ b/docs/process-container/networking.md @@ -187,7 +187,8 @@ The scoped peer rule and `privateNetworkClientServer` do not bypass Windows Firewall's block-inbound-to-non-allowed-apps policy. A packaged AppContainer proxy uses the package-owned firewall declaration shown in the [schema 0.8 examples](examples/0.8.0-schema.md); its application entry uses `uap10:RuntimeBehavior="packagedClassicApp"` with `uap10:TrustLevel="appContainer"`. An unpackaged AppContainer proxy -requires its installer or administrator to own an equivalent rule scoped to the proxy executable and configured port. See +requires its installer or administrator to own an equivalent rule scoped to the proxy executable and configured port. +See [CreateAppContainerProfile](https://learn.microsoft.com/windows/win32/api/userenv/nf-userenv-createappcontainerprofile) for unpackaged profile creation. From 1f9d51f514f821fbf0f21088ecb0a1cb963caa07 Mon Sep 17 00:00:00 2001 From: Branden Bonaby <105318831+bbonaby@users.noreply.github.com> Date: Wed, 12 Aug 2026 22:04:25 -0700 Subject: [PATCH 16/23] Make deployment guidance additive Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2449dac1-feb7-4da5-a249-9df137cc5360 --- docs/process-container/networking.md | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/docs/process-container/networking.md b/docs/process-container/networking.md index 00a5e76d5..29f2d42fc 100644 --- a/docs/process-container/networking.md +++ b/docs/process-container/networking.md @@ -92,14 +92,8 @@ Model 2 involves two separate processes: | Unpackaged AppContainer | Profile | `default: "allow"`; `hostLoopback: "deny"` | AppContainer profile | | Unpackaged non-AppContainer | Omit | `default: "allow"`; `hostLoopback: "allow"` | None | -Regardless of proxy type, an enforcing BaseContainer path applies per-container WFP rules that permit the MXC client -container to connect only to the configured loopback address and port. `allowedProxyPeer` adds proxy identity binding -on top of that common endpoint enforcement. - -All deployments use `ingress.default: "allow"` because ProcessContainer uses it as the capability gate for -`privateNetworkClientServer`. This is a Windows capability requirement, not a statement that the proxy connection -enters the MXC client container; the client initiates that connection. The capability is bidirectional, so it also -permits private-network server traffic. +All deployments retain the base Model 2 client policy. `allowedProxyPeer` adds proxy identity binding on top of the +common WFP endpoint enforcement. `ingress.hostLoopback` is bidirectional. `allowedProxyPeer` authorizes a package family or AppContainer profile without opening general host-loopback access, so identity-scoped paths keep `hostLoopback: "deny"`. Only an unpackaged @@ -158,11 +152,10 @@ apply when `runtimeConfig.networkProxy` is present. The proxy endpoint is runtime metadata, not shared network policy. MXC configures the per-container WinHTTP proxy, applies WFP endpoint scoping, and grants the private-network capability selected by `ingress.default`. -The identity-scoped and host-loopback paths are -mutually exclusive. When `allowedProxyPeer` is present, MXC resolves the package family or AppContainer profile and -grants the private-network capability selected by `ingress.default`. When it is omitted, MXC uses the configured proxy -endpoint without peer identity binding and requires bidirectional host-loopback access. MXC configures the per-container -WinHTTP proxy for either path. +The identity-scoped and host-loopback paths are mutually exclusive. When `allowedProxyPeer` is present, MXC resolves +the package family or AppContainer profile and grants the private-network capability selected by `ingress.default`. +When it is omitted, MXC uses the configured proxy endpoint without peer identity binding and requires bidirectional +host-loopback access. MXC configures the per-container WinHTTP proxy for either path. The caller must: From cd504ab8974d4251aa7b01b5ef4742abc30aef90 Mon Sep 17 00:00:00 2001 From: Branden Bonaby <105318831+bbonaby@users.noreply.github.com> Date: Wed, 12 Aug 2026 22:43:02 -0700 Subject: [PATCH 17/23] Clarify proxy deployment enforcement Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2449dac1-feb7-4da5-a249-9df137cc5360 --- docs/process-container/examples/0.8.0-schema.md | 16 ++++++++++------ docs/process-container/networking.md | 14 ++++++++++---- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/docs/process-container/examples/0.8.0-schema.md b/docs/process-container/examples/0.8.0-schema.md index 1367851ad..129e26a23 100644 --- a/docs/process-container/examples/0.8.0-schema.md +++ b/docs/process-container/examples/0.8.0-schema.md @@ -46,12 +46,14 @@ Windows implements this with the bidirectional `privateNetworkClientServer` capa private-network server traffic. `egress.default: "deny"` continues to block direct internet traffic. Valid endpoints use `localhost`, `127.0.0.1`, or `[::1]` with an explicit -port. The proxy-specific `network` block above is required on ProcessContainer. +port. The proxy-specific `network` block above is required for an identity-scoped ProcessContainer proxy and is +omitted for the identity-less host-loopback deployment. The proxy must already be running and listening on the loopback address and -port configured by `runtimeConfig.networkProxy`. MXC's schema 0.8 implementation must validate that the configured -endpoint is loopback. The proxy must bind only the configured loopback listener. A packaged AppContainer proxy needs -`privateNetworkClientServer`, `internetClient` for external destinations, and inbound firewall authorization. +port configured by `runtimeConfig.networkProxy`. See the canonical +[proxy deployment requirements](../networking.md#proxy-deployment-choices) for endpoint validation and listener +binding. A packaged AppContainer proxy needs `privateNetworkClientServer`, `internetClient` for external destinations, +and inbound firewall authorization. ### Minimal packaged AppContainer proxy manifest @@ -107,8 +109,10 @@ for package identity, signing, assets, and application metadata. `runFullTrust` is required by the firewall extension; `TrustLevel="appContainer"` still runs the proxy in an AppContainer. -The firewall declaration is scoped to the configured port. A deployment that uses a dynamic port must create or -update an equivalently executable- and port-scoped firewall rule before launching the client. Do not use an +The static package firewall declaration is scoped to the configured port and cannot follow a dynamic port at runtime. +A dynamic-port deployment must use an installer- or administrator-owned firewall API to replace the previous rule +before launching the client. The replacement must be scoped to the package or AppContainer SID, proxy executable, and +new port; the deployment must remove stale rules during replacement, teardown, and uninstall. Do not use an unrestricted package firewall rule to accommodate an OS-assigned port. After installing the package, retrieve its exact Package Family Name: diff --git a/docs/process-container/networking.md b/docs/process-container/networking.md index 29f2d42fc..5c3c317b5 100644 --- a/docs/process-container/networking.md +++ b/docs/process-container/networking.md @@ -86,14 +86,18 @@ Model 2 involves two separate processes: - **Proxy process:** a caller-created process that is already running outside the MXC client container. It may be packaged or unpackaged, with or without AppContainer isolation. +MXC must reject a `runtimeConfig.networkProxy` endpoint that is not loopback. The caller must configure the proxy to +bind only the exact loopback address and port supplied to MXC. + | External proxy | `allowedProxyPeer` | MXC client policy | Additional proxy identity | |---|---|---|---| -| Packaged proxy | PFN | `default: "allow"`; `hostLoopback: "deny"` | Package identity | +| Packaged proxy | Package Family Name | `default: "allow"`; `hostLoopback: "deny"` | Package identity | | Unpackaged AppContainer | Profile | `default: "allow"`; `hostLoopback: "deny"` | AppContainer profile | | Unpackaged non-AppContainer | Omit | `default: "allow"`; `hostLoopback: "allow"` | None | All deployments retain the base Model 2 client policy. `allowedProxyPeer` adds proxy identity binding on top of the -common WFP endpoint enforcement. +common WFP endpoint enforcement. The packaged row covers both AppContainer and non-AppContainer proxies because their +client policy and package identity are the same; the enforcement table below separates their additional protections. `ingress.hostLoopback` is bidirectional. `allowedProxyPeer` authorizes a package family or AppContainer profile without opening general host-loopback access, so identity-scoped paths keep `hostLoopback: "deny"`. Only an unpackaged @@ -167,7 +171,8 @@ The caller must: #### Proxy identity and firewall authorization The WFP loopback-address-and-port restriction described above applies to every row. The table compares the additional -OS enforcement provided for the external proxy. A packaged AppContainer proxy provides the best enforcement. +OS enforcement provided for the external proxy. A packaged AppContainer proxy provides the best enforcement. The two +middle rows provide different protections and are not ordered relative to each other. | Proxy deployment | `allowedProxyPeer` | Additional OS enforcement | |---|---|---| @@ -180,7 +185,8 @@ The scoped peer rule and `privateNetworkClientServer` do not bypass Windows Firewall's block-inbound-to-non-allowed-apps policy. A packaged AppContainer proxy uses the package-owned firewall declaration shown in the [schema 0.8 examples](examples/0.8.0-schema.md); its application entry uses `uap10:RuntimeBehavior="packagedClassicApp"` with `uap10:TrustLevel="appContainer"`. An unpackaged AppContainer proxy -requires its installer or administrator to own an equivalent rule scoped to the proxy executable and configured port. +requires its installer or administrator to own an equivalent rule scoped to the AppContainer profile SID, proxy +executable, and configured port. See [CreateAppContainerProfile](https://learn.microsoft.com/windows/win32/api/userenv/nf-userenv-createappcontainerprofile) for unpackaged profile creation. From cc300e4819e8bb346193b71f6504130d6721825a Mon Sep 17 00:00:00 2001 From: Branden Bonaby <105318831+bbonaby@users.noreply.github.com> Date: Wed, 12 Aug 2026 23:16:59 -0700 Subject: [PATCH 18/23] Clarify dynamic proxy port support Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2449dac1-feb7-4da5-a249-9df137cc5360 --- docs/process-container/examples/0.8.0-schema.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/process-container/examples/0.8.0-schema.md b/docs/process-container/examples/0.8.0-schema.md index 129e26a23..e45f9f890 100644 --- a/docs/process-container/examples/0.8.0-schema.md +++ b/docs/process-container/examples/0.8.0-schema.md @@ -109,11 +109,10 @@ for package identity, signing, assets, and application metadata. `runFullTrust` is required by the firewall extension; `TrustLevel="appContainer"` still runs the proxy in an AppContainer. -The static package firewall declaration is scoped to the configured port and cannot follow a dynamic port at runtime. -A dynamic-port deployment must use an installer- or administrator-owned firewall API to replace the previous rule -before launching the client. The replacement must be scoped to the package or AppContainer SID, proxy executable, and -new port; the deployment must remove stale rules during replacement, teardown, and uninstall. Do not use an -unrestricted package firewall rule to accommodate an OS-assigned port. +The manifest example uses a fixed port. Dynamic ports are supported, but a static manifest rule does not change when +the deployment selects a different port at runtime. Before launching the client, the deployment must ensure that an +equivalent inbound rule exists for the proxy identity, executable, and selected port. How the rule is provisioned and +retired is deployment-owned. Do not use an unrestricted package firewall rule to accommodate an OS-assigned port. After installing the package, retrieve its exact Package Family Name: From 335f05ea02a421464d7fe444bc210216fbc21d6b Mon Sep 17 00:00:00 2001 From: Branden Bonaby <105318831+bbonaby@users.noreply.github.com> Date: Wed, 12 Aug 2026 23:20:56 -0700 Subject: [PATCH 19/23] Keep proxy firewall guidance caller-owned Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2449dac1-feb7-4da5-a249-9df137cc5360 --- docs/process-container/examples/0.8.0-schema.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/process-container/examples/0.8.0-schema.md b/docs/process-container/examples/0.8.0-schema.md index e45f9f890..07361e8a0 100644 --- a/docs/process-container/examples/0.8.0-schema.md +++ b/docs/process-container/examples/0.8.0-schema.md @@ -109,10 +109,8 @@ for package identity, signing, assets, and application metadata. `runFullTrust` is required by the firewall extension; `TrustLevel="appContainer"` still runs the proxy in an AppContainer. -The manifest example uses a fixed port. Dynamic ports are supported, but a static manifest rule does not change when -the deployment selects a different port at runtime. Before launching the client, the deployment must ensure that an -equivalent inbound rule exists for the proxy identity, executable, and selected port. How the rule is provisioned and -retired is deployment-owned. Do not use an unrestricted package firewall rule to accommodate an OS-assigned port. +The manifest example uses port 8080. The proxy developer must ensure that its inbound firewall rule covers the port +supplied to MXC in `runtimeConfig.networkProxy`. After installing the package, retrieve its exact Package Family Name: From 26dbce262dd8a3848f76fb5a990601fc73ef5c3f Mon Sep 17 00:00:00 2001 From: Branden Bonaby <105318831+bbonaby@users.noreply.github.com> Date: Wed, 12 Aug 2026 23:27:18 -0700 Subject: [PATCH 20/23] Clarify proxy endpoint and loopback scope Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2449dac1-feb7-4da5-a249-9df137cc5360 --- docs/process-container/examples/0.8.0-schema.md | 5 ++--- docs/process-container/networking.md | 9 +++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/process-container/examples/0.8.0-schema.md b/docs/process-container/examples/0.8.0-schema.md index 07361e8a0..4445b2eff 100644 --- a/docs/process-container/examples/0.8.0-schema.md +++ b/docs/process-container/examples/0.8.0-schema.md @@ -119,9 +119,8 @@ Get-AppxPackage -Name Contoso.AgentProxy | Select-Object -ExpandProperty PackageFamilyName ``` -Use that value verbatim for `allowedProxyPeer` for any packaged proxy. The Package Family Name is derived from the -manifest identity name and publisher; it is not the display name or application ID. A bare profile name such as -`agent-proxy` is valid only for an unpackaged AppContainer proxy. +Use that value verbatim for `allowedProxyPeer` for any packaged proxy. For an unpackaged AppContainer proxy, use its +AppContainer profile name instead. See [Proxy identity and firewall authorization](../networking.md#proxy-identity-and-firewall-authorization) for Windows enforcement and firewall details. diff --git a/docs/process-container/networking.md b/docs/process-container/networking.md index 5c3c317b5..6b5f1d2df 100644 --- a/docs/process-container/networking.md +++ b/docs/process-container/networking.md @@ -96,14 +96,15 @@ bind only the exact loopback address and port supplied to MXC. | Unpackaged non-AppContainer | Omit | `default: "allow"`; `hostLoopback: "allow"` | None | All deployments retain the base Model 2 client policy. `allowedProxyPeer` adds proxy identity binding on top of the -common WFP endpoint enforcement. The packaged row covers both AppContainer and non-AppContainer proxies because their +common WFP endpoint enforcement. The proxy endpoint is the loopback address and port in +`runtimeConfig.networkProxy`. The packaged row covers both AppContainer and non-AppContainer proxies because their client policy and package identity are the same; the enforcement table below separates their additional protections. `ingress.hostLoopback` is bidirectional. `allowedProxyPeer` authorizes a package family or AppContainer profile without opening general host-loopback access, so identity-scoped paths keep `hostLoopback: "deny"`. Only an unpackaged -non-AppContainer proxy lacks an accepted peer identity and requires `hostLoopback: "allow"`. That also permits the MXC -client container to reach other host-loopback services and permits host-loopback clients to reach listeners in the MXC -client container. +non-AppContainer proxy lacks an accepted peer identity and requires `hostLoopback: "allow"`. That authorizes both +host-loopback directions, but Model 2 WFP still restricts client-container egress to the configured proxy endpoint. +Host-loopback clients can reach listeners in the MXC client container. #### Identity-scoped proxy From 1e0d9a43914e74671c00832a04c268b42e68092e Mon Sep 17 00:00:00 2001 From: Branden Bonaby <105318831+bbonaby@users.noreply.github.com> Date: Wed, 12 Aug 2026 23:30:56 -0700 Subject: [PATCH 21/23] Scope identity-less proxy firewall rule Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2449dac1-feb7-4da5-a249-9df137cc5360 --- docs/process-container/networking.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/process-container/networking.md b/docs/process-container/networking.md index 6b5f1d2df..839367ff3 100644 --- a/docs/process-container/networking.md +++ b/docs/process-container/networking.md @@ -137,7 +137,8 @@ MXC grants the client container `privateNetworkClientServer` through `ingress.de identity-scoped proxy. The difference is that MXC identifies this proxy only by the configured endpoint and enables bidirectional host-loopback access. This is the lowest-enforcement deployment option because common WFP endpoint scoping remains, but Windows cannot verify which host process owns that endpoint. It is intended primarily for -development and debugging and requires an installer- or administrator-owned firewall rule. +development and debugging and requires an installer- or administrator-owned firewall rule scoped to the proxy +executable and configured port. #### HTTP client guidance From f1563a2a2d2ab09fb94f921db542dc0821c1f4b8 Mon Sep 17 00:00:00 2001 From: Branden Bonaby <105318831+bbonaby@users.noreply.github.com> Date: Thu, 13 Aug 2026 00:13:55 -0700 Subject: [PATCH 22/23] Order manifest capabilities canonically Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2449dac1-feb7-4da5-a249-9df137cc5360 --- docs/process-container/examples/0.8.0-schema.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/process-container/examples/0.8.0-schema.md b/docs/process-container/examples/0.8.0-schema.md index 4445b2eff..b14c940aa 100644 --- a/docs/process-container/examples/0.8.0-schema.md +++ b/docs/process-container/examples/0.8.0-schema.md @@ -79,9 +79,9 @@ and inbound firewall authorization. - + From 8c681f7e8b25a63b137f2b2c3c0f412af61bca00 Mon Sep 17 00:00:00 2001 From: Branden Bonaby <105318831+bbonaby@users.noreply.github.com> Date: Thu, 13 Aug 2026 00:18:57 -0700 Subject: [PATCH 23/23] Align proxy peer eligibility wording Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2449dac1-feb7-4da5-a249-9df137cc5360 --- docs/process-container/examples/0.8.0-schema.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/process-container/examples/0.8.0-schema.md b/docs/process-container/examples/0.8.0-schema.md index b14c940aa..d4b9a5c2e 100644 --- a/docs/process-container/examples/0.8.0-schema.md +++ b/docs/process-container/examples/0.8.0-schema.md @@ -42,8 +42,9 @@ Package identity can scope a packaged proxy whether or not that proxy uses AppCo | `processContainer.network.allowedProxyPeer` | Installed Package Family Name or AppContainer profile name | ProcessContainer requires `ingress.default: "allow"` for private-network communication with an identity-scoped proxy. -Windows implements this with the bidirectional `privateNetworkClientServer` capability, so the setting also permits -private-network server traffic. `egress.default: "deny"` continues to block direct internet traffic. +Windows implements this on the MXC client with the bidirectional `privateNetworkClientServer` capability, so the +setting also permits private-network server traffic. `egress.default: "deny"` continues to block direct internet +traffic. Valid endpoints use `localhost`, `127.0.0.1`, or `[::1]` with an explicit port. The proxy-specific `network` block above is required for an identity-scoped ProcessContainer proxy and is