Why can I bypass JEA VisibleExternalCommands restrictions?

Adam Kerrison 0 Reputation points
2026-11-06T12:43:31.6366667+00:00

I have a question about JEA restrictions on executables (VisibleExternalCommands).

I've setup a JEA endpoint (SessionType = Default) which allows a subset of cmdlets and executables, specifically only one executable:

VisibleExternalCommands = 'C:\Windows\System32\whoami.exe'

In normal usage the restrictions are applied. For example, netstat is not allowed:

User's image

However, I can easily escape these restrictions using the call operator, for exampleUser's image

Why is allowed? Surely such a simple escape from the restrictions is a security hole and renders VisibleExternalCommands a bit useless?

Windows for business | Windows Server | User experience | PowerShell
0 comments No comments

3 answers

Sort by: Oldest
  1. AI answer

    2026-11-06T12:45:09.1833333+00:00

    Replace SessionType = 'Default' with SessionType = 'RestrictedRemoteServer'; Default permits PowerShell language features such as script blocks, so VisibleExternalCommands alone cannot provide a secure command boundary.

    VisibleExternalCommands controls which executables are exposed as commands, but your endpoint still permits & { netstat } to invoke a script block. A proper JEA endpoint uses RestrictedRemoteServer, which runs in NoLanguage mode and limits users to command invocation without scripts or variables.^1^ ^2^

    Correct the endpoint

    Run the endpoint-management commands from an elevated PowerShell session.

    1. Open the original .pssc file used to register the endpoint.
    2. Change this setting:
    SessionType = 'RestrictedRemoteServer'
    
    1. Preserve the existing RoleDefinitions, run-as identity, transcript directory, and other endpoint settings. For example, the relevant portions should resemble:
    @{
        SessionType = 'RestrictedRemoteServer'
        RunAsVirtualAccount = $true
    
        RoleDefinitions = @{
            'CONTOSO\JEAUsers' = @{
                RoleCapabilities = 'WhoAmIRole'
            }
        }
    
        TranscriptDirectory = 'C:\ProgramData\JEA\Transcripts'
    }
    
    1. Validate the complete file, then register it under a temporary name so the existing endpoint remains available during testing:
    Test-PSSessionConfigurationFile -Path C:\ProgramData\JEA\WhoAmI.pssc
    
    Register-PSSessionConfiguration `
        -Name WhoAmI-Restricted `
        -Path C:\ProgramData\JEA\WhoAmI.pssc
    
    Get-PSSessionConfiguration -Name WhoAmI-Restricted
    

    If rebuilding the role, WhoAmIRole.psrc must be stored in a RoleCapabilities directory inside a valid PowerShell module located under a path in $env:PSModulePath. Give the role capability a unique filename because JEA’s search order is not deterministic when duplicate names exist.^1^

    Before cutover, inspect the effective commands assigned to the intended user:

    Get-PSSessionCapability `
        -ConfigurationName WhoAmI-Restricted `
        -Username 'CONTOSO\JEAUser'
    

    Then connect to the temporary endpoint and test:

    Enter-PSSession -ComputerName localhost `
        -ConfigurationName WhoAmI-Restricted
    
    whoami.exe
    netstat.exe
    & { netstat.exe }
    

    Expected results:

    • whoami.exe succeeds.
    • Direct netstat.exe fails because it is not visible.
    • & { netstat.exe } fails because script-block syntax is unavailable in NoLanguage mode.

    After validation, migrate clients to the new endpoint or replace the old registration during a controlled change.

    Tighten the role capability

    Keep the complete executable path:

    VisibleExternalCommands = @(
        'C:\Windows\System32\whoami.exe'
    )
    

    Microsoft recommends using constrained cmdlets or functions instead of external executables where possible because JEA can restrict cmdlet/function parameters and values, while an executable’s arguments cannot be constrained as granularly.^3^

    Also review the effective role for commands that can escape the boundary, particularly:

    • Start-Process, Invoke-Expression, or other arbitrary execution mechanisms.
    • Commands that create new runspaces, including *-Job.
    • Writable FileSystem-provider access.
    • Trace-Command and commands that modify type or format data.

    These are specifically identified as risks for restricted JEA endpoints.^4^

    The observed behavior is therefore a consequence of using a normal Default session as the endpoint foundation, rather than a failure of the VisibleExternalCommands list itself.


    References

    1. JEA Session Configurations
    2. about_Language_Modes
    3. JEA Role Capabilities
    4. JEA Security Considerations
    AI-generated content may be incorrect. Read our transparency notes for more information.

    Was this answer helpful?

  2. Marcin Policht 112.4K Reputation points MVP Volunteer Moderator
    2026-11-06T13:23:41.3166667+00:00

    The issue is that SessionType = 'Default' allows PowerShell language features, including script blocks. As a result, VisibleExternalCommands alone does not enforce a sufficiently restrictive command-execution environment.

    To address this, change:

    SessionType = 'Default'
    

    to:

    SessionType = 'RestrictedRemoteServer'
    

    RestrictedRemoteServer runs in NoLanguage mode, preventing users from executing general PowerShell expressions, defining variables, or running script blocks. This closes the specific bypass you described.

    Retain your executable restriction:

    VisibleExternalCommands = @(
        'C:\Windows\System32\whoami.exe'
    )
    

    Register a separate endpoint for validation before replacing the existing one:

    Test-PSSessionConfigurationFile `
        -Path C:\ProgramData\JEA\WhoAmI.pssc
    
    Register-PSSessionConfiguration `
        -Name WhoAmI-Restricted `
        -Path C:\ProgramData\JEA\WhoAmI.pssc
    

    Connect to the new endpoint and verify that only the permitted executable runs:

    whoami.exe
    net.exe
    & { Get-Process }
    

    The first command should succeed; the other two should be rejected.

    Btw.RestrictedRemoteServer provides stronger language restrictions, but the exposed role capabilities must still be reviewed for commands that could facilitate arbitrary execution or create additional runspaces. For enforcement beyond the PowerShell session, consider AppLocker or Windows Defender Application Control


    If the above response helps answer your question, remember to "Accept Answer" so that others in the community facing similar issues can easily find the solution. Your contribution is highly appreciated.

    hth

    Marcin

    Was this answer helpful?

    0 comments No comments

  3. Adam Kerrison 0 Reputation points
    2026-11-06T13:33:59.5233333+00:00

    I thought that might be the case. Sadly don't think we can use RestrictedRemoteServer as the usage needs access to things like if conditions, loop etc.

    I'll have to investigate the LanguageMode setting I think

    Was this answer helpful?

    0 comments No comments

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.