Detailed comparison of AppContainer (AC / LPAC) and Restricted Token — architecture, capabilities, constraints, and how to choose the right mode for your use case.
Sandy supports two fundamentally different Windows sandbox mechanisms. Transient runs use per-instance identities, while saved profiles preserve one durable identity across repeated runs.
Uses the same kernel-level isolation as UWP apps and Microsoft Edge. Each instance generates a UUID-based profile (Sandy_<uuid>) and receives a unique SID (S-1-15-2-*) from CreateAppContainerProfile.
lan key)
Creates a restricted token with a per-instance SID (S-1-9-*) under the SECURITY_RESOURCE_MANAGER_AUTHORITY. The old fixed S-1-5-12 SID remains in restricting SIDs for system object access only. Configurable integrity level: low or medium.
DENY_ACCESS ACEs — kernel evaluates deny-before-allownamed_pipes = true)desktop = true by default)[registry] section)strict = true): exclude user SID from restricting list for grant-only access modelBoth modes generate a unique SID per instance — no two concurrent Sandy instances share security identifiers, even if they grant access to the same paths.
| Aspect | AC / LPAC | Restricted Low | Restricted Medium |
|---|---|---|---|
| SID authority | S-1-15-2-* (AppContainer) | S-1-9-* (Resource Manager) | S-1-9-* (Resource Manager) |
| SID uniqueness | UUID-derived, per-profile | GUID-derived, per-instance | GUID-derived, per-instance |
| Integrity level | 🔒 Low (fixed) | 🔒 Low (fixed) | 🔒 Medium (fixed) |
| Object namespace | 🔒 Isolated, private | 🔒 Shared with host | 🔒 Shared with host |
| Privilege stripping | 🔒 All stripped | 🔒 All except SeChangeNotify | 🔒 All except SeChangeNotify |
| Elevation | ❌ Blocked | ❌ Blocked | ❌ Blocked |
| Isolation layers | 2: SID + namespace | 2: SIDs + integrity | 1: SIDs only |
| DENY ACE mechanism | Mask reduction (kernel ignores DENY ACEs) | Real DENY_ACCESS ACEs | Real DENY_ACCESS ACEs |
| Pre-launch token validation | N/A | ✅ Integrity verified (0x1000) | ✅ Integrity verified (0x2000) |
The Windows kernel ignores DENY_ACCESS ACEs for AppContainer SIDs — this is a kernel property, not a design choice. Sandy implements AC deny by computing reducedMask = existingMask & ~denyOnlyBits and setting PROTECTED_DACL on denied paths to prevent re-inheritance from parent grants. Restricted Token mode uses real DENY_ACCESS ACEs, which the kernel evaluates deny-before-allow as expected.
All sandbox aspects across all three operating modes.
| Aspect | AC / LPAC | Restricted Low | Restricted Medium |
|---|---|---|---|
| Identity & Process | |||
| Integrity level | 🔒 Low | 🔒 Low | 🔒 Medium |
| Object namespace | 🔒 Isolated | 🔒 Shared | 🔒 Shared |
| Elevation | ❌ Blocked | ❌ Blocked | ❌ Blocked |
| Network | |||
| Internet / outbound | ⚙️ network | ✅ Allowed | ✅ Allowed |
| LAN access | ⚙️ lan | ✅ Allowed | ✅ Allowed |
| Localhost / loopback | ⚙️ lan = 'with localhost' ¹ | ✅ Allowed | ✅ Allowed |
| IPC & Interop | |||
| Named pipes | ❌ Blocked | ⚙️ named_pipes | ⚙️ named_pipes |
| Desktop access | ✅ Inherited | ⚙️ desktop | ⚙️ desktop |
| COM / RPC servers | ❌ Blocked | ✅ Allowed | ✅ Allowed |
| Window messages (UIPI) | ❌ Blocked | ❌ Blocked | ✅ Allowed |
| Scheduled tasks | ❌ Blocked | ❌ Blocked | ✅ Allowed |
| File System | |||
| System dir reads (Windows, PF) | ✅ Via App. Packages ³ | ✅ Allowed | ✅ Allowed |
| System dir writes | ❌ Blocked | ❌ Blocked | ❌ Blocked |
| User profile reads | ⚙️ [allow.*] | ✅ Allowed | ✅ Allowed |
| User profile writes | ⚙️ [allow.*] | ⚙️ [allow.*] ² | ✅ Allowed |
| Custom file/folder grants | ⚙️ [allow.*] | ⚙️ [allow.*] | ⚙️ [allow.*] |
| DLL/API set resolution | ✅ Allowed ³ | ⚠️ May break apps | ✅ Allowed |
| Registry | |||
| Registry reads | ✅ Private hive | ✅ Allowed | ✅ Allowed |
| HKCU writes | ❌ Blocked | ❌ Blocked | ✅ Allowed |
| HKLM writes | ❌ Blocked | ❌ Blocked | ❌ Blocked |
| Custom registry grants | ❌ N/A | ⚙️ [registry] | ⚙️ [registry] |
| Process & I/O | |||
| Child processes | ⚙️ child_processes | ⚙️ child_processes | ⚙️ child_processes |
| Stdin | ⚙️ stdin | ⚙️ stdin | ⚙️ stdin |
| Clipboard read | ⚙️ clipboard_read | ⚙️ clipboard_read | ⚙️ clipboard_read |
| Clipboard write | ⚙️ clipboard_write | ⚙️ clipboard_write | ⚙️ clipboard_write |
| Environment | ⚙️ inherit | ⚙️ inherit | ⚙️ inherit |
| Resource limits | ⚙️ [limit] | ⚙️ [limit] | ⚙️ [limit] |
¹ Loopback (AppContainer) is enabled with lan = 'with localhost'. Sandy uses CheckNetIsolation.exe to manage a per-instance loopback exemption. Loopback always implies LAN — there is no localhost-only capability in Windows.
² Restricted Low writes to medium-integrity folders (most of C:\Users) are blocked by Mandatory Integrity Control even with [allow.*] grants. Use AppData\LocalLow or Restricted Medium for user profile writes.
³ LPAC opts out of ALL APPLICATION PACKAGES (S-1-15-2-1). Windows system dirs (C:\Windows, System32, Program Files) carry ALL RESTRICTED APPLICATION PACKAGES (S-1-15-2-2) ACEs on Win10+ and are readable by LPAC. However, user-installed application dirs (e.g. Python under AppData\Local\Programs) typically carry only the APP ACE without ARAP, making them invisible to LPAC unless explicitly granted via [allow.*]. DLLs from those paths also need explicit execute grants.
Both modes share one run pipeline, but ownership differs: transient runs clean up their grants on exit, while saved profiles keep profile-owned grants and container state until --delete-profile.
AppData\LocalLowUse -c or -s while you are discovering the minimum grant set. Once the policy is stable, create a saved profile with --create-profile so repeated runs reuse one durable sandbox identity.
Run-scoped state is recovered on clean exit and after crashes, but durable profile state intentionally survives normal runs. Cleanup must therefore distinguish run-owned resources from profile-owned resources.
| Resource | AC / LPAC | Restricted (any) |
|---|---|---|
| ACL grants | Remove ACEs for instance SID (S-1-15-2-*) | Remove ACEs for instance SID (S-1-9-*) |
| AppContainer profile | Deleted: Sandy_<uuid> | N/A |
| Loopback exemption | Removed via CheckNetIsolation.exe | N/A |
| Desktop / WinSta ACLs | N/A | ACEs removed by SID (if desktop = true) |
| Registry grants | N/A | ACEs removed by SID |
| Instance subkey | Deleted from HKCU\Software\Sandy\Grants\<UUID> | |
| Scheduled task | Deleted: SandyCleanup_<UUID> | |
Because each instance uses a unique SID, cleanup is ACE-level: RemoveSidFromDacl removes only ACEs matching the instance's SID. Concurrent instances never interfere — one instance's cleanup cannot accidentally revoke another's grants.