Skip to content

Release 26.9.0

Latest

Choose a tag to compare

@vladimir-litvinchik vladimir-litvinchik released this 13 Oct 09:07

This release updates the rendering engine to GroupDocs.Viewer 26.9.0 and fixes several security issues in the API, the local storage and cache, and the cloud storage providers. Upgrading is strongly recommended for every application where the viewer can be reached by users you do not fully trust.


🔒 Security fixes

Update all GroupDocs.Viewer.UI.* packages to 26.9.0. The fixes are spread across packages, so updating only some of them leaves the others open:

Issue Affected applications Fixed in
Files outside the storage folder could be read, listed, and overwritten AddLocalStorage(...) GroupDocs.Viewer.UI.Api.Local.Storage
Files outside the cache folder could be read through page resource requests, whatever the storage provider AddLocalCache(...) with HTML rendering (the default) GroupDocs.Viewer.UI.Api.Local.Cache, GroupDocs.Viewer.UI.Api
Blobs in other containers of the storage account could be read and written AddAzureBlobStorage(...) GroupDocs.Viewer.UI.Api.AzureBlob.Storage
File paths could change GroupDocs Cloud API requests AddCloudStorage(...), AddGroupDocsViewerCloudApi(...) GroupDocs.Viewer.UI.Api.Cloud.Storage, GroupDocs.Viewer.UI.Cloud.Api
Upload by URL could reach internal network addresses (server-side request forgery) EnableFileUpload = true (the default) GroupDocs.Viewer.UI.Api
RequireAuthorization() on MapGroupDocsViewerApi had no effect applications that protect the API with endpoint conventions GroupDocs.Viewer.UI.Api
Error messages exposed absolute paths on the server all GroupDocs.Viewer.UI.Api

Local storage keeps paths inside the storage folder

A crafted file or folder path, such as one with .. segments or an absolute path, could reach files outside the folder passed to AddLocalStorage. A client could open, list, or overwrite any file the application has access to. Every path received from the client is now resolved inside the storage folder:

  • A leading / (or \ on Windows) refers to the storage folder: /reports/q3.docx is <storage folder>/reports/q3.docx.
  • Paths that resolve outside the storage folder are rejected with UnauthorizedAccessException. The client receives "Access to the file or folder is denied."
  • Uploaded files are saved under their file name only. Any folder part of the name sent by the browser is ignored.

Local cache keeps entries inside the cache folder

The local cache builds its file paths from the document path and the page resource name. A crafted resource name could read files outside the cache folder, with any storage provider, and a rooted document path could make the cache create folders and write files outside it.

  • Cache keys must be plain file names, and every cache path is checked to stay inside the cache folder.
  • get-resource returns 404 Not Found for resource names that contain / or \. Resource names produced by the viewer never do.
  • Documents opened by a rooted path, such as /doc.pdf or C:\doc.pdf, are now cached in a sub-folder of the cache folder, so they are rendered again once. Cached entries for regular relative paths are reused as before.

Azure Blob Storage rejects .. in blob names

The Azure SDK resolves .. segments in blob names, so a file path with .. could read or write blobs in other containers of the same storage account. Paths with .. segments are now rejected with UnauthorizedAccessException.

The Amazon S3 storage rejects such paths too. Amazon S3 treats them as literal keys, but some S3-compatible services resolve them.

GroupDocs Cloud requests escape file paths

File paths were inserted into GroupDocs Cloud API URLs as is, so a path containing ?, #, or .. could change which storage or API route a request goes to. Each path segment is now URL-escaped, and paths with .. segments are rejected. As a side effect, files whose names contain #, ?, or % now open correctly.

Upload by URL reaches public internet addresses only

When a file is uploaded by URL, the server downloads it. Any address was accepted, including loopback, private networks, and cloud metadata endpoints, and the downloaded content could then be opened in the viewer.

  • Only public internet addresses are allowed. Loopback, private, link-local (such as 169.254.169.254), and other special-purpose ranges are refused. The address is checked when the connection is opened, so redirects and DNS tricks can't get around it.
  • Proxy settings (HTTP_PROXY, HTTPS_PROXY, the system proxy) are not used for these downloads.
  • The downloaded file can't be larger than the server's request body size limit, the same limit that applies when the file is uploaded directly (30,000,000 bytes by default in Kestrel and IIS).
  • Only http and https URLs are accepted.

Conventions on MapGroupDocsViewerApi apply to all API endpoints

MapGroupDocsViewerApi returned a builder that dropped every convention added to it, so .RequireAuthorization() left the API, and with it every document, open to anonymous users even when the UI required sign-in (#116). Conventions such as RequireAuthorization(), RequireCors(), or WithMetadata() now apply to all API endpoints.

To require signed-in users, protect both the UI and the API:

app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();

app.MapGroupDocsViewerUI(options =>
{
    options.UIPath = "/viewer";
    options.ApiEndpoint = "/viewer-api";
}).RequireAuthorization();

app.MapGroupDocsViewerApi(options =>
{
    options.ApiPath = "/viewer-api";
}).RequireAuthorization();

Error messages no longer expose server paths

The default IErrorMessageProvider returned exception messages unchanged, and file system errors contain absolute paths, for example the full path of the storage folder. File system errors now get generic messages, such as "File 'report.docx' was not found." or "Access to the file or folder is denied." All other messages, including those from the rendering engine, are unchanged. A custom IErrorMessageProvider still receives the original exception.

If you can't upgrade right away

  • Set config.EnableFileUpload = false to block both uploads and upload by URL.

  • Require authentication for every endpoint without authorization metadata, including the viewer API, with a fallback policy:

    builder.Services.AddAuthorization(options =>
        options.FallbackPolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build());

    The fallback policy also applies to your own endpoints, so mark the public ones with [AllowAnonymous] or .AllowAnonymous().

  • The path issues in the local storage, local cache, Azure Blob, and GroupDocs Cloud providers have no configuration workaround. Upgrade.


⚠️ Behavior changes

  • Rejected paths fail. Paths that leave the storage folder (local storage) or contain .. segments (Azure Blob, Amazon S3, GroupDocs Cloud) now return an error instead of a file. Paths returned by the file browser are not affected.
  • Upload by URL from internal addresses, or through a proxy, no longer works. Upload such files directly instead.
  • Larger URL uploads need a higher request body limit. Downloads above the request body size limit are refused. To allow larger files, raise the limit, for example with KestrelServerOptions.Limits.MaxRequestBodySize. The same setting applies to direct uploads.
  • New 400 Bad Request responses. Requests without a valid JSON body ("Request body is missing or is not valid JSON.") or without a file ("File is required.") used to fail with 500 Internal Server Error. The viewer UI never sends such requests.
  • RequireAuthorization() on MapGroupDocsViewerApi now takes effect. If your application calls it, anonymous API requests are now challenged in the same way as the UI.
  • No password prompt for missing files. A file that can't be found no longer opens the password dialog when its name contains "password".

🛠️ Other changes

Rendering engine updated to GroupDocs.Viewer 26.9.0

This is a bug-fix release of the engine with no public API changes, and its dependencies are the same as in 26.8.0. It fixes rendering of PPTX (missing characters in HTML, a crash when rendering PPT, a null reference exception on Linux), PDF to HTML (lost graphics, an incorrectly rendered footer graphic), CAD (the default font, rendering exceptions), TEX, EPS, IGS, and PS documents, and reduces stream reads when processing PDF files. See the GroupDocs.Viewer for .NET 26.9 release notes for details.

PSD, PSB, AI, and ONE documents are still not rendered by the cross-platform engine build, as described in the 26.8.0 release notes.

GroupDocs.Viewer.UI.SelfHost.Api.CrossPlatform is not updated

26.8.0 remains the final release of the deprecated package. It depends on GroupDocs.Viewer.UI.SelfHost.Api 26.8.0 or later, and NuGet resolves the lowest version that matches, so a project that references only the CrossPlatform package keeps getting 26.8.0 without the fixes above. Replace the reference, no code changes are needed:

-<PackageReference Include="GroupDocs.Viewer.UI.SelfHost.Api.CrossPlatform" Version="26.8.0" />
+<PackageReference Include="GroupDocs.Viewer.UI.SelfHost.Api" Version="26.9.0" />

📦 Packages

All GroupDocs.Viewer.UI packages are available on NuGet at version 26.9.0:


Thank you for using GroupDocs.Viewer.UI! If you encounter any issues or have suggestions, please don't hesitate to provide feedback here on GitHub or at our Free Support Forum.