Skip to content

Commit 0e4a588

Browse files
tablackburnclaude
andcommitted
fix(build): identify the gallery by scheme and host, not string equality
Review pointed out that -ne is case-insensitive, so a source location differing only in case would pass the check, and suggested -cne. -cne would be wrong in the other direction. Host names are case-insensitive by definition, so a strict comparison rejects https://WWW.PowerShellGallery.com/api/v2 -- which is the real gallery. The identifying part is the host, and a repository standing in for the gallery would differ there, not in casing. The source location is now parsed and its scheme and host compared, which accepts any casing of the genuine host and rejects a different one. Unparseable values are rejected too, where the previous string comparison would have thrown on a null SourceLocation instead. Verified: https://www.powershellgallery.com/api/v2 accepted https://WWW.PowerShellGallery.com/api/V2 accepted https://evil.example.com/api/v2 rejected not-a-uri rejected Unsigned at the author's request -- 1Password is unavailable this session. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G1CarQG8VibNFxw4cN53Zs
1 parent 0c77ef4 commit 0e4a588

1 file changed

Lines changed: 13 additions & 4 deletions

File tree

build.ps1

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,19 @@ if ($Bootstrap) {
108108
# is already registered against a different SourceLocation, every dependency in
109109
# build.depend.psd1 would be installed from it on the strength of the name alone.
110110
# Refuse rather than trust the name.
111-
$expectedSourceLocation = 'https://www.powershellgallery.com/api/v2'
112-
$actualSourceLocation = $psGallery.SourceLocation.TrimEnd('/')
113-
if ($actualSourceLocation -ne $expectedSourceLocation.TrimEnd('/')) {
114-
throw "The repository named 'PSGallery' points at [$actualSourceLocation], not [$expectedSourceLocation]. Refusing to install build dependencies from an unexpected source."
111+
# Compare scheme and host rather than the whole string. What identifies the
112+
# gallery is the host, and a plain -ne is case-insensitive while -cne would be
113+
# wrong in the other direction: host names are case-insensitive by definition,
114+
# so -cne would reject https://WWW.PowerShellGallery.com/api/v2, which is the
115+
# real gallery. Parsing sidesteps both, and an attacker-controlled repository
116+
# would differ by host, which is what this actually checks.
117+
$expectedSource = [Uri]'https://www.powershellgallery.com/api/v2'
118+
$actualSource = $psGallery.SourceLocation -as [Uri]
119+
$sourceIsExpected = $null -ne $actualSource -and
120+
$actualSource.Scheme -eq $expectedSource.Scheme -and
121+
$actualSource.Host -eq $expectedSource.Host
122+
if (-not $sourceIsExpected) {
123+
throw "The repository named 'PSGallery' points at [$($psGallery.SourceLocation)], which is not $($expectedSource.Scheme)://$($expectedSource.Host). Refusing to install build dependencies from an unexpected source."
115124
}
116125

117126
if ($psGallery.InstallationPolicy -ne 'Trusted') {

0 commit comments

Comments
 (0)