CVE-2026-53598: Prompty File Reference Sandbox Patch Review
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
GetCanonicalPathis 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
GetCanonicalPathis 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.GetRelativePathsemantics. 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.
Recommended Labs
Try this vulnerability pattern yourself with hands-on labs.
- Path Traversal.js
Best direct match for CVE-2026-53598 because the Prompty issue is a file-reference expansion flaw that enables arbitrary file read through traversal and path escaping. This lab is hands-on and defensive, focused on identifying and fixing path traversal patterns in JavaScript.
- Path Traversal II.js
A stronger follow-up lab for defence-in-depth. It is useful for practicing mitigations beyond simple input filtering, which fits this CVE's patch theme involving traversal, absolute-path handling, and escape prevention in file loading logic.
- Slipstream.js
Recommended because the CVE description explicitly mentions symbolic link escapes. This lab maps well to archive/file extraction and path-escape classes including symlink-related unsafe file handling, which helps build intuition for canonicalization and safe file boundary enforcement.