Skip to content

IIS application pool identity and NTFS permissions: least privilege that works

Verified 2 min read

Use ApplicationPoolIdentity, grant only the NTFS rights the site needs, and tune app-pool settings without breaking the app or widening access.

Tested onStandard / Datacenter · Build 26100.33650 · x64
E1
Build
26100.33650
Edition
Standard / Datacenter
Architecture
x64
Support
Documentation (E1)
Evidence
E1Official documentation
Verified
2026-10-29
Test machine
IIS Manager UI reference: VM 361 Windows 11 26H2; app pool labpool; Server 2025 cmdlets E1
Page type
Task
IIS Manager Application Pools showing DefaultAppPool and a labpool with ApplicationPoolIdentity.
VM 361 app pools: DefaultAppPool and labpool. Both use ApplicationPoolIdentity; the lab site uses labpool. Windows 11 UI reference; Server 2025 steps E1.

By default, an IIS app pool runs as a virtual account named IIS AppPool\<PoolName> (ApplicationPoolIdentity). You do not create a password; Windows creates the SID when the pool starts.

Grant that identity only what the site needs:

  • read/execute on the site root;
  • modify on one upload/cache directory if the app writes files;
  • nothing on C:\, C:\Windows or another site’s folder.

Do not “fix” a 401.3 by adding Everyone or by putting the app pool on a domain admin.

Identity Use Risk
ApplicationPoolIdentity Default; per-pool virtual account Low; grant NTFS explicitly
NetworkService Legacy/domain machine account Broader network identity
LocalSystem Never for a web app Full local control
Custom local user App needs a fixed profile/ACL Password/rotation burden
gMSA Domain app, managed password Requires AD design

For a standalone server, ApplicationPoolIdentity is the right default.

Terminal window
Import-Module WebAdministration
New-WebAppPool -Name 'labpool'
Set-ItemProperty IIS:\AppPools\labpool -Name managedRuntimeVersion -Value ''

Grant read/execute:

Terminal window
icacls C:\inetpub\lab /grant "IIS AppPool\labpool:(OI)(CI)RX"

Grant write only where needed:

Terminal window
New-Item -ItemType Directory -Force C:\inetpub\lab\uploads | Out-Null
icacls C:\inetpub\lab\uploads /grant "IIS AppPool\labpool:(OI)(CI)M"

(OI)(CI) applies to files and folders; RX is read/execute; M is modify. Do not grant F (full) unless the app genuinely needs to change ACLs/ownership.

Terminal window
Get-IISAppPool | Select-Object Name, State, ProcessModel
icacls C:\inetpub\lab
Invoke-WebRequest http://localhost:8080/ -UseBasicParsing | Select-Object StatusCode

If you get 401.3, the identity cannot read the file. Check the effective ACL, not just the folder’s Sharing tab. If you get 500.19, it is a configuration/permissions error, often a parent web.config or a missing module.

Setting Default When to change
.NET CLR version v4.0 Set No Managed Code for static/Node/Python
Managed pipeline Integrated Classic only for legacy apps
Start mode OnDemand AlwaysRunning for latency-sensitive apps
Idle timeout 20 min Disable only if the app must stay warm
Regular time interval 1740 min Recycle off-peak; watch memory
32-bit applications False True only for 32-bit DLLs
Load user profile False True for apps that need a profile (e.g. some crypto)

Do not disable recycling globally to “fix” a memory leak. Find the leak or schedule a recycle.

  • Granting Everyone read on the whole site because one subfolder failed.
  • Giving the app pool write access to the site root “for uploads”; point uploads at one directory.
  • Running the pool as a domain admin to reach a UNC share.
  • Using LocalSystem because a vendor installer said so.
  • Forgetting that a virtual directory uses the parent app’s pool, not its own.

The screenshot is from Windows 11 26H2; labpool was created for C:\inetpub\lab on port 8080. Server 2025 uses the same WebAdministration object model, but role installation remains E1.

Sources