Repository navigation
Applying ACLPolicy for HNSEndpoint is broken in WindowsServer2025 #616
Description
Describe the bug
When I create an ACLPolicy for HNSEndpoint, it fails to apply in Windows Server 2025 Containers. This behavior works as expected in Windows Server 2019. It's unclear what has changed in the latest version of Windows Server to break this behavior. The lack of being able to apply ACLPolicy for NAT indicates that containers on Windows Server 2025 can talk to any internal IP. For context, we have been able to shield containers from reaching internal IPs in Windows Server 2019, but we've lost this ability in Windows Server 2025.
To Reproduce
- Create container-1 in docker, capture the IP-Address, and run a simple web server on port 8080
- Create container-2 in docker, capture the IP-Address
- If you curl.exe container-1:8080 (from inside container-2), you should see the response from the server. That's expected because by default there is not ACLPolicy.
- Run
Get-HNSEndpointon the host to get the Endpoint-ID for container-2 - Execute acl-policy.exe (a simple binary that sets ACLPolicy) e.g.
c:\acl-policy.exe endoint-id-from-step-4 ip-address-for-container-2 ip-address-for-container-1. This will create an ACLPolicy to Block Outgoing traffic from container-2 to container-1. - Re-run the
curl.exefrom step 3 and you still see container-2 is able to talk to container-1
Expected behavior
When I re-run the curl.exe in container-2 I expect to see an error after setting the ACLPolicy
Configuration:
- Edition: Windows Server
- Base Image being used: Windows Server Core
- Container engine: docker
- Container Engine version N/A
Additional context
Simple acl-policy binary:
package main
import (
"fmt"
"os"
"encoding/json"
"github.com/Microsoft/hcsshim"
)
func main() {
endpointId := os.Args[1]
source := os.Args[2]
dest := os.Args[3]
endpoint, err := hcsshim.GetHNSEndpointByID(endpointId)
if err != nil {
fmt.Printf("ERR GetHNSEndpointByID: %+v\n", err.Error())
os.Exit(1)
}
acl := &hcsshim.ACLPolicy{
Type: hcsshim.ACL,
Action: hcsshim.Block,
Direction: hcsshim.Out,
Protocol: uint16(256),
LocalAddresses: source,
RemoteAddresses: dest,
}
policy, err := json.Marshal(acl)
if err != nil {
fmt.Printf("ERR json.Marshal: %+v\n", err.Error())
os.Exit(1)
}
endpoint.Policies = append(endpoint.Policies, policy)
_, err = endpoint.Update()
if err != nil {
fmt.Printf("ERR endpoint.Update: %+v\n", err.Error())
os.Exit(1)
}
fmt.Printf("Updated endpoint to BLOCK %s from %s\n", dest, source)
}Simple WebServer in powershell for container-1:
$listener = New-Object System.Net.HttpListener
$listener.Prefixes.Add("http://+:8080/")
$listener.Start()
Write-Host "Listening on http://+:8080/"
while ($listener.IsListening) {
$context = $listener.GetContext()
$request = $context.Request
$response = $context.Response
$response.ContentType = "text/plain"
$response.StatusCode = 200
$response.StatusDescription = "OK"
$output = $response.OutputStream
$writer = New-Object System.IO.StreamWriter($output)
$writer.Write("Hello from PowerShell Server!")
$writer.Flush()
$writer.Close()
}
$listener.Stop()
Activity
github-actions commentedon Oct 2, 2025
Thank you for creating an Issue. Please note that GitHub is not an official channel for Microsoft support requests. To create an official support request, please open a ticket here. Microsoft and the GitHub Community strive to provide a best effort in answering questions and supporting Issues on GitHub.
winkingturtle-vmw commentedon Oct 2, 2025
Nicole Trappe (@ntrappe-msft) Can you please triage this issue ? This is quite an important issue with Windows Server 2025.
winkingturtle-vmw commentedon Nov 7, 2025
Pinging to keep this issue open
winkingturtle-vmw commentedon Dec 3, 2025
Pining to keep this issue open
winkingturtle-vmw commentedon Jan 12, 2026
Pinging to keep this issue open
winkingturtle-vmw commentedon Feb 17, 2026
Pinging to keep this issue open
winkingturtle-vmw commentedon Mar 23, 2026
Pinging to keep this issue open
sureshbabu-msft commentedon Apr 16, 2026
Hi Amin Jamali (@winkingturtle-vmw), thank you for reporting this issue and for your patience.
We attempted to reproduce the issue by following your steps on Windows Server 2025, but the ACLPolicy for HNSEndpoint worked as expected in our environment — outbound traffic was successfully blocked after applying the policy.
To help us investigate further, could you please share the following details about your environment?
| Where-Object { $_.Id -eq "" } | ConvertTo-Json -Depth 5
This will help us verify whether the ACL policy was actually persisted on the endpoint, or if the Update() call silently failed
to apply it.
7. hcsshim library version — which version of github.com/Microsoft/hcsshim is your acl-policy.exe binary built with?
This information will help us narrow down whether the issue is tied to a specific host build, patch level, or configuration.
Thank you!
winkingturtle-vmw commentedon Apr 21, 2026
sureshbabu-msft Thank you for following up on this issue. There seems to have been a recent windows patch fix that has fixed the original issue, but have introduced a new issue. The original issue didn't block the traffic when I tested this in Oct 2025, the new issue is that it blocks every IP instead of the just the source. In other words, the current behavior is that once we run the
acl-policy.exeit blocks access to all sources, so when creating a new container with a different IP and webserver, I can't curl the new webserver.Here is are my build information for the version I am running:
[System.Environment]::OSVersion.VersionGet-HotFix | Sort-Object InstalledOn -Descending | Select-Object -First 5docker versionmcr.microsoft.com/windows/servercore:ltsc2025is the image I am usingGet-HNSEndpoint | Where-Object { $_.Id -eq "c489649f-79f7-4319-b37d-985781a512c7" } | ConvertTo-Json -Depth 5sureshbabu-msft commentedon May 11, 2026
Hi Amin Jamali (@winkingturtle-vmw), thank you for the detailed environment information and for confirming the updated behavior after the April 2026 patches (KB5082062/KB5082063).
We've investigated this with the networking team and can confirm that this behavior is by design. When any ACL policy is applied on an HNS endpoint, HNS switches the endpoint to a default-deny posture — meaning all outbound traffic not explicitly allowed by an ACL rule gets blocked. So, a lone Block rule effectively results in "block the target + deny everything else," which is the behavior you're observing.
Workaround
To achieve the intended behavior (block specific traffic while allowing everything else), you need to add an explicit Allow-all outbound rule alongside your specific Block rule. The Allow-all rule should use a higher
Prioritynumber (lower precedence) so the Block rule is evaluated first.Here's the updated
acl-policy.exesource:Key points:
Prioritynumbers = higher precedence in VFPWith both rules applied, traffic to the blocked IP will be denied while traffic to all other destinations will continue to work normally.
We understand this adds extra configuration overhead, but this is the expected pattern when working with HNS ACL policies — any ACL presence triggers default-deny, requiring explicit Allow rules for permitted traffic.
sureshbabu-msft commentedon Jun 2, 2026
Hi Amin Jamali (@winkingturtle-vmw),
We're closing this issue as we haven't heard back since our last response on May 11, 2026.
To summarize the resolution:
If you're still experiencing issues or have further questions, please feel free to reopen this issue and we'll be happy to assist.
Thank you for your patience and for reporting this!