Hardening WinRM and PowerShell remoting
Lock down WinRM: inventory listeners, enforce Kerberos, block Basic, Digest and CredSSP, add HTTPS listeners, keep TrustedHosts empty and scope the firewall.
WinRM is the transport under PowerShell remoting, winrs, Server Manager, Windows Admin Center, JEA and Windows Event Forwarding. It is also one of the most used lateral movement channels, because a valid admin credential plus an open port 5985 means remote code execution by design. The PowerShell security pillar lists the three baseline settings. This guide covers the rest: what's actually listening, how to force strong authentication, how to add HTTPS and how to limit who can reach it.
Defaults worth knowing
| Windows Server 2016 to 2025 | Windows 10 / 11 (including 24H2 and 25H2) | |
|---|---|---|
| WinRM service | Running, automatic start | Present; not configured for remoting by default |
| Listener | HTTP on 5985, all addresses | None until Enable-PSRemoting or winrm quickconfig |
| Firewall rule | Windows Remote Management (HTTP-In) enabled; Public profile limited to the local subnet | Disabled until remoting is enabled |
| Basic, unencrypted, CredSSP | Off | Off |
The secure authentication defaults are good. The problem is drift: a vendor installer, a troubleshooting session or a script found online turns on Basic, sets TrustedHosts to * or adds a listener on every interface. Policy stops that.
Step 1: inventory what is really configured
On a sample of servers and workstations, record the listeners, authentication settings and endpoints:
winrm enumerate winrm/config/listener
Get-ChildItem WSMan:\localhost\Service\Auth
Get-ChildItem WSMan:\localhost\Client\Auth
Get-Item WSMan:\localhost\Service\AllowUnencrypted
Get-Item WSMan:\localhost\Client\TrustedHosts
Get-PSSessionConfiguration | Select-Object Name, Permission
Get-LocalGroupMember -Group 'Remote Management Users'Look for HTTP listeners on workstations that don't need them, compatibility listeners on ports 80 or 443, a non-empty TrustedHosts, Basic or CredSSP set to true, and unexpected members of Remote Management Users. Anyone in that group can open a remote PowerShell session on the machine without being an administrator.
Step 2: enforce authentication and encryption by GPO
Under Computer Configuration > Policies > Administrative Templates > Windows Components > Windows Remote Management (WinRM):
WinRM Service
| Setting | Value | Why |
|---|---|---|
| Allow Basic authentication | Disabled | Basic sends reusable credentials |
| Allow unencrypted traffic | Disabled | Keeps message encryption mandatory on HTTP |
| Allow CredSSP authentication | Disabled | CredSSP delegates full credentials to the server |
| Disallow WinRM from storing RunAs credentials | Enabled | Stops plug-ins from caching credentials |
| Specify channel binding token hardening level | Strict | Ties authentication to the TLS channel on HTTPS |
| Turn On Compatibility HTTP Listener / HTTPS Listener | Disabled | No legacy listeners on 80/443 |
WinRM Client
| Setting | Value |
|---|---|
| Allow Basic authentication | Disabled |
| Allow unencrypted traffic | Disabled |
| Allow CredSSP authentication | Disabled |
| Disallow Digest authentication | Enabled |
| Trusted Hosts | Not configured, or Disabled |
The registry equivalents live under HKLM\SOFTWARE\Policies\Microsoft\Windows\WinRM\Service and ...\WinRM\Client (for example AllowBasic = 0, AllowUnencryptedTraffic = 0, DisableRunAs = 1). The Microsoft and CIS security baselines set most of these; enforce them where the baselines don't reach.
CredSSP deserves a note. It's usually enabled to solve the "double hop" (a remote session that needs to reach a file share). The better answers are resource-based constrained delegation, a JEA endpoint running as a gMSA, or passing a credential object explicitly to the second command. Each of those avoids leaving a full credential on the intermediate server.
Step 3: prefer Kerberos, and consider Kerberos only
Kerberos gives mutual authentication: the client knows it is talking to the real server. NTLM, which Negotiate falls back to, does not, and is open to NTLM relay. Negotiate falls back to NTLM when you connect by IP address, to a non-domain host or to a name without an SPN.
Three levels, in increasing strictness:
- Connect by FQDN and keep TrustedHosts empty. Clients then use Kerberos for domain hosts and refuse NTLM to unauthenticated servers over HTTP.
- Restrict NTLM domain-wide with the NTLM auditing and restriction policies, so fallback shows up in logs before you block it.
- Disable Negotiate on Tier 0 servers. In the WinRM Service policy set Disallow Negotiate authentication = Enabled. Clients must then connect with
-Authentication Kerberos.
Enter-PSSession -ComputerName dc01.corp.example -Authentication KerberosTest option 3 carefully. Server Manager, Windows Admin Center and many scripts use Negotiate by default and will fail until reconfigured.
Step 4: add HTTPS listeners where they're needed
HTTPS adds certificate-based server authentication and TLS. You need it for non-domain hosts and workgroup servers, across forests without trusts, and wherever policy demands TLS on the wire. Issue a certificate from your internal CA with the Server Authentication EKU and the host's FQDN in the subject or SAN, ideally through autoenrollment. Then:
$fqdn = [System.Net.Dns]::GetHostEntry($env:COMPUTERNAME).HostName
$cert = Get-ChildItem Cert:\LocalMachine\My |
Where-Object { $_.Subject -eq "CN=$fqdn" -and $_.EnhancedKeyUsageList.FriendlyName -contains 'Server Authentication' } |
Sort-Object NotAfter -Descending | Select-Object -First 1
New-Item -Path WSMan:\localhost\Listener -Transport HTTPS -Address * `
-CertificateThumbPrint $cert.Thumbprint -ForceClients connect with -UseSSL. Don't use self-signed certificates with -SkipCACheck and -SkipCNCheck outside a lab: that throws away the server authentication you added HTTPS for.
The listener is bound to a thumbprint and does not follow certificate renewal. Update it from your configuration management after each renewal:
Set-WSManInstance -ResourceURI winrm/config/Listener `
-SelectorSet @{ Address = '*'; Transport = 'HTTPS' } `
-ValueSet @{ CertificateThumbprint = $cert.Thumbprint }Once every management tool uses HTTPS, you can remove the HTTP listener on sensitive servers. Leave it in place where Windows Event Forwarding collectors or tools still depend on port 5985.
Step 5: scope who can reach WinRM
The most effective WinRM control isn't a WinRM setting. It's the host firewall. Only jump servers, privileged access workstations and management servers need to reach 5985/5986.
- In the firewall GPO, replace the built-in Windows Remote Management (HTTP-In) rule with rules whose remote address is your management subnets, for both 5985 and 5986. See Windows Firewall hardening and managing firewall policy at scale.
- On workstations, block inbound WinRM entirely unless a specific tool needs it.
- Don't rely on Allow remote server management through WinRM for this. Its IPv4/IPv6 filter controls which local addresses the listener binds to, not which remote clients may connect.
Also restrict who can authenticate once they reach it. Keep Remote Management Users empty or tightly controlled, and remember that local administrator accounts are subject to UAC remote restrictions. Keep those restrictions on as described in UAC and Administrator protection.
Endpoint permissions
Every remoting endpoint has its own security descriptor. Get-PSSessionConfiguration shows them. The defaults (microsoft.powershell, microsoft.powershell32 and, where installed, PowerShell.7) allow Administrators and Remote Management Users. Vendors sometimes register extra endpoints with broader permissions, and JEA endpoints define their own through role definitions. Review the list after every software rollout, remove endpoints nobody uses with Unregister-PSSessionConfiguration, and treat a new endpoint appearing on a server as a configuration change that needs an owner. On sensitive servers where nobody should use full remoting at all, you can restrict the default endpoints to a dedicated Tier 0 admin group with Set-PSSessionConfiguration -SecurityDescriptorSddl and publish JEA endpoints for everything else.
What breaks
- Server Manager and Windows Admin Center fail against hosts where Negotiate is disabled or only HTTPS is available, until they are set to Kerberos or HTTPS.
- Scripts that connect by IP address stop working with an empty TrustedHosts. That's intended; fix them to use names.
- Double-hop workflows that relied on CredSSP break. Move them to constrained delegation or a gMSA-backed JEA endpoint.
- Event forwarding stops if you disable the WinRM service on sources, or firewall 5985 on the collector. See Windows Event Forwarding at scale.
- Expired certificates break HTTPS listeners silently. Monitor listener certificate expiry.
Verify it
# Policy applied?
Get-Item WSMan:\localhost\Service\AllowUnencrypted # false
Get-ChildItem WSMan:\localhost\Service\Auth # Basic false, CredSSP false
Get-Item WSMan:\localhost\Client\TrustedHosts # empty
# Kerberos and HTTPS work from a management host
Test-WSMan -ComputerName srv01.corp.example -UseSSL
Invoke-Command -ComputerName srv01.corp.example -UseSSL -ScriptBlock { hostname }
# Blocked from a normal workstation (should time out)
Test-NetConnection srv01.corp.example -Port 5985For detection, remote sessions show up as wsmprovhost.exe processes on the target (4688 or Sysmon 1), network logons (4624 type 3) and entries in Microsoft-Windows-WinRM/Operational. Alert on WinRM sessions to servers that don't originate from your management subnets, and on changes to WinRM configuration outside your change process. The PowerShell security topic page collects the related guides, including JEA for restricting what those sessions can do.
Checklist
- Listeners, auth settings, TrustedHosts and endpoint permissions inventoried
- Basic, unencrypted traffic, CredSSP and Digest disabled by GPO (service and client)
- RunAs credential storage disallowed; compatibility listeners off
- TrustedHosts empty; connections by FQDN with Kerberos
- Negotiate disabled on Tier 0 servers after testing
- HTTPS listeners with CA-issued certificates where needed; thumbprint updated on renewal
- Inbound 5985/5986 allowed only from management subnets
- Remote Management Users membership reviewed
- WinRM session and configuration-change detections in place
Frequently asked questions
Is WinRM over HTTP port 5985 sent in clear text?
Not in a domain with Kerberos or Negotiate authentication. WinRM encrypts the message payload with the session key, so commands and output are protected even on port 5985. What HTTP lacks is certificate-based server authentication, which matters when Kerberos isn't available. Keep 'Allow unencrypted traffic' disabled so this protection can't be switched off.
Should I disable the WinRM service on workstations?
Check first. Source-initiated Windows Event Forwarding needs the WinRM service running on every source, and some management tools use it. A safer default is to leave the service running for outbound use, remove any inbound listener that isn't needed, and block inbound 5985/5986 at the host firewall except from management hosts.
Why is TrustedHosts set to * a problem?
TrustedHosts tells the WinRM client which computers it may send NTLM credentials to when it can't verify their identity with Kerberos or a certificate. A wildcard means the client will authenticate to any machine, including one an attacker controls or spoofs. Connect by FQDN with Kerberos, or use HTTPS for non-domain hosts, and leave TrustedHosts empty.
Hardening WinRM and PowerShell remoting