dotnet/wpf · error · FileFormatException
SR.Resource_XpsPackageBoundaryViolation
Error message
SR.Resource_XpsPackageBoundaryViolation
What it means
FontSource.GetUnmanagedStream enforces an XPS package-boundary security check: when loading XPS content, font URIs must resolve inside the current XPS package. A non-file URI that XpsLoadingContext.IsUriAllowedAgainstPackage rejects is blocked with FileFormatException(SR.Resource_XpsPackageBoundaryViolation) to prevent SSRF — a font reference inside a document must not point at an external resource.
Solutions
- Fix the XPS document so all font part URIs are relative and resolve within the same package.
- Re-generate the document with a compliant XPS producer that never emits external font references.
- If the URI is trusted, load the font from a local file/stream instead of relying on the XPS package path.
- Catch FileFormatException and surface a clear 'untrusted document resource' error to the user.
Example fix
// before (in .xps FixedPage markup) <FontUri Source="http://evil.example.com/mal.ttf" /> // after <FontUri Source="/Resources/Fonts/1-0.ttf" />
Defensive patterns
Strategy: validation
Validate before calling
if (!fontUri.IsFile && !XpsLoadingContext.IsUriAllowedAgainstPackage(xpsPackageOrigin, fontUri))
throw new FileFormatException("Font URI escapes the XPS package."); Try / catch
try { stream = fontSource.GetUnmanagedStream(); }
catch (FileFormatException ex) when (ex.Message.Contains("PackageBoundary") || ex.Data.Count >= 0) { /* reject document */ } Prevention
- Use package-relative font URIs in XPS documents.
- Never reference http(s) or cross-package fonts inside XPS.
- Scan untrusted XPS documents for external resource URIs before loading.
- Catch FileFormatException and reject the document.
When it happens
Trigger: Opening an XPS document whose font part URI escapes the containing package — e.g. a pack URI referencing another package (http://, or pack URI for a different package) instead of a resource within the same XPS file, evaluated during deferred font loading.
Common situations: Malicious or hand-edited XPS documents referencing remote fonts; documents produced by tools writing absolute URIs instead of package-relative ones; a package origin/context mismatch where the stored XPS package origin no longer matches the font URI at load time.
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
- Resource_XpsPackageBoundaryViolation
- Resource_XpsPackageBoundaryViolation
- SR.Resource_XpsPackageBoundaryViolation
- SR.Resource_XpsPackageBoundaryViolation
- SR.Resource_XpsPackageBoundaryViolation
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/099785013027a624.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/FontCache/FontSource.cs:191
}
if (bits == null)
{
Stream fontStream;
if (_isInternalCompositeFont)
{
// We should read this font from our framework resources
fontStream = GetCompositeFontResourceStream();
}
else
{
// Security: When loading XPS content, block font URIs that escape
// the current package to prevent SSRF. Uses stored origin to
// handle deferred loading after XPS parse context has ended.
if (!_fontUri.IsFile && !XpsLoadingContext.IsUriAllowedAgainstPackage(_xpsPackageOrigin, _fontUri))
{
throw new FileFormatException(SR.Resource_XpsPackageBoundaryViolation);
}
WebResponse response = WpfWebRequestHelper.CreateRequestAndGetResponse(_fontUri);
fontStream = response.GetResponseStream();
if (string.Equals(response.ContentType, ObfuscatedContentType, StringComparison.Ordinal))
{
// The third parameter makes sure the original stream is closed
// when the deobfuscating stream is disposed.
fontStream = new DeobfuscatingStream(fontStream, _fontUri, false);
}
}
// We don't want any memory leaks
// TODO: Remove FinalizableUnmanagedStream once FontFileStream is migrated from C++/CLI.
if (fontStream is UnmanagedMemoryStream unmanagedMemoryStream)
return new FinalizableUnmanagedStream(unmanagedMemoryStream);
// Convert the DeobfuscatingStream to byte[]; add it to our cache, dispose itView on GitHub (pinned to 81131a70a4)