The public Win32 contract does not establish that an AppAuthority capability SID is invalid as a restricting SID, but it also does not document capability SIDs as supported inputs or explain ERROR_INVALID_PARAMETER for this combination; therefore, do not treat the observed error as proof of a membership, UAC-filtering, or namespace rule.
What the documented contract establishes
CreateRestrictedToken documents these requirements for SidsToRestrict:
- It is an array of valid
SID_AND_ATTRIBUTESstructures. -
Attributesmust be zero. - Restricting SIDs are enabled automatically for access checks.
- It does not state that a restricting SID must already appear in
TokenGroups. - It does not state any permitted or prohibited SID authorities.
- The documented explicit
ERROR_INVALID_PARAMETERcase concerns passing too many privileges inPrivilegesToDelete, which does not apply to your call becauseDISABLE_MAX_PRIVILEGEcauses that list to be ignored anyway.^1^
Consequently, Everyone being present in TokenGroups while the capability SID is absent does not establish the reason for the different outcomes. The documented “ignore SIDs not in the existing token” rule applies to SidsToDisable, not SidsToRestrict.^1^
DeriveCapabilitySidsFromName returns two distinct arrays:
- NT Authority capability group SIDs
- AppAuthority capability SIDs
The documentation describes their construction and ownership requirements, but not their use with CreateRestrictedToken.^2^ Capability SIDs use the S-1-15-3 prefix and are intended to identify capabilities granting components or applications access to associated resources.^3^
There is therefore no documented basis to conclude either:
- all structurally valid capability SIDs must be accepted by
CreateRestrictedToken, or - capability SIDs are categorically prohibited as restricting SIDs.
The exact ERROR_INVALID_PARAMETER result on build 26300 is outside the published contract shown here.
TokenHasRestrictions versus a restricting-SID list
TokenHasRestrictions != 0 means that the token has ever been filtered. It does not mean that TokenRestrictedSids currently contains an entry.^4^
The narrower test is IsTokenRestricted:
- Nonzero only when the token contains a list of restricting SIDs.
- Zero when it has no restricting SIDs, even if it was created by
CreateRestrictedTokenand was filtered in other ways.^5^
Accordingly, an empty TokenRestrictedSids result is not evidence of an existing empty set participating in intersection. The documented intersection rule applies if the existing token is a restricted token, meaning it already has a restricting-SID list.^1^ Nothing in the documented contract says that UAC filtering history changes which SID authorities SidsToRestrict accepts.
Supported non-AppContainer design
For a WRITE_RESTRICTED worker, use an ordinary SID whose acceptance you have validated with CreateRestrictedToken, rather than relying on capability-SID behavior that is not documented for this API.
- Select a dedicated trustee SID for the worker restriction. Avoid Everyone for isolation: because Everyone represents all users, it does not identify the scratch boundary narrowly.^6^
- Pass that SID as the sole
SidsToRestrictentry withAttributes = 0, together withDISABLE_MAX_PRIVILEGE | WRITE_RESTRICTED. - On each scratch directory, configure the DACL so that:
- the worker’s normal enabled identity receives the required write rights; and
- the restricting SID independently receives those same write rights.
- Do not grant the restricting SID write access on protected inputs or other destinations.
- Query the returned token with
TokenRestrictedSidsand verify that the intended SID is actually present. - Run positive tests against scratch paths and negative create, overwrite, rename, delete, and directory-creation tests elsewhere.
This follows the restricted-token access model: Windows performs one check using the token’s enabled SIDs and another using its restricting SIDs, and grants access only when both checks permit it.^7^ With WRITE_RESTRICTED, the restricting SIDs are considered only while evaluating write access.^1^
Do not infer success from token creation alone. For the successful Everyone experiment, inspect TokenRestrictedSids; it determines whether the resulting token actually contains the requested restricting SID. Also run the worker on a desktop other than the default desktop, as Microsoft warns that restricted applications on the default desktop can attack unrestricted applications through window messaging.^7^
For a definitive support statement about the build-26300 rejection of S-1-15-3-1024-…, a minimal native reproducer should be submitted through Microsoft support. Include the exact derived SID, both arrays returned by DeriveCapabilitySidsFromName, source-token information, and the successful control call. The public API documentation does not specify that implementation boundary.
References