GroupDocs.Annotation for .NET 26.10 Release Notes
GroupDocs.Annotation for .NET 26.10 is a security-focused release.
- External resources are no longer loaded by default. Opening, previewing or saving a document no longer downloads the remote images, style sheets or linked files it references. New
LoadOptionsmembers let you allow specific hosts, inspect every request or restore the previous behaviour. This is a behaviour change — please read External resources are no longer loaded by default before upgrading. - The bundled document engines are updated to their October 2026 releases.
System.Security.Cryptography.Pkcsis raised to 8.0.2 (CVE-2026-84008, CVE-2026-70162).- Fixes:
- EML messages that could not be opened from a stream;
- documents annotated by old versions that could not be opened on .NET 8;
- presentations whose annotations could not be read back after re-saving;
- PDF pages that were not rotated by 90 degrees.
Full list of changes in this release
| Key | Category | Summary |
|---|---|---|
| ANNOTATIONNET-2663 | ⚠️ Enhancement | External resources are no longer loaded by default (new LoadOptions controls) |
| ANNOTATIONNET-2687 | ✨ Enhancement | Upgrade the underlying document engines |
| ANNOTATIONNET-2672 | 🔒 Security | Update System.Security.Cryptography.Pkcs to 8.0.2 (CVE-2026-84008 / CVE-2026-70162) |
| ANNOTATIONNET-2102 | 🔧 Fix | Fix FileTypeNotSupportedException when extracting annotations from EML documents |
| ANNOTATIONNET-1903 | 🔧 Fix | Fix documents annotated by older versions failing to open on .NET 8 |
| ANNOTATIONNET-2689 | 🔧 Fix | Fix PDF page rotation by 90 degrees being lost on save |
Behaviour Changes
External resources are no longer loaded by default
A document can reference resources outside itself, for example:
- an
<img src="https://...">in an HTML page or an e-mail body; - a linked (not embedded) picture in a Word document;
- a remote style sheet;
- an external workbook link.
Until now, opening, previewing or saving such a document made GroupDocs.Annotation request those resources from the network or from a file share. The caller had no way to switch this off.
On a server that processes untrusted documents, this is a server-side request forgery (SSRF) risk. A document can make the server request internal addresses such as cloud metadata endpoints or localhost services. A UNC path can also leak the Windows (NTLM) credentials of the process. The requests also break offline and air-gapped installations.
Starting with 26.10, external resources are skipped by default:
No requests.
Annotatormakes no network or file-share request for resources referenced by the document. This applies to every operation:Get,Add,Save,GeneratePreviewandGetDocumentInfo.Formats covered.
- Word-processing documents: DOCX, DOC, RTF, ODT and others.
- HTML documents.
- E-mail documents: EML, MSG and MHT.
- Presentations.
- Spreadsheets.
Skipped images. A skipped image is rendered as an empty (transparent) placeholder. The link itself is kept, so a saved document still references the original image.
What counts as external. These are all treated as external and skipped:
- absolute URLs, such as
http(s)://,ftp://andfile://; - UNC paths and protocol-relative URLs (
//host/...); - rooted local paths.
Resources stored inside the document are always loaded, for example
cid:parts of an e-mail,data:URIs and embedded pictures.- absolute URLs, such as
Image annotations are not affected.
ImageAnnotation.ImagePathis a resource you specify yourself, not one the document references, so it is still loaded from a URL. The library also no longer installs a process-wideServicePointManager.ServerCertificateValidationCallbackwhen it downloads that image. Standard certificate validation applies, and your application’s own callback is left untouched.
Action required. If your documents rely on remote images or style sheets being rendered (in previews or in saved output), allow them explicitly with the new LoadOptions members:
| Member | Default | Description |
|---|---|---|
LoadOptions.SkipExternalResources | true | Skip external resources referenced by the document. Set it to false to restore the pre-26.10 behaviour. |
LoadOptions.WhitelistedResources | empty | Resources loaded even when SkipExternalResources is true. Each entry is a host name, or an absolute URI prefix. |
LoadOptions.ExternalResourceHandler | null | Called for every external resource before it is loaded. The handler can allow it, skip it, or supply its content. |
A WhitelistedResources entry matches as follows:
- Host name, for example
"example.com". It matches that host and its subdomains. - Absolute URI prefix, for example
"https://cdn.example.com/images/".- The scheme, host and port must match exactly, so
https://a.comdoes not admithttps://a.com.evil.net. - The path matches only on a segment boundary, so
/imagesadmits/images/x.pngbut not/images-private/x.png.
- The scheme, host and port must match exactly, so
Allow trusted hosts only (recommended):
LoadOptions loadOptions = new LoadOptions
{
// SkipExternalResources stays true (the default)
WhitelistedResources = { "cdn.example.com", "https://intranet.example.com/images/" }
};
using (Annotator annotator = new Annotator("input.html", loadOptions))
{
annotator.Save("output.html"); // only images from the two whitelisted locations are loaded
}
Inspect, allow or substitute each resource with a handler:
class AuditingResourceHandler : ExternalResourceHandler
{
public override void OnLoading(ExternalResourceLoadingArgs args)
{
// args.Skipped is pre-set from SkipExternalResources and WhitelistedResources
Console.WriteLine($"{args.Uri}: {(args.Skipped ? "skipped" : "loaded")}");
// serve a local copy instead of going to the network
if (args.Uri == "https://example.com/logo.png")
args.Data = File.ReadAllBytes("logo.png");
}
}
using (Annotator annotator = new Annotator("input.docx", new LoadOptions { ExternalResourceHandler = new AuditingResourceHandler() }))
{
annotator.Document.GeneratePreview(new PreviewOptions(pageNumber => File.Create($"page_{pageNumber}.png")));
}
Restore the previous behaviour (not recommended for untrusted documents):
using (Annotator annotator = new Annotator("input.eml", new LoadOptions { SkipExternalResources = false }))
{
annotator.Save("output.eml");
}
Enhancements
Upgrade the underlying document engines
The bundled document engines have been updated to their latest (October 2026) releases. These include the word-processing, spreadsheet, presentation, PDF, diagram, e-mail, imaging, CAD and graphics rendering engines.
Note: As with every engine upgrade, regenerated documents and page previews may differ slightly at the byte or pixel level while remaining visually equivalent. For example, the PDF engine now re-encodes embedded images, and the word-processing engine may write a non-breaking space where it previously wrote a regular one. If your pipeline compares output byte-for-byte against stored baselines, refresh those baselines after upgrading.
Note for .NET 6 and .NET 8 projects: the runtime packages now depend on SkiaSharp 4.152.1 (previously 3.119.0). If your project references SkiaSharp 3.x directly, update it to 4.x. Several
Microsoft.Extensions.*andSystem.*dependencies have moved to their 10.x versions. On .NET 6 these packages may report that .NET 6 is not a supported target framework. The warning does not affect GroupDocs.Annotation, which is tested on .NET 6.
Security
Update System.Security.Cryptography.Pkcs to 8.0.2
The engines bring in System.Security.Cryptography.Pkcs 8.0.0 or 8.0.1, which are affected by CVE-2026-84008 and CVE-2026-70162. GroupDocs.Annotation now references the patched 8.0.2 directly on every target framework. On .NET 6 the matching System.Formats.Asn1 8.0.2 is also referenced. No code changes are required.
Fixes
Fix FileTypeNotSupportedException when extracting annotations from EML documents
An EML message whose first line is MIME-Version: 1.0 was detected as an MHT web archive. Opening it from a stream therefore threw FileTypeNotSupportedException. The same message opened from a file path worked. MIME documents are now handled as e-mail, so the message opens the same way from a stream and from a file. As a side effect, MHT (.mht) files are now supported and are processed as e-mail documents.
using (Stream stream = File.OpenRead("message.eml"))
using (Annotator annotator = new Annotator(stream)) // previously threw FileTypeNotSupportedException
{
var annotations = annotator.Get();
}
Fix documents annotated by older versions failing to open on .NET 8
Versions before 26.6 stored annotations inside the document using .NET BinaryFormatter, which is disabled on .NET 8. On the .NET 8 build, the Annotator constructor threw NotSupportedException for such a document. A typical example is a DOCX annotated by an older version and then saved as PDF. The document could not be opened at all, not even to add new annotations.
The document now opens on .NET 8:
- Legacy annotations are skipped. The annotations written by the old version are ignored on .NET 8, and a warning is written to the log.
- New annotations work. You can add new annotations and save the document as usual.
- Saving drops the legacy annotations. Saving replaces the old annotation data. If you need to keep, edit or export those annotations, process the document on the .NET 6 or .NET Framework build, which still reads them, and save it there once. After that, the annotations are stored as XML and are readable on every framework.
Annotations written by 26.6 and later are not affected.
This release also fixes a related problem with presentations (PPTX) on all frameworks. Re-saving a presentation whose annotation data had become shorter left fragments of the previous data in the file. Its annotations could then not be read back.
// input.pdf carries annotations written by a pre-26.6 version
using (Annotator annotator = new Annotator("input.pdf")) // .NET 8: previously threw NotSupportedException
{
annotator.Add(new AreaAnnotation { Box = new Rectangle(100, 100, 100, 100), PageNumber = 0 });
annotator.Save("output.pdf");
}
Fix PDF page rotation by 90 degrees being lost on save
Rotating a PDF page with Annotator.Rotation and Annotator.ProcessPages worked for 180 and 270 degrees, but a 90-degree rotation had no effect. The page was saved unrotated, because the rotation was reset while the annotations were being placed. The requested rotation is now kept for every angle, and annotations on the page are positioned as before.
using (Annotator annotator = new Annotator("input.pdf"))
{
annotator.ProcessPages = 1; // the page to rotate
annotator.Rotation = RotationDocument.on90; // previously ignored
annotator.Save("output.pdf");
}
Public API changes
Added:
GroupDocs.Annotation.Options.LoadOptions.SkipExternalResources(bool, defaulttrue)GroupDocs.Annotation.Options.LoadOptions.WhitelistedResources(List<string>)GroupDocs.Annotation.Options.LoadOptions.ExternalResourceHandler(ExternalResourceHandler)GroupDocs.Annotation.Options.ExternalResourceHandler, a class withvirtual void OnLoading(ExternalResourceLoadingArgs args)GroupDocs.Annotation.Options.ExternalResourceLoadingArgs, with the membersUri,SkippedandData
No public members were removed or changed.