dotnet/wpf · error · FileFormatException

Resource_XpsPackageBoundaryViolation

Error message

Resource_XpsPackageBoundaryViolation

What it means

BitmapDecoder.CreateFromUriOrStream enforces XPS package containment: while an XPS document is loading, only URIs inside the current package may be resolved. If an absolute external URI is requested (a resource outside the package, potential SSRF), a FileFormatException with Resource_XpsPackageBoundaryViolation is thrown before any cache lookup.

Solutions

  1. Rewrite image references in the XPS to relative URIs pointing to parts inside the same package.
  2. Embed the image resources into the XPS package instead of linking to external locations.
  3. If external URIs are legitimate, resolve/load the images before entering the XPS loading context (or outside it).
  4. Catch FileFormatException and render a placeholder for untrusted external resources.

Example fix

// before
var dec = BitmapDecoder.Create(new Uri("http://cdn.example.com/img.png"), opts, cache); // during XPS load
// after
// embed the image as a package part and use a relative pack URI
var dec = BitmapDecoder.Create(packUriOfEmbeddedPart, opts, cache);
Defensive patterns

Strategy: validation

Validate before calling

static void EnsureUriInsidePackage(Uri finalUri, Uri packageBase)
{
    if (finalUri == null || !finalUri.IsAbsoluteUri) return;
    if (!finalUri.AbsolutePath.StartsWith(packageBase.AbsolutePath, StringComparison.Ordinal))
        throw new InvalidOperationException("URI escapes the XPS package boundary.");
}

Type guard

bool IsContained(Uri candidate) => candidate != null && (!candidate.IsAbsoluteUri || XpsLoadingContext.IsUriAllowedInCurrentContext(candidate));

Try / catch

try { decoder = BitmapDecoder.Create(uri, opts, cache); }
catch (FileFormatException ex) when (ex.Message.Contains("boundary") || ex.Message.Contains("package")) { RenderPlaceholder(); }

Prevention

When it happens

Trigger: Creating a BitmapDecoder from an absolute http:// or file:// URI (or a pack URI referencing another package) while an XPS loading context is active, when XpsLoadingContext.IsUriAllowedInCurrentContext rejects the URI.

Common situations: XPS documents referencing remote images; generated XPS containing absolute external image links; security-hardened environments blocking cross-package resource fetches.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/e1e7255af685368f. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Imaging/BitmapDecoder.cs:252

            UnmanagedMemoryStream unmanagedMemoryStream = null;
            SafeFileHandle safeFilehandle = null;

            if (uri != null)
            {
                finalUri = (baseUri != null) ?
                               System.Windows.Navigation.BaseUriHelper.GetResolvedUri(baseUri, uri) :
                               uri;

                // Security: When loading XPS content, block URIs that escape the
                // current package to prevent SSRF (outbound HTTP/NTLM requests via
                // attacker-controlled ImageSource attributes in XPS FixedPages).
                // This check runs before the cache lookup so that a previously-
                // cached external URI cannot bypass containment.
                if (finalUri != null
                    && finalUri.IsAbsoluteUri
                    && !XpsLoadingContext.IsUriAllowedInCurrentContext(finalUri))
                {
                    throw new FileFormatException(SR.Resource_XpsPackageBoundaryViolation);
                }

                if (insertInDecoderCache)
                {
                    if ((createOptions & BitmapCreateOptions.IgnoreImageCache) != 0)
                    {
                        ImagingCache.RemoveFromDecoderCache(finalUri);
                    }

                    cachedDecoder = CheckCache(
                        finalUri,
                        out clsId
                        );
                }
            }

            // try to retrieve the cached decoder
            if (cachedDecoder != null)

View on GitHub (pinned to 81131a70a4)