Solve symlinks destination - #129281

Merged
alinpahontu2912 merged 9 commits into
dotnet:mainfrom
alinpahontu2912:symlink_resolution
Jul 3, 2026
Merged

Solve symlinks destination #129281
alinpahontu2912 merged 9 commits into
dotnet:mainfrom
alinpahontu2912:symlink_resolution

Conversation

@alinpahontu2912

Copy link
Copy Markdown
Member

Evaluate symlinks destination properly

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-system-formats-tar
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR tightens System.Formats.Tar extraction safety by validating that computed extraction destinations (including link destinations) don’t escape the intended destination directory once filesystem symlinks are taken into account, and adds tests intended to cover symlink-based directory traversal scenarios.

Changes:

  • Add a symlink-aware escape check (FilePathEscapesDirectory) during destination and link path validation in TarEntry.
  • Extend extraction validation to reject entries whose resolved destinations would traverse outside the destination directory.
  • Add new extraction tests covering symlink traversal attempts (including chained symlinks).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

FileDescription
src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.csAdds symlink-aware escape validation for extraction destination paths and link destinations.
src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectory.File.Tests.csAdds new tests intended to validate rejection of symlink-based directory traversal during extraction.

Comment threadsrc/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs Outdated

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(holding for offline feedback)

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like it's providing a guarantee we do not intend to provide.

There needs to be a prominent code comment to echo the Remarks section at https://learn.microsoft.com/en-us/dotnet/api/system.formats.tar.tarfile.extracttodirectory:

This is only intended to guard against the case where both:

  1. a symlink tries to break out of the destination folder; and
  2. the symlink is introduced by an entry within the archive.

No specific defenses are intended for the case where a symlink already exists in the destination folder, as the destination folder is assumed trustworthy. (See also: https://github.com/dotnet/core/blob/main/Documentation/security-foundations/baseline-security-assumptions.md#23-the-command-line-is-trusted-as-a-control-plane-mechanism)

CopilotAI review requested due to automatic review settings June 26, 2026 09:16

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

Comment threadsrc/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs Outdated
Comment threadsrc/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs Outdated

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment as proposed on line 418 is still misleading.

The comment needs to clearly state that we intend to defend this ONLY WHEN a directory-escaping symlink is introduced by the archive itself. We do not intend to defend other scenarios, including when preexisting symlinks on disk link outside the destination directory.

Note: Nothing stops you from blocking preexisting-symlink scenarios if you decide you no longer want to follow them. For example, maybe this is the easiest way to also block the "hostile symlink within an archive" scenario. (Though currently your public docs say you follow existing symlinks, so this would be a breaking change.)

The crux of my comment is that we absolutely cannot have any comment or behavior which can be misinterpreted as "we intend to defend against hostile symlinks already on disk." If we want to make a behavioral change to how we interpret preexisting symlinks, that's totally fine, but a reader or future maintainer must be able to easily understand that we're not trying to offer a defense specifically against existing hostile symlinks.

CopilotAI review requested due to automatic review settings July 1, 2026 07:13

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My concerns are addressed. Thanks. :)

@GrabYourPitchforks
GrabYourPitchforks dismissed their stale reviewJuly 2, 2026 17:07

Removing block.

@alinpahontu2912
alinpahontu2912 merged commit 710da3b into dotnet:mainJul 3, 2026
86 of 88 checks passed
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview7 milestone Jul 4, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
Evaluate symlinks destination properly
richlander added a commit to richlander/dotnet-install that referenced this pull request Jul 18, 2026
Adversarial review noted that TarFile.ExtractToDirectory does not reject
chained-symlink traversal on all supported runtimes (the physical
symlink-containment fix, dotnet/runtime#129281, is not present in the
preview this repo currently builds against). A malicious tar could create
a symlink to an outside directory then write a file through it, escaping
the extraction directory before payload validation runs.
Walk the tar entries explicitly instead: reject any link/device/fifo entry
(a single-file tool payload never contains them), and independently contain
each entry's resolved path within the extraction directory rather than
trusting the runtime. Windows keeps ZipFile.ExtractToDirectory.
Adds tests for symlink-entry rejection and the chained-symlink escape.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 93b4a21a-2d53-4208-9078-2643c540666a
richlander added a commit to richlander/dotnet-install that referenced this pull request Jul 18, 2026
* Extract release archives with managed APIs to prevent tar-slip
The github-release update path extracted downloaded assets by shelling
out to `tar -xzf`, which honors entries containing `../` and can write
files outside the extraction directory (tar-slip / path traversal) from
an attacker-controlled release asset.
Replace the external `tar` call with managed extraction via
System.Formats.Tar.TarFile over a GZipStream (and ZipFile on Windows),
both of which reject entries that escape the destination directory.
Factored into a testable TryExtractReleaseArchive helper.
Adds tests covering rejection of a tar-slip entry and successful
extraction of a legitimate tarball.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 93b4a21a-2d53-4208-9078-2643c540666a
* Harden tar extraction against symlink escape and untrusted runtimes
Adversarial review noted that TarFile.ExtractToDirectory does not reject
chained-symlink traversal on all supported runtimes (the physical
symlink-containment fix, dotnet/runtime#129281, is not present in the
preview this repo currently builds against). A malicious tar could create
a symlink to an outside directory then write a file through it, escaping
the extraction directory before payload validation runs.
Walk the tar entries explicitly instead: reject any link/device/fifo entry
(a single-file tool payload never contains them), and independently contain
each entry's resolved path within the extraction directory rather than
trusting the runtime. Windows keeps ZipFile.ExtractToDirectory.
Adds tests for symlink-entry rejection and the chained-symlink escape.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 93b4a21a-2d53-4208-9078-2643c540666a
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Aug 4, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@alinpahontu2912@GrabYourPitchforks@am11@rzikm@iremyux
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Solve symlinks destination - #129281

Merged
alinpahontu2912 merged 9 commits into
dotnet:mainfrom
alinpahontu2912:symlink_resolution
Jul 3, 2026
Merged

Solve symlinks destination #129281
alinpahontu2912 merged 9 commits into
dotnet:mainfrom
alinpahontu2912:symlink_resolution

Conversation

@alinpahontu2912

Copy link
Copy Markdown
Member

Evaluate symlinks destination properly

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-system-formats-tar
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR tightens System.Formats.Tar extraction safety by validating that computed extraction destinations (including link destinations) don’t escape the intended destination directory once filesystem symlinks are taken into account, and adds tests intended to cover symlink-based directory traversal scenarios.

Changes:

  • Add a symlink-aware escape check (FilePathEscapesDirectory) during destination and link path validation in TarEntry.
  • Extend extraction validation to reject entries whose resolved destinations would traverse outside the destination directory.
  • Add new extraction tests covering symlink traversal attempts (including chained symlinks).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

FileDescription
src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.csAdds symlink-aware escape validation for extraction destination paths and link destinations.
src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectory.File.Tests.csAdds new tests intended to validate rejection of symlink-based directory traversal during extraction.

Comment threadsrc/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs Outdated

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(holding for offline feedback)

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like it's providing a guarantee we do not intend to provide.

There needs to be a prominent code comment to echo the Remarks section at https://learn.microsoft.com/en-us/dotnet/api/system.formats.tar.tarfile.extracttodirectory:

This is only intended to guard against the case where both:

  1. a symlink tries to break out of the destination folder; and
  2. the symlink is introduced by an entry within the archive.

No specific defenses are intended for the case where a symlink already exists in the destination folder, as the destination folder is assumed trustworthy. (See also: https://github.com/dotnet/core/blob/main/Documentation/security-foundations/baseline-security-assumptions.md#23-the-command-line-is-trusted-as-a-control-plane-mechanism)

CopilotAI review requested due to automatic review settings June 26, 2026 09:16

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

Comment threadsrc/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs Outdated
Comment threadsrc/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs Outdated

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment as proposed on line 418 is still misleading.

The comment needs to clearly state that we intend to defend this ONLY WHEN a directory-escaping symlink is introduced by the archive itself. We do not intend to defend other scenarios, including when preexisting symlinks on disk link outside the destination directory.

Note: Nothing stops you from blocking preexisting-symlink scenarios if you decide you no longer want to follow them. For example, maybe this is the easiest way to also block the "hostile symlink within an archive" scenario. (Though currently your public docs say you follow existing symlinks, so this would be a breaking change.)

The crux of my comment is that we absolutely cannot have any comment or behavior which can be misinterpreted as "we intend to defend against hostile symlinks already on disk." If we want to make a behavioral change to how we interpret preexisting symlinks, that's totally fine, but a reader or future maintainer must be able to easily understand that we're not trying to offer a defense specifically against existing hostile symlinks.

CopilotAI review requested due to automatic review settings July 1, 2026 07:13

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My concerns are addressed. Thanks. :)

@GrabYourPitchforks
GrabYourPitchforks dismissed their stale reviewJuly 2, 2026 17:07

Removing block.

@alinpahontu2912
alinpahontu2912 merged commit 710da3b into dotnet:mainJul 3, 2026
86 of 88 checks passed
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview7 milestone Jul 4, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
Evaluate symlinks destination properly
richlander added a commit to richlander/dotnet-install that referenced this pull request Jul 18, 2026
Adversarial review noted that TarFile.ExtractToDirectory does not reject
chained-symlink traversal on all supported runtimes (the physical
symlink-containment fix, dotnet/runtime#129281, is not present in the
preview this repo currently builds against). A malicious tar could create
a symlink to an outside directory then write a file through it, escaping
the extraction directory before payload validation runs.
Walk the tar entries explicitly instead: reject any link/device/fifo entry
(a single-file tool payload never contains them), and independently contain
each entry's resolved path within the extraction directory rather than
trusting the runtime. Windows keeps ZipFile.ExtractToDirectory.
Adds tests for symlink-entry rejection and the chained-symlink escape.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 93b4a21a-2d53-4208-9078-2643c540666a
richlander added a commit to richlander/dotnet-install that referenced this pull request Jul 18, 2026
* Extract release archives with managed APIs to prevent tar-slip
The github-release update path extracted downloaded assets by shelling
out to `tar -xzf`, which honors entries containing `../` and can write
files outside the extraction directory (tar-slip / path traversal) from
an attacker-controlled release asset.
Replace the external `tar` call with managed extraction via
System.Formats.Tar.TarFile over a GZipStream (and ZipFile on Windows),
both of which reject entries that escape the destination directory.
Factored into a testable TryExtractReleaseArchive helper.
Adds tests covering rejection of a tar-slip entry and successful
extraction of a legitimate tarball.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 93b4a21a-2d53-4208-9078-2643c540666a
* Harden tar extraction against symlink escape and untrusted runtimes
Adversarial review noted that TarFile.ExtractToDirectory does not reject
chained-symlink traversal on all supported runtimes (the physical
symlink-containment fix, dotnet/runtime#129281, is not present in the
preview this repo currently builds against). A malicious tar could create
a symlink to an outside directory then write a file through it, escaping
the extraction directory before payload validation runs.
Walk the tar entries explicitly instead: reject any link/device/fifo entry
(a single-file tool payload never contains them), and independently contain
each entry's resolved path within the extraction directory rather than
trusting the runtime. Windows keeps ZipFile.ExtractToDirectory.
Adds tests for symlink-entry rejection and the chained-symlink escape.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 93b4a21a-2d53-4208-9078-2643c540666a
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Aug 4, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@alinpahontu2912@GrabYourPitchforks@am11@rzikm@iremyux
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Solve symlinks destination - #129281

Merged
alinpahontu2912 merged 9 commits into
dotnet:mainfrom
alinpahontu2912:symlink_resolution
Jul 3, 2026
Merged

Solve symlinks destination #129281
alinpahontu2912 merged 9 commits into
dotnet:mainfrom
alinpahontu2912:symlink_resolution

Conversation

@alinpahontu2912

Copy link
Copy Markdown
Member

Evaluate symlinks destination properly

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-system-formats-tar
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR tightens System.Formats.Tar extraction safety by validating that computed extraction destinations (including link destinations) don’t escape the intended destination directory once filesystem symlinks are taken into account, and adds tests intended to cover symlink-based directory traversal scenarios.

Changes:

  • Add a symlink-aware escape check (FilePathEscapesDirectory) during destination and link path validation in TarEntry.
  • Extend extraction validation to reject entries whose resolved destinations would traverse outside the destination directory.
  • Add new extraction tests covering symlink traversal attempts (including chained symlinks).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

FileDescription
src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.csAdds symlink-aware escape validation for extraction destination paths and link destinations.
src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectory.File.Tests.csAdds new tests intended to validate rejection of symlink-based directory traversal during extraction.

Comment threadsrc/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs Outdated

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(holding for offline feedback)

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like it's providing a guarantee we do not intend to provide.

There needs to be a prominent code comment to echo the Remarks section at https://learn.microsoft.com/en-us/dotnet/api/system.formats.tar.tarfile.extracttodirectory:

This is only intended to guard against the case where both:

  1. a symlink tries to break out of the destination folder; and
  2. the symlink is introduced by an entry within the archive.

No specific defenses are intended for the case where a symlink already exists in the destination folder, as the destination folder is assumed trustworthy. (See also: https://github.com/dotnet/core/blob/main/Documentation/security-foundations/baseline-security-assumptions.md#23-the-command-line-is-trusted-as-a-control-plane-mechanism)

CopilotAI review requested due to automatic review settings June 26, 2026 09:16

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

Comment threadsrc/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs Outdated
Comment threadsrc/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs Outdated

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment as proposed on line 418 is still misleading.

The comment needs to clearly state that we intend to defend this ONLY WHEN a directory-escaping symlink is introduced by the archive itself. We do not intend to defend other scenarios, including when preexisting symlinks on disk link outside the destination directory.

Note: Nothing stops you from blocking preexisting-symlink scenarios if you decide you no longer want to follow them. For example, maybe this is the easiest way to also block the "hostile symlink within an archive" scenario. (Though currently your public docs say you follow existing symlinks, so this would be a breaking change.)

The crux of my comment is that we absolutely cannot have any comment or behavior which can be misinterpreted as "we intend to defend against hostile symlinks already on disk." If we want to make a behavioral change to how we interpret preexisting symlinks, that's totally fine, but a reader or future maintainer must be able to easily understand that we're not trying to offer a defense specifically against existing hostile symlinks.

CopilotAI review requested due to automatic review settings July 1, 2026 07:13

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My concerns are addressed. Thanks. :)

@GrabYourPitchforks
GrabYourPitchforks dismissed their stale reviewJuly 2, 2026 17:07

Removing block.

@alinpahontu2912
alinpahontu2912 merged commit 710da3b into dotnet:mainJul 3, 2026
86 of 88 checks passed
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview7 milestone Jul 4, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
Evaluate symlinks destination properly
richlander added a commit to richlander/dotnet-install that referenced this pull request Jul 18, 2026
Adversarial review noted that TarFile.ExtractToDirectory does not reject
chained-symlink traversal on all supported runtimes (the physical
symlink-containment fix, dotnet/runtime#129281, is not present in the
preview this repo currently builds against). A malicious tar could create
a symlink to an outside directory then write a file through it, escaping
the extraction directory before payload validation runs.
Walk the tar entries explicitly instead: reject any link/device/fifo entry
(a single-file tool payload never contains them), and independently contain
each entry's resolved path within the extraction directory rather than
trusting the runtime. Windows keeps ZipFile.ExtractToDirectory.
Adds tests for symlink-entry rejection and the chained-symlink escape.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 93b4a21a-2d53-4208-9078-2643c540666a
richlander added a commit to richlander/dotnet-install that referenced this pull request Jul 18, 2026
* Extract release archives with managed APIs to prevent tar-slip
The github-release update path extracted downloaded assets by shelling
out to `tar -xzf`, which honors entries containing `../` and can write
files outside the extraction directory (tar-slip / path traversal) from
an attacker-controlled release asset.
Replace the external `tar` call with managed extraction via
System.Formats.Tar.TarFile over a GZipStream (and ZipFile on Windows),
both of which reject entries that escape the destination directory.
Factored into a testable TryExtractReleaseArchive helper.
Adds tests covering rejection of a tar-slip entry and successful
extraction of a legitimate tarball.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 93b4a21a-2d53-4208-9078-2643c540666a
* Harden tar extraction against symlink escape and untrusted runtimes
Adversarial review noted that TarFile.ExtractToDirectory does not reject
chained-symlink traversal on all supported runtimes (the physical
symlink-containment fix, dotnet/runtime#129281, is not present in the
preview this repo currently builds against). A malicious tar could create
a symlink to an outside directory then write a file through it, escaping
the extraction directory before payload validation runs.
Walk the tar entries explicitly instead: reject any link/device/fifo entry
(a single-file tool payload never contains them), and independently contain
each entry's resolved path within the extraction directory rather than
trusting the runtime. Windows keeps ZipFile.ExtractToDirectory.
Adds tests for symlink-entry rejection and the chained-symlink escape.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 93b4a21a-2d53-4208-9078-2643c540666a
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Aug 4, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@alinpahontu2912@GrabYourPitchforks@am11@rzikm@iremyux
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Solve symlinks destination - #129281

Merged
alinpahontu2912 merged 9 commits into
dotnet:mainfrom
alinpahontu2912:symlink_resolution
Jul 3, 2026
Merged

Solve symlinks destination #129281
alinpahontu2912 merged 9 commits into
dotnet:mainfrom
alinpahontu2912:symlink_resolution

Conversation

@alinpahontu2912

Copy link
Copy Markdown
Member

Evaluate symlinks destination properly

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-system-formats-tar
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR tightens System.Formats.Tar extraction safety by validating that computed extraction destinations (including link destinations) don’t escape the intended destination directory once filesystem symlinks are taken into account, and adds tests intended to cover symlink-based directory traversal scenarios.

Changes:

  • Add a symlink-aware escape check (FilePathEscapesDirectory) during destination and link path validation in TarEntry.
  • Extend extraction validation to reject entries whose resolved destinations would traverse outside the destination directory.
  • Add new extraction tests covering symlink traversal attempts (including chained symlinks).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

FileDescription
src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.csAdds symlink-aware escape validation for extraction destination paths and link destinations.
src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectory.File.Tests.csAdds new tests intended to validate rejection of symlink-based directory traversal during extraction.

Comment threadsrc/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs Outdated

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(holding for offline feedback)

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like it's providing a guarantee we do not intend to provide.

There needs to be a prominent code comment to echo the Remarks section at https://learn.microsoft.com/en-us/dotnet/api/system.formats.tar.tarfile.extracttodirectory:

This is only intended to guard against the case where both:

  1. a symlink tries to break out of the destination folder; and
  2. the symlink is introduced by an entry within the archive.

No specific defenses are intended for the case where a symlink already exists in the destination folder, as the destination folder is assumed trustworthy. (See also: https://github.com/dotnet/core/blob/main/Documentation/security-foundations/baseline-security-assumptions.md#23-the-command-line-is-trusted-as-a-control-plane-mechanism)

CopilotAI review requested due to automatic review settings June 26, 2026 09:16

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

Comment threadsrc/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs Outdated
Comment threadsrc/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs Outdated

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment as proposed on line 418 is still misleading.

The comment needs to clearly state that we intend to defend this ONLY WHEN a directory-escaping symlink is introduced by the archive itself. We do not intend to defend other scenarios, including when preexisting symlinks on disk link outside the destination directory.

Note: Nothing stops you from blocking preexisting-symlink scenarios if you decide you no longer want to follow them. For example, maybe this is the easiest way to also block the "hostile symlink within an archive" scenario. (Though currently your public docs say you follow existing symlinks, so this would be a breaking change.)

The crux of my comment is that we absolutely cannot have any comment or behavior which can be misinterpreted as "we intend to defend against hostile symlinks already on disk." If we want to make a behavioral change to how we interpret preexisting symlinks, that's totally fine, but a reader or future maintainer must be able to easily understand that we're not trying to offer a defense specifically against existing hostile symlinks.

CopilotAI review requested due to automatic review settings July 1, 2026 07:13

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My concerns are addressed. Thanks. :)

@GrabYourPitchforks
GrabYourPitchforks dismissed their stale reviewJuly 2, 2026 17:07

Removing block.

@alinpahontu2912
alinpahontu2912 merged commit 710da3b into dotnet:mainJul 3, 2026
86 of 88 checks passed
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview7 milestone Jul 4, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
Evaluate symlinks destination properly
richlander added a commit to richlander/dotnet-install that referenced this pull request Jul 18, 2026
Adversarial review noted that TarFile.ExtractToDirectory does not reject
chained-symlink traversal on all supported runtimes (the physical
symlink-containment fix, dotnet/runtime#129281, is not present in the
preview this repo currently builds against). A malicious tar could create
a symlink to an outside directory then write a file through it, escaping
the extraction directory before payload validation runs.
Walk the tar entries explicitly instead: reject any link/device/fifo entry
(a single-file tool payload never contains them), and independently contain
each entry's resolved path within the extraction directory rather than
trusting the runtime. Windows keeps ZipFile.ExtractToDirectory.
Adds tests for symlink-entry rejection and the chained-symlink escape.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 93b4a21a-2d53-4208-9078-2643c540666a
richlander added a commit to richlander/dotnet-install that referenced this pull request Jul 18, 2026
* Extract release archives with managed APIs to prevent tar-slip
The github-release update path extracted downloaded assets by shelling
out to `tar -xzf`, which honors entries containing `../` and can write
files outside the extraction directory (tar-slip / path traversal) from
an attacker-controlled release asset.
Replace the external `tar` call with managed extraction via
System.Formats.Tar.TarFile over a GZipStream (and ZipFile on Windows),
both of which reject entries that escape the destination directory.
Factored into a testable TryExtractReleaseArchive helper.
Adds tests covering rejection of a tar-slip entry and successful
extraction of a legitimate tarball.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 93b4a21a-2d53-4208-9078-2643c540666a
* Harden tar extraction against symlink escape and untrusted runtimes
Adversarial review noted that TarFile.ExtractToDirectory does not reject
chained-symlink traversal on all supported runtimes (the physical
symlink-containment fix, dotnet/runtime#129281, is not present in the
preview this repo currently builds against). A malicious tar could create
a symlink to an outside directory then write a file through it, escaping
the extraction directory before payload validation runs.
Walk the tar entries explicitly instead: reject any link/device/fifo entry
(a single-file tool payload never contains them), and independently contain
each entry's resolved path within the extraction directory rather than
trusting the runtime. Windows keeps ZipFile.ExtractToDirectory.
Adds tests for symlink-entry rejection and the chained-symlink escape.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 93b4a21a-2d53-4208-9078-2643c540666a
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Aug 4, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@alinpahontu2912@GrabYourPitchforks@am11@rzikm@iremyux
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Solve symlinks destination - #129281

Merged
alinpahontu2912 merged 9 commits into
dotnet:mainfrom
alinpahontu2912:symlink_resolution
Jul 3, 2026
Merged

Solve symlinks destination #129281
alinpahontu2912 merged 9 commits into
dotnet:mainfrom
alinpahontu2912:symlink_resolution

Conversation

@alinpahontu2912

Copy link
Copy Markdown
Member

Evaluate symlinks destination properly

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-system-formats-tar
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR tightens System.Formats.Tar extraction safety by validating that computed extraction destinations (including link destinations) don’t escape the intended destination directory once filesystem symlinks are taken into account, and adds tests intended to cover symlink-based directory traversal scenarios.

Changes:

  • Add a symlink-aware escape check (FilePathEscapesDirectory) during destination and link path validation in TarEntry.
  • Extend extraction validation to reject entries whose resolved destinations would traverse outside the destination directory.
  • Add new extraction tests covering symlink traversal attempts (including chained symlinks).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

FileDescription
src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.csAdds symlink-aware escape validation for extraction destination paths and link destinations.
src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectory.File.Tests.csAdds new tests intended to validate rejection of symlink-based directory traversal during extraction.

Comment threadsrc/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs Outdated

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(holding for offline feedback)

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like it's providing a guarantee we do not intend to provide.

There needs to be a prominent code comment to echo the Remarks section at https://learn.microsoft.com/en-us/dotnet/api/system.formats.tar.tarfile.extracttodirectory:

This is only intended to guard against the case where both:

  1. a symlink tries to break out of the destination folder; and
  2. the symlink is introduced by an entry within the archive.

No specific defenses are intended for the case where a symlink already exists in the destination folder, as the destination folder is assumed trustworthy. (See also: https://github.com/dotnet/core/blob/main/Documentation/security-foundations/baseline-security-assumptions.md#23-the-command-line-is-trusted-as-a-control-plane-mechanism)

CopilotAI review requested due to automatic review settings June 26, 2026 09:16

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

Comment threadsrc/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs Outdated
Comment threadsrc/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs Outdated

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment as proposed on line 418 is still misleading.

The comment needs to clearly state that we intend to defend this ONLY WHEN a directory-escaping symlink is introduced by the archive itself. We do not intend to defend other scenarios, including when preexisting symlinks on disk link outside the destination directory.

Note: Nothing stops you from blocking preexisting-symlink scenarios if you decide you no longer want to follow them. For example, maybe this is the easiest way to also block the "hostile symlink within an archive" scenario. (Though currently your public docs say you follow existing symlinks, so this would be a breaking change.)

The crux of my comment is that we absolutely cannot have any comment or behavior which can be misinterpreted as "we intend to defend against hostile symlinks already on disk." If we want to make a behavioral change to how we interpret preexisting symlinks, that's totally fine, but a reader or future maintainer must be able to easily understand that we're not trying to offer a defense specifically against existing hostile symlinks.

CopilotAI review requested due to automatic review settings July 1, 2026 07:13

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My concerns are addressed. Thanks. :)

@GrabYourPitchforks
GrabYourPitchforks dismissed their stale reviewJuly 2, 2026 17:07

Removing block.

@alinpahontu2912
alinpahontu2912 merged commit 710da3b into dotnet:mainJul 3, 2026
86 of 88 checks passed
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview7 milestone Jul 4, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
Evaluate symlinks destination properly
richlander added a commit to richlander/dotnet-install that referenced this pull request Jul 18, 2026
Adversarial review noted that TarFile.ExtractToDirectory does not reject
chained-symlink traversal on all supported runtimes (the physical
symlink-containment fix, dotnet/runtime#129281, is not present in the
preview this repo currently builds against). A malicious tar could create
a symlink to an outside directory then write a file through it, escaping
the extraction directory before payload validation runs.
Walk the tar entries explicitly instead: reject any link/device/fifo entry
(a single-file tool payload never contains them), and independently contain
each entry's resolved path within the extraction directory rather than
trusting the runtime. Windows keeps ZipFile.ExtractToDirectory.
Adds tests for symlink-entry rejection and the chained-symlink escape.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 93b4a21a-2d53-4208-9078-2643c540666a
richlander added a commit to richlander/dotnet-install that referenced this pull request Jul 18, 2026
* Extract release archives with managed APIs to prevent tar-slip
The github-release update path extracted downloaded assets by shelling
out to `tar -xzf`, which honors entries containing `../` and can write
files outside the extraction directory (tar-slip / path traversal) from
an attacker-controlled release asset.
Replace the external `tar` call with managed extraction via
System.Formats.Tar.TarFile over a GZipStream (and ZipFile on Windows),
both of which reject entries that escape the destination directory.
Factored into a testable TryExtractReleaseArchive helper.
Adds tests covering rejection of a tar-slip entry and successful
extraction of a legitimate tarball.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 93b4a21a-2d53-4208-9078-2643c540666a
* Harden tar extraction against symlink escape and untrusted runtimes
Adversarial review noted that TarFile.ExtractToDirectory does not reject
chained-symlink traversal on all supported runtimes (the physical
symlink-containment fix, dotnet/runtime#129281, is not present in the
preview this repo currently builds against). A malicious tar could create
a symlink to an outside directory then write a file through it, escaping
the extraction directory before payload validation runs.
Walk the tar entries explicitly instead: reject any link/device/fifo entry
(a single-file tool payload never contains them), and independently contain
each entry's resolved path within the extraction directory rather than
trusting the runtime. Windows keeps ZipFile.ExtractToDirectory.
Adds tests for symlink-entry rejection and the chained-symlink escape.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 93b4a21a-2d53-4208-9078-2643c540666a
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Aug 4, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@alinpahontu2912@GrabYourPitchforks@am11@rzikm@iremyux
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Solve symlinks destination - #129281

Merged
alinpahontu2912 merged 9 commits into
dotnet:mainfrom
alinpahontu2912:symlink_resolution
Jul 3, 2026
Merged

Solve symlinks destination #129281
alinpahontu2912 merged 9 commits into
dotnet:mainfrom
alinpahontu2912:symlink_resolution

Conversation

@alinpahontu2912

Copy link
Copy Markdown
Member

Evaluate symlinks destination properly

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-system-formats-tar
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR tightens System.Formats.Tar extraction safety by validating that computed extraction destinations (including link destinations) don’t escape the intended destination directory once filesystem symlinks are taken into account, and adds tests intended to cover symlink-based directory traversal scenarios.

Changes:

  • Add a symlink-aware escape check (FilePathEscapesDirectory) during destination and link path validation in TarEntry.
  • Extend extraction validation to reject entries whose resolved destinations would traverse outside the destination directory.
  • Add new extraction tests covering symlink traversal attempts (including chained symlinks).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

FileDescription
src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.csAdds symlink-aware escape validation for extraction destination paths and link destinations.
src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectory.File.Tests.csAdds new tests intended to validate rejection of symlink-based directory traversal during extraction.

Comment threadsrc/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs Outdated

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(holding for offline feedback)

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like it's providing a guarantee we do not intend to provide.

There needs to be a prominent code comment to echo the Remarks section at https://learn.microsoft.com/en-us/dotnet/api/system.formats.tar.tarfile.extracttodirectory:

This is only intended to guard against the case where both:

  1. a symlink tries to break out of the destination folder; and
  2. the symlink is introduced by an entry within the archive.

No specific defenses are intended for the case where a symlink already exists in the destination folder, as the destination folder is assumed trustworthy. (See also: https://github.com/dotnet/core/blob/main/Documentation/security-foundations/baseline-security-assumptions.md#23-the-command-line-is-trusted-as-a-control-plane-mechanism)

CopilotAI review requested due to automatic review settings June 26, 2026 09:16

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

Comment threadsrc/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs Outdated
Comment threadsrc/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs Outdated

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment as proposed on line 418 is still misleading.

The comment needs to clearly state that we intend to defend this ONLY WHEN a directory-escaping symlink is introduced by the archive itself. We do not intend to defend other scenarios, including when preexisting symlinks on disk link outside the destination directory.

Note: Nothing stops you from blocking preexisting-symlink scenarios if you decide you no longer want to follow them. For example, maybe this is the easiest way to also block the "hostile symlink within an archive" scenario. (Though currently your public docs say you follow existing symlinks, so this would be a breaking change.)

The crux of my comment is that we absolutely cannot have any comment or behavior which can be misinterpreted as "we intend to defend against hostile symlinks already on disk." If we want to make a behavioral change to how we interpret preexisting symlinks, that's totally fine, but a reader or future maintainer must be able to easily understand that we're not trying to offer a defense specifically against existing hostile symlinks.

CopilotAI review requested due to automatic review settings July 1, 2026 07:13

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My concerns are addressed. Thanks. :)

@GrabYourPitchforks
GrabYourPitchforks dismissed their stale reviewJuly 2, 2026 17:07

Removing block.

@alinpahontu2912
alinpahontu2912 merged commit 710da3b into dotnet:mainJul 3, 2026
86 of 88 checks passed
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview7 milestone Jul 4, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
Evaluate symlinks destination properly
richlander added a commit to richlander/dotnet-install that referenced this pull request Jul 18, 2026
Adversarial review noted that TarFile.ExtractToDirectory does not reject
chained-symlink traversal on all supported runtimes (the physical
symlink-containment fix, dotnet/runtime#129281, is not present in the
preview this repo currently builds against). A malicious tar could create
a symlink to an outside directory then write a file through it, escaping
the extraction directory before payload validation runs.
Walk the tar entries explicitly instead: reject any link/device/fifo entry
(a single-file tool payload never contains them), and independently contain
each entry's resolved path within the extraction directory rather than
trusting the runtime. Windows keeps ZipFile.ExtractToDirectory.
Adds tests for symlink-entry rejection and the chained-symlink escape.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 93b4a21a-2d53-4208-9078-2643c540666a
richlander added a commit to richlander/dotnet-install that referenced this pull request Jul 18, 2026
* Extract release archives with managed APIs to prevent tar-slip
The github-release update path extracted downloaded assets by shelling
out to `tar -xzf`, which honors entries containing `../` and can write
files outside the extraction directory (tar-slip / path traversal) from
an attacker-controlled release asset.
Replace the external `tar` call with managed extraction via
System.Formats.Tar.TarFile over a GZipStream (and ZipFile on Windows),
both of which reject entries that escape the destination directory.
Factored into a testable TryExtractReleaseArchive helper.
Adds tests covering rejection of a tar-slip entry and successful
extraction of a legitimate tarball.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 93b4a21a-2d53-4208-9078-2643c540666a
* Harden tar extraction against symlink escape and untrusted runtimes
Adversarial review noted that TarFile.ExtractToDirectory does not reject
chained-symlink traversal on all supported runtimes (the physical
symlink-containment fix, dotnet/runtime#129281, is not present in the
preview this repo currently builds against). A malicious tar could create
a symlink to an outside directory then write a file through it, escaping
the extraction directory before payload validation runs.
Walk the tar entries explicitly instead: reject any link/device/fifo entry
(a single-file tool payload never contains them), and independently contain
each entry's resolved path within the extraction directory rather than
trusting the runtime. Windows keeps ZipFile.ExtractToDirectory.
Adds tests for symlink-entry rejection and the chained-symlink escape.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 93b4a21a-2d53-4208-9078-2643c540666a
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Aug 4, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@alinpahontu2912@GrabYourPitchforks@am11@rzikm@iremyux
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Solve symlinks destination - #129281

Merged
alinpahontu2912 merged 9 commits into
dotnet:mainfrom
alinpahontu2912:symlink_resolution
Jul 3, 2026
Merged

Solve symlinks destination #129281
alinpahontu2912 merged 9 commits into
dotnet:mainfrom
alinpahontu2912:symlink_resolution

Conversation

@alinpahontu2912

Copy link
Copy Markdown
Member

Evaluate symlinks destination properly

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-system-formats-tar
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR tightens System.Formats.Tar extraction safety by validating that computed extraction destinations (including link destinations) don’t escape the intended destination directory once filesystem symlinks are taken into account, and adds tests intended to cover symlink-based directory traversal scenarios.

Changes:

  • Add a symlink-aware escape check (FilePathEscapesDirectory) during destination and link path validation in TarEntry.
  • Extend extraction validation to reject entries whose resolved destinations would traverse outside the destination directory.
  • Add new extraction tests covering symlink traversal attempts (including chained symlinks).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

FileDescription
src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.csAdds symlink-aware escape validation for extraction destination paths and link destinations.
src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectory.File.Tests.csAdds new tests intended to validate rejection of symlink-based directory traversal during extraction.

Comment threadsrc/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs Outdated

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(holding for offline feedback)

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like it's providing a guarantee we do not intend to provide.

There needs to be a prominent code comment to echo the Remarks section at https://learn.microsoft.com/en-us/dotnet/api/system.formats.tar.tarfile.extracttodirectory:

This is only intended to guard against the case where both:

  1. a symlink tries to break out of the destination folder; and
  2. the symlink is introduced by an entry within the archive.

No specific defenses are intended for the case where a symlink already exists in the destination folder, as the destination folder is assumed trustworthy. (See also: https://github.com/dotnet/core/blob/main/Documentation/security-foundations/baseline-security-assumptions.md#23-the-command-line-is-trusted-as-a-control-plane-mechanism)

CopilotAI review requested due to automatic review settings June 26, 2026 09:16

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

Comment threadsrc/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs Outdated
Comment threadsrc/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs Outdated

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment as proposed on line 418 is still misleading.

The comment needs to clearly state that we intend to defend this ONLY WHEN a directory-escaping symlink is introduced by the archive itself. We do not intend to defend other scenarios, including when preexisting symlinks on disk link outside the destination directory.

Note: Nothing stops you from blocking preexisting-symlink scenarios if you decide you no longer want to follow them. For example, maybe this is the easiest way to also block the "hostile symlink within an archive" scenario. (Though currently your public docs say you follow existing symlinks, so this would be a breaking change.)

The crux of my comment is that we absolutely cannot have any comment or behavior which can be misinterpreted as "we intend to defend against hostile symlinks already on disk." If we want to make a behavioral change to how we interpret preexisting symlinks, that's totally fine, but a reader or future maintainer must be able to easily understand that we're not trying to offer a defense specifically against existing hostile symlinks.

CopilotAI review requested due to automatic review settings July 1, 2026 07:13

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My concerns are addressed. Thanks. :)

@GrabYourPitchforks
GrabYourPitchforks dismissed their stale reviewJuly 2, 2026 17:07

Removing block.

@alinpahontu2912
alinpahontu2912 merged commit 710da3b into dotnet:mainJul 3, 2026
86 of 88 checks passed
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview7 milestone Jul 4, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
Evaluate symlinks destination properly
richlander added a commit to richlander/dotnet-install that referenced this pull request Jul 18, 2026
Adversarial review noted that TarFile.ExtractToDirectory does not reject
chained-symlink traversal on all supported runtimes (the physical
symlink-containment fix, dotnet/runtime#129281, is not present in the
preview this repo currently builds against). A malicious tar could create
a symlink to an outside directory then write a file through it, escaping
the extraction directory before payload validation runs.
Walk the tar entries explicitly instead: reject any link/device/fifo entry
(a single-file tool payload never contains them), and independently contain
each entry's resolved path within the extraction directory rather than
trusting the runtime. Windows keeps ZipFile.ExtractToDirectory.
Adds tests for symlink-entry rejection and the chained-symlink escape.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 93b4a21a-2d53-4208-9078-2643c540666a
richlander added a commit to richlander/dotnet-install that referenced this pull request Jul 18, 2026
* Extract release archives with managed APIs to prevent tar-slip
The github-release update path extracted downloaded assets by shelling
out to `tar -xzf`, which honors entries containing `../` and can write
files outside the extraction directory (tar-slip / path traversal) from
an attacker-controlled release asset.
Replace the external `tar` call with managed extraction via
System.Formats.Tar.TarFile over a GZipStream (and ZipFile on Windows),
both of which reject entries that escape the destination directory.
Factored into a testable TryExtractReleaseArchive helper.
Adds tests covering rejection of a tar-slip entry and successful
extraction of a legitimate tarball.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 93b4a21a-2d53-4208-9078-2643c540666a
* Harden tar extraction against symlink escape and untrusted runtimes
Adversarial review noted that TarFile.ExtractToDirectory does not reject
chained-symlink traversal on all supported runtimes (the physical
symlink-containment fix, dotnet/runtime#129281, is not present in the
preview this repo currently builds against). A malicious tar could create
a symlink to an outside directory then write a file through it, escaping
the extraction directory before payload validation runs.
Walk the tar entries explicitly instead: reject any link/device/fifo entry
(a single-file tool payload never contains them), and independently contain
each entry's resolved path within the extraction directory rather than
trusting the runtime. Windows keeps ZipFile.ExtractToDirectory.
Adds tests for symlink-entry rejection and the chained-symlink escape.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 93b4a21a-2d53-4208-9078-2643c540666a
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Aug 4, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@alinpahontu2912@GrabYourPitchforks@am11@rzikm@iremyux
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Solve symlinks destination - #129281

Merged
alinpahontu2912 merged 9 commits into
dotnet:mainfrom
alinpahontu2912:symlink_resolution
Jul 3, 2026
Merged

Solve symlinks destination #129281
alinpahontu2912 merged 9 commits into
dotnet:mainfrom
alinpahontu2912:symlink_resolution

Conversation

@alinpahontu2912

Copy link
Copy Markdown
Member

Evaluate symlinks destination properly

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-system-formats-tar
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR tightens System.Formats.Tar extraction safety by validating that computed extraction destinations (including link destinations) don’t escape the intended destination directory once filesystem symlinks are taken into account, and adds tests intended to cover symlink-based directory traversal scenarios.

Changes:

  • Add a symlink-aware escape check (FilePathEscapesDirectory) during destination and link path validation in TarEntry.
  • Extend extraction validation to reject entries whose resolved destinations would traverse outside the destination directory.
  • Add new extraction tests covering symlink traversal attempts (including chained symlinks).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

FileDescription
src/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.csAdds symlink-aware escape validation for extraction destination paths and link destinations.
src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectory.File.Tests.csAdds new tests intended to validate rejection of symlink-based directory traversal during extraction.

Comment threadsrc/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs Outdated

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(holding for offline feedback)

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like it's providing a guarantee we do not intend to provide.

There needs to be a prominent code comment to echo the Remarks section at https://learn.microsoft.com/en-us/dotnet/api/system.formats.tar.tarfile.extracttodirectory:

This is only intended to guard against the case where both:

  1. a symlink tries to break out of the destination folder; and
  2. the symlink is introduced by an entry within the archive.

No specific defenses are intended for the case where a symlink already exists in the destination folder, as the destination folder is assumed trustworthy. (See also: https://github.com/dotnet/core/blob/main/Documentation/security-foundations/baseline-security-assumptions.md#23-the-command-line-is-trusted-as-a-control-plane-mechanism)

CopilotAI review requested due to automatic review settings June 26, 2026 09:16

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

Comment threadsrc/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs Outdated
Comment threadsrc/libraries/System.Formats.Tar/src/System/Formats/Tar/TarEntry.cs Outdated

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment as proposed on line 418 is still misleading.

The comment needs to clearly state that we intend to defend this ONLY WHEN a directory-escaping symlink is introduced by the archive itself. We do not intend to defend other scenarios, including when preexisting symlinks on disk link outside the destination directory.

Note: Nothing stops you from blocking preexisting-symlink scenarios if you decide you no longer want to follow them. For example, maybe this is the easiest way to also block the "hostile symlink within an archive" scenario. (Though currently your public docs say you follow existing symlinks, so this would be a breaking change.)

The crux of my comment is that we absolutely cannot have any comment or behavior which can be misinterpreted as "we intend to defend against hostile symlinks already on disk." If we want to make a behavioral change to how we interpret preexisting symlinks, that's totally fine, but a reader or future maintainer must be able to easily understand that we're not trying to offer a defense specifically against existing hostile symlinks.

CopilotAI review requested due to automatic review settings July 1, 2026 07:13

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

@GrabYourPitchforksGrabYourPitchforks left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My concerns are addressed. Thanks. :)

@GrabYourPitchforks
GrabYourPitchforks dismissed their stale reviewJuly 2, 2026 17:07

Removing block.

@alinpahontu2912
alinpahontu2912 merged commit 710da3b into dotnet:mainJul 3, 2026
86 of 88 checks passed
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview7 milestone Jul 4, 2026
eiriktsarpalis pushed a commit that referenced this pull request Jul 15, 2026
Evaluate symlinks destination properly
richlander added a commit to richlander/dotnet-install that referenced this pull request Jul 18, 2026
Adversarial review noted that TarFile.ExtractToDirectory does not reject
chained-symlink traversal on all supported runtimes (the physical
symlink-containment fix, dotnet/runtime#129281, is not present in the
preview this repo currently builds against). A malicious tar could create
a symlink to an outside directory then write a file through it, escaping
the extraction directory before payload validation runs.
Walk the tar entries explicitly instead: reject any link/device/fifo entry
(a single-file tool payload never contains them), and independently contain
each entry's resolved path within the extraction directory rather than
trusting the runtime. Windows keeps ZipFile.ExtractToDirectory.
Adds tests for symlink-entry rejection and the chained-symlink escape.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 93b4a21a-2d53-4208-9078-2643c540666a
richlander added a commit to richlander/dotnet-install that referenced this pull request Jul 18, 2026
* Extract release archives with managed APIs to prevent tar-slip
The github-release update path extracted downloaded assets by shelling
out to `tar -xzf`, which honors entries containing `../` and can write
files outside the extraction directory (tar-slip / path traversal) from
an attacker-controlled release asset.
Replace the external `tar` call with managed extraction via
System.Formats.Tar.TarFile over a GZipStream (and ZipFile on Windows),
both of which reject entries that escape the destination directory.
Factored into a testable TryExtractReleaseArchive helper.
Adds tests covering rejection of a tar-slip entry and successful
extraction of a legitimate tarball.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 93b4a21a-2d53-4208-9078-2643c540666a
* Harden tar extraction against symlink escape and untrusted runtimes
Adversarial review noted that TarFile.ExtractToDirectory does not reject
chained-symlink traversal on all supported runtimes (the physical
symlink-containment fix, dotnet/runtime#129281, is not present in the
preview this repo currently builds against). A malicious tar could create
a symlink to an outside directory then write a file through it, escaping
the extraction directory before payload validation runs.
Walk the tar entries explicitly instead: reject any link/device/fifo entry
(a single-file tool payload never contains them), and independently contain
each entry's resolved path within the extraction directory rather than
trusting the runtime. Windows keeps ZipFile.ExtractToDirectory.
Adds tests for symlink-entry rejection and the chained-symlink escape.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 93b4a21a-2d53-4208-9078-2643c540666a
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Aug 4, 2026
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@alinpahontu2912@GrabYourPitchforks@am11@rzikm@iremyux