From 61c2f5d10cecfa511154697ac9f51ed2c914403e Mon Sep 17 00:00:00 2001 From: mangod9 Date: Tue, 7 Jul 2026 22:38:28 -0700 Subject: [PATCH 1/4] Add TAR security guidance: link boundary validation, PAX extended attributes Adds security guidance to the ZIP/TAR best-practices article for handling untrusted TAR archives: - A note that destination boundary validation assumes the destination is a real directory the app controls; a junction/symlink destination (or parent) causes extraction to follow the link, even with TarFile.ExtractToDirectory. - A new section on PAX extended attributes and link names as untrusted, archive-supplied input that can override header fields. - Updated the untrusted-metadata checklist item to include link names and PAX extended attributes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/standard/io/zip-tar-best-practices.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/standard/io/zip-tar-best-practices.md b/docs/standard/io/zip-tar-best-practices.md index 93c0beab80dfa..98fb70a71544a 100644 --- a/docs/standard/io/zip-tar-best-practices.md +++ b/docs/standard/io/zip-tar-best-practices.md @@ -129,6 +129,9 @@ Key points: - The `StartsWith` check ensures the resolved path is still inside the destination. - The trailing directory separator on `fullDestDir` is critical—without it, a path like `/safe-dir-evil/file` would incorrectly match `/safe-dir`. +> [!NOTE] +> Boundary validation assumes the destination directory itself is a real directory you control. If the destination directory or one of its parents is already a junction or symbolic link, extraction follows that link and writes to the link's target—even with , which otherwise rejects entries and link targets that escape the destination. When handling untrusted archives, extract into a fresh, application-controlled directory rather than a reused or externally-writable location. + > [!WARNING] > The following APIs leave you completely unprotected against path traversal. You must validate paths yourself before calling them. @@ -248,6 +251,11 @@ Starting with .NET 11, the runtime validates ZIP CRC-32 values automatically whe - **Extra fields** are binary key-value pairs attached to each entry. The runtime preserves unknown extra fields and trailing data when reading and writing archives in mode and round-trips them as-is. If your application reads or interprets extra fields, validate their contents. - **Entry name encoding:** when writing, the runtime uses ASCII for entry names that contain only ASCII printable characters (32-126) and UTF-8 (with the language encoding flag set) for names that contain other characters. When reading without a custom encoding, entries with or without the language encoding flag are decoded as UTF-8 (which also correctly decodes ASCII). Use the `entryNameEncoding` parameter on to override encoding when needed, but be aware the override affects all entries uniformly. +### TAR extended attributes and link names + +- **PAX extended attributes** () are an arbitrary, archive-supplied set of key-value strings. A PAX entry can carry many attributes, and individual values can be large. The format also uses these attributes to override standard header fields such as the entry path, link name, and size. Treat them as untrusted input: if your application reads or acts on extended attributes, validate their contents and bound how many you process and how large they can be. +- **Link names** () on symbolic-link and hard-link entries are archive-supplied paths. Validate them the same way you validate entry names—see [Handle symbolic and hard links (TAR)](#handle-symbolic-and-hard-links-tar). + ## Encryption considerations (.NET 11+) .NET 11 adds support for reading and writing encrypted ZIP archives. The following subsections explain how to choose an encryption method, read encrypted entries, and use encrypted archives with the convenience APIs. @@ -337,7 +345,7 @@ Before deploying code that handles archives from untrusted sources, verify you'v - **Symlink/hardlink attacks (TAR):** Validate link targets resolve within the destination, or skip link entries entirely. - **Memory limits:** Avoid for large untrusted archives. Avoid mode with unseekable streams from untrusted sources. - **Thread safety:** Don't share , , or instances across threads. -- **Untrusted metadata:** Treat entry names, comments, and extra fields as untrusted input. Sanitize before display or processing. +- **Untrusted metadata:** Treat entry names, link names, comments, ZIP extra fields, and TAR PAX extended attributes as untrusted input. Validate and bound them before display or processing. - **Overwrite behavior:** Default to `overwrite: false`. - **Resource disposal:** Always dispose , , , and their streams. From b930651b83af50e69ce60838b3a6bf439395ad8d Mon Sep 17 00:00:00 2001 From: Manish Godse <61718172+mangod9@users.noreply.github.com> Date: Wed, 8 Jul 2026 11:44:34 -0700 Subject: [PATCH 2/4] Update docs/standard/io/zip-tar-best-practices.md Co-authored-by: Genevieve Warren <24882762+gewarren@users.noreply.github.com> --- docs/standard/io/zip-tar-best-practices.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/standard/io/zip-tar-best-practices.md b/docs/standard/io/zip-tar-best-practices.md index 98fb70a71544a..a5f6547c66967 100644 --- a/docs/standard/io/zip-tar-best-practices.md +++ b/docs/standard/io/zip-tar-best-practices.md @@ -130,7 +130,7 @@ Key points: - The trailing directory separator on `fullDestDir` is critical—without it, a path like `/safe-dir-evil/file` would incorrectly match `/safe-dir`. > [!NOTE] -> Boundary validation assumes the destination directory itself is a real directory you control. If the destination directory or one of its parents is already a junction or symbolic link, extraction follows that link and writes to the link's target—even with , which otherwise rejects entries and link targets that escape the destination. When handling untrusted archives, extract into a fresh, application-controlled directory rather than a reused or externally-writable location. +> Boundary validation assumes the destination directory itself is a real directory you control. If the destination directory or one of its parents is already a junction or symbolic link, extraction follows that link and writes to the link's target—even with , which otherwise rejects entries and link targets that escape the destination. When handling untrusted archives, extract into a fresh, application-controlled directory rather than a reused or externally writable location. > [!WARNING] > The following APIs leave you completely unprotected against path traversal. You must validate paths yourself before calling them. From 7eb1f39c79424324e7c889fd028b63406887123b Mon Sep 17 00:00:00 2001 From: mangod9 Date: Wed, 8 Jul 2026 11:52:37 -0700 Subject: [PATCH 3/4] Apply review feedback: clearer wording for metadata limits Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/standard/io/zip-tar-best-practices.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/standard/io/zip-tar-best-practices.md b/docs/standard/io/zip-tar-best-practices.md index a5f6547c66967..a5b61a96ed64e 100644 --- a/docs/standard/io/zip-tar-best-practices.md +++ b/docs/standard/io/zip-tar-best-practices.md @@ -253,7 +253,7 @@ Starting with .NET 11, the runtime validates ZIP CRC-32 values automatically whe ### TAR extended attributes and link names -- **PAX extended attributes** () are an arbitrary, archive-supplied set of key-value strings. A PAX entry can carry many attributes, and individual values can be large. The format also uses these attributes to override standard header fields such as the entry path, link name, and size. Treat them as untrusted input: if your application reads or acts on extended attributes, validate their contents and bound how many you process and how large they can be. +- **PAX extended attributes** () are an arbitrary, archive-supplied set of key-value strings. A PAX entry can carry many attributes, and individual values can be large. The format also uses these attributes to override standard header fields such as the entry path, link name, and size. Treat them as untrusted input: if your application reads or acts on extended attributes, validate their contents and set limits on how many you process and how large they can be. - **Link names** () on symbolic-link and hard-link entries are archive-supplied paths. Validate them the same way you validate entry names—see [Handle symbolic and hard links (TAR)](#handle-symbolic-and-hard-links-tar). ## Encryption considerations (.NET 11+) @@ -345,7 +345,7 @@ Before deploying code that handles archives from untrusted sources, verify you'v - **Symlink/hardlink attacks (TAR):** Validate link targets resolve within the destination, or skip link entries entirely. - **Memory limits:** Avoid for large untrusted archives. Avoid mode with unseekable streams from untrusted sources. - **Thread safety:** Don't share , , or instances across threads. -- **Untrusted metadata:** Treat entry names, link names, comments, ZIP extra fields, and TAR PAX extended attributes as untrusted input. Validate and bound them before display or processing. +- **Untrusted metadata:** Treat entry names, link names, comments, ZIP extra fields, and TAR PAX extended attributes as untrusted input. Validate them and set limits before display or processing. - **Overwrite behavior:** Default to `overwrite: false`. - **Resource disposal:** Always dispose , , , and their streams. From bb804fd9ad16a4559b2ebc2cbd3e567b6599aecc Mon Sep 17 00:00:00 2001 From: mangod9 Date: Wed, 8 Jul 2026 16:32:54 -0700 Subject: [PATCH 4/4] Address review: remove ExtractToDirectory reference from untrusted-archive note The note lives in the streaming/untrusted-input section, but referenced TarFile.ExtractToDirectory, which the article frames as a trusted-input convenience API. Reword to keep the note focused on manual boundary validation and avoid the inconsistency. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/standard/io/zip-tar-best-practices.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/standard/io/zip-tar-best-practices.md b/docs/standard/io/zip-tar-best-practices.md index a5b61a96ed64e..9c1b2e3de317e 100644 --- a/docs/standard/io/zip-tar-best-practices.md +++ b/docs/standard/io/zip-tar-best-practices.md @@ -130,7 +130,7 @@ Key points: - The trailing directory separator on `fullDestDir` is critical—without it, a path like `/safe-dir-evil/file` would incorrectly match `/safe-dir`. > [!NOTE] -> Boundary validation assumes the destination directory itself is a real directory you control. If the destination directory or one of its parents is already a junction or symbolic link, extraction follows that link and writes to the link's target—even with , which otherwise rejects entries and link targets that escape the destination. When handling untrusted archives, extract into a fresh, application-controlled directory rather than a reused or externally writable location. +> Boundary validation assumes the destination directory itself is a real directory you control. If the destination directory or one of its parents is already a junction or symbolic link, extraction follows that link and writes to the link's target, even when each entry's resolved path still appears to stay within the destination. When handling untrusted archives, extract into a fresh, application-controlled directory rather than a reused or externally writable location. > [!WARNING] > The following APIs leave you completely unprotected against path traversal. You must validate paths yourself before calling them.