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

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

**Tested on**

- Build: 26100.33650
- Edition: Standard / Datacenter
- Architecture: x64
- Evidence: E1
- Verified: 2026-10-29
- Test machine: IIS Manager UI reference: VM 361 Windows 11 26H2; app pool labpool; Server 2025 cmdlets E1

VM 361 app pools: DefaultAppPool and labpool. Both use ApplicationPoolIdentity; the lab site uses labpool. Windows 11 UI reference; Server 2025 steps E1.

## The short answer

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 choices

| 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.

## Create the pool and grant NTFS

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

Grant read/execute:

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

Grant write only where needed:

```powershell
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.

## Verify

```powershell
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.

## App-pool settings that matter

| 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.

> **Caution: ApplicationPoolIdentity is not a user you can log in as**
>
> `IIS AppPool\labpool` is a virtual account. You cannot set its password or log in interactively. Grant NTFS to that exact name; do not guess a SID.

## Common mistakes

- 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.

## Lab note

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

- [Microsoft Learn — Application pool identities](https://learn.microsoft.com/en-us/iis/manage/configuring-security/application-pool-identities)
- [Microsoft Learn — Application pools](https://learn.microsoft.com/en-us/iis/configuration/system.applicationhost/applicationpools/)
- [Microsoft Learn — icacls](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/icacls)

---

Source: https://winbook.fyi/en/server/web/iis-app-pools/
