CVE Patch Review

CVE-2026-53598: Prompty File Reference Sandbox Patch Review

CVE-2026-53598 · GHSA-WXHM-2MQ7-7697 · Updated 2026-07-18 Root-cause

Summary

The patch in Prompty 2.0.0-beta.2 changes ${file:...} expansion from unrestricted path resolution to an allowlisted root model anchored at the containing .prompty directory, with optional host-supplied extra roots. The implementation adds canonicalization and root-containment checks intended to block traversal, absolute-path reads, and symlink escapes described in the advisory and CVE.

Analysis

Vulnerability

CVE-2026-53598 and the corresponding GHSA advisory describe an arbitrary file read in Microsoft Prompty loaders before 2.0.0-beta.2. The vulnerable behavior was in frontmatter ${file:...} expansion: references were resolved by combining the supplied path with the prompt directory and calling path normalization, but without enforcing that the final target remained inside an approved filesystem boundary.

That design allowed three practical escape classes reflected in the patch tests and advisory context: directory traversal such as ../secret.txt, absolute paths, and symbolic-link based escapes. In the vulnerable code path, ResolveFileRef effectively trusted the resolved path after Path.GetFullPath, so any readable file reachable by the process could be injected into prompt metadata if the attacker controlled a .prompty file or its frontmatter references.

var fullPath = Path.GetFullPath(Path.Combine(parentDir, relativePath));

The README update in the patch also confirms the intended security boundary: ${file:...} is now documented as loading content from the prompt directory tree by default, not from arbitrary host paths. See the patch commit 88ac9948d7d37995edbb2f6d36913436626c39e1 and the CVE record at CVE.org.

Patch

The patch introduces an explicit allowlist model for file reference expansion. The containing prompt directory is always allowed, and host applications may add extra roots through the new PromptyLoadOptions.AllowedFileRoots API. The loader now threads these options into preprocessing so reference resolution has the context needed to enforce policy.

public sealed class PromptyLoadOptions
{
    public IEnumerable<string> AllowedFileRoots { get; init; } = [];
}

public static Prompty Load(string path, PromptyLoadOptions? options = null)

PreProcess = ReferenceResolver.CreatePreProcess(fullPath, options?.AllowedFileRoots),

In ReferenceResolver, the patch canonicalizes both the prompt path and allowed roots, resolves absolute and relative references, canonicalizes the final target, and rejects any target outside the allowlist using a relative-path containment check.

var allowedRoots = new[] { parentDir }
    .Concat(allowedFileRoots ?? [])
    .Select(GetCanonicalPath)
    .ToArray();

fullPath = GetCanonicalPath(fullPath);
if (!allowedRoots.Any(root => IsWithinRoot(fullPath, root)))
{
    throw new InvalidOperationException(
        $"File reference '{relativePath}' resolves outside allowed roots (resolved to '{fullPath}', key: '{key}').");
}

The tests added in the commit cover the key exploit modes: traversal outside the prompt directory, absolute-path reads, explicit host-approved shared roots, and symlink escapes. Version bumps from 2.0.0-beta.1 to 2.0.0-beta.2 in the affected C# packages align with the fixed release noted by the advisory.

Review

Pros

  • The patch addresses the core trust-boundary failure by moving from path normalization alone to policy enforcement on the resolved target path.
  • The default security posture is materially improved: the prompt's own directory becomes the implicit sandbox, and prompts cannot self-expand their privileges. That is reinforced by the README language in the patch commit 88ac9948....
  • Canonicalization via GetCanonicalPath is important because it attempts to collapse symlink indirection before the root check, directly targeting one of the documented bypass classes.
  • The API design is reasonable for embedders: additional access requires host-side opt-in through AllowedFileRoots, which preserves least privilege.
  • Regression coverage is strong for the disclosed issue classes. The new tests exercise traversal, absolute paths, symlink escape, and a positive case for explicitly allowed shared content.

Cons

  • The reviewable snippet for GetCanonicalPath is truncated, so the full behavior across platforms and edge cases cannot be completely validated from the provided source digest alone. The correctness of symlink handling depends heavily on that implementation detail.
  • The containment check uses Path.GetRelativePath semantics. While this is a standard approach, filesystem corner cases such as platform-specific case sensitivity, UNC/device path forms, or unusual link behavior deserve additional cross-platform tests beyond the current set.
  • The patch appears scoped to the C# runtime paths shown in the commit summary. If Prompty has other loaders or language runtimes with equivalent ${file:...} expansion logic, parity should be verified separately rather than assumed from this patch alone.
  • The exception message includes the resolved path and key name. That is useful for debugging, but in some embedding contexts it may disclose filesystem layout to callers if surfaced directly.

Verdict

Root-cause.

This patch appears to remediate the underlying flaw rather than merely filtering a subset of payloads. The vulnerable behavior was unrestricted file dereference during reference expansion; the fix introduces a canonicalized allowlist boundary and makes broader access an explicit host decision. Based on the commit, tests, and advisory context from GHSA-WXHM-2MQ7-7697 and NVD, the patch is technically aligned with the reported attack vectors and should block the disclosed arbitrary file read paths.

Recommended follow-up is to add platform-focused tests for symlink and path canonicalization behavior, and to confirm equivalent protections in any non-C# loaders if they exist in the product surface.

Sources