Skip to content

Path traversal in Export-User and Export-Role cmdlets #1448

@michaellwest

Description

@michaellwest

M7: Path Traversal in Export-User / Export-Role Cmdlets

Severity: MEDIUM
Category: Path Traversal / Arbitrary File Write
File: src/Spe/Commands/Serialization/ExportUserCommand.cs (line 106)
File: src/Spe/Commands/Serialization/ExportRoleCommand.cs (line 94)


Risk Explanation

Both Export-User and Export-Role cmdlets construct output file paths by concatenating the user-controlled Root parameter with a user/role reference:

var target = Root.EndsWith("\\") ? Root : Root + "\\";
Path = (target + roleReference).Replace('/', System.IO.Path.DirectorySeparatorChar);

There is no validation that Root points to an expected directory, the resulting Path stays within the intended location, or roleReference does not contain traversal sequences.

Attack scenarios:

  1. Arbitrary directory write via Root:

    Export-Role -Root "C:\inetpub\wwwroot\upload" -Identity "sitecore\Admin"
  2. Traversal via role/user name (if role names can contain path characters):

    Export-Role -Root "C:\Sitecore\Data" -Identity "sitecore\..\..\wwwroot\shell"

Who can exploit this: Any user with access to the SPE console or remoting who has permission to run these cmdlets.


Implementation Plan

Fix

  1. Canonicalize and validate the output path:

    var target = Root.EndsWith("\\") ? Root : Root + "\\";
    var rawPath = (target + roleReference).Replace('/', System.IO.Path.DirectorySeparatorChar);
    var canonicalPath = System.IO.Path.GetFullPath(rawPath);
    var canonicalRoot = System.IO.Path.GetFullPath(Root);
    
    if (!canonicalPath.StartsWith(canonicalRoot, StringComparison.OrdinalIgnoreCase))
    {
        WriteError(new ErrorRecord(
            new PSSecurityException($"Output path escapes the root directory: {canonicalPath}"),
            "PathTraversal", ErrorCategory.SecurityError, null));
        return;
    }
    
    Path = canonicalPath;
  2. Apply the same fix to both ExportUserCommand.cs and ExportRoleCommand.cs.

  3. Sanitize the role/user reference to remove path separator characters:

    var safeReference = roleReference
        .Replace("..", "")
        .Replace("/", "_")
        .Replace("\\", "_");

Files to modify

File Change
src/Spe/Commands/Serialization/ExportUserCommand.cs Add path canonicalization and boundary check
src/Spe/Commands/Serialization/ExportRoleCommand.cs Add path canonicalization and boundary check

Test Plan

  1. Unit test — traversal in role reference:

    [Test]
    public void ExportRole_RejectsTraversalInRoleName()
    {
        // Identity = "sitecore\..\..\wwwroot\evil"
        // Before fix: writes to C:\Sitecore\wwwroot\evil.yml (escaped Root)
        // After fix: error — path escapes root directory
    }
  2. Positive test — normal export works.

  3. Negative test — various traversal attempts rejected.

  4. Existing serialization tests pass.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions