Skip to content

Add Constrained Language Mode and token scoping for MCP remoting sessions #1419

@michaellwest

Description

@michaellwest

Summary

Enhance SPE's remoting endpoint security to support AI agent access via the SPE MCP Server. The MCP server implements client-side script sandboxing (AST analysis, allowlists, obfuscation detection — see mcp-server#13), but server-side defense-in-depth is needed to protect against bypasses.

Current State

  • Remoting sessions run in FullLanguage mode (ScriptSession.cs line 188: state.UseFullLanguageModeInDebugger = true)
  • No command blacklist/whitelist enforcement at the SPE level
  • No AST or token analysis before script execution in RemoteScriptCall.ashx.cs
  • JWT tokens carry minimal claims (iss, aud, exp, name) — no scope restrictions

Proposed Enhancements

1. Constrained Language Mode for Remoting (High Priority)

Add a configuration option to run remoting sessions in PowerShell Constrained Language Mode. This blocks at the engine level:

  • Invoke-Expression / iex
  • .NET type access ([System.Convert], [System.IO.File], etc.)
  • Add-Type (arbitrary C# compilation)
  • New-Object -ComObject (COM access)
  • [scriptblock]::Create() from strings
  • Arbitrary method invocation on .NET objects

Configuration in Spe.config:

<services>
  <remoting enabled="true" languageMode="ConstrainedLanguage" />
</services>

When languageMode="ConstrainedLanguage", set SessionState.LanguageMode = PSLanguageMode.ConstrainedLanguage on the runspace before executing remoting scripts.

Default: FullLanguage (backwards compatible). MCP server documentation would recommend ConstrainedLanguage.

2. Command Allowlist/Blocklist (Medium Priority)

Add server-side command filtering in Spe.config:

<remoting enabled="true">
  <commandRestrictions>
    <blockedCommands hint="list:AddBlockedCommand">
      <command>Remove-Item</command>
      <command>Remove-User</command>
      <command>Start-Process</command>
      <command>Invoke-WebRequest</command>
    </blockedCommands>
  </commandRestrictions>
</remoting>

Enforce in RemoteScriptCall.ashx.cs by parsing the script AST before execution and rejecting scripts that invoke blocked commands.

3. JWT Token Scoping (Lower Priority)

Extend SharedSecretAuthenticationProvider to support a scope claim in JWT tokens:

Scope Allowed
read-only Only Get-*, Find-*, Read-*, Search-*, Test-* commands
content-edit Read + content modification (Set-*, New-* on content items)
admin Unrestricted (current behavior)

Also add an mcp_session claim to tie tokens to specific MCP sessions for audit purposes.

Token validation change in SharedSecretAuthenticationProvider.cs:

  • Read scope claim after signature validation
  • Store scope in the session/context
  • Check scope against command being executed

See mcp-server#17 for the client-side counterpart.

4. Audit Logging for Remoting (Medium Priority)

Log all remoting script executions with:

  • Timestamp, authenticated user, source IP
  • Script content hash (not full script — avoid log bloat)
  • Execution result (success/error)
  • JWT claims (scope, session ID)

Write to Sitecore log via Log.Audit().

Impact

  • Backwards compatible: All features are opt-in via config. Default behavior unchanged.
  • No breaking changes: Existing remoting consumers (PowerShell module, CI/CD scripts) continue to work with FullLanguage mode.
  • MCP server alignment: The MCP server (mcp-server#13) provides client-side sandboxing. These SPE changes provide server-side defense-in-depth.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions