-
Notifications
You must be signed in to change notification settings - Fork 925
Reject shell metacharacters and use -File for PowerShell operations #5348
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Gabriel Dufresne (GabrielDuf)
merged 12 commits into
main
from
fix/sec-16522-command-injection
Sep 4, 2026
Merged
Changes from 4 commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
f10296c
Reject shell metacharacters in package fields before they reach a com…
GabrielDuf 4b17350
Launch PowerShell package operations with -File instead of -Command
GabrielDuf 0982834
Address PR review: option injection, probe deadlock and over-rejection
GabrielDuf b3d4db2
Address second review pass: broker parity, launcher exit codes, unpin…
GabrielDuf 5b1a2ce
Refuse unusable package versions and validate Scoop bucket specifiers
GabrielDuf d639bbf
Close standard input on the shim-launched manager processes
GabrielDuf eaa91d2
Close operation standard input when the line handler is disabled
GabrielDuf ceca0af
Drop two launcher tests that depend on the PowerShell Gallery
GabrielDuf ac6421f
Isolate the shim test settings from the real configuration
GabrielDuf a70a0aa
Validate the effective WinGet selector, not just the identifier
GabrielDuf 5332e88
Refuse process names the exported script would let cmd reinterpret
GabrielDuf 5c39b2b
Validate custom arguments on the concatenated paths and ship the laun…
GabrielDuf File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
128 changes: 128 additions & 0 deletions
128
src/SharedAssets/Assets/Utilities/unigetui_ps_operation.ps1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,128 @@ | ||
| #Requires -Version 5 | ||
| # Controlled launcher for UniGetUI PowerShell package operations. | ||
| # | ||
| # Invoked as: powershell.exe -NoProfile -ExecutionPolicy Bypass -File <this> <mode> <command> [args...] | ||
| # | ||
| # This script deliberately declares NO param() block. Without one, PowerShell binds every | ||
| # argument positionally into $args and performs no parameter-name binding at all, so a data | ||
| # argument that happens to look like "-Mode" or "-Command" cannot be smuggled into a control | ||
| # value. The arguments after <command> are splatted, which passes them to the cmdlet as data | ||
| # and never re-parses them as script. | ||
|
|
||
| $ErrorActionPreference = 'Continue' | ||
| $ConfirmPreference = 'None' | ||
|
|
||
| if ($args.Count -lt 2) | ||
| { | ||
| [Console]::Error.WriteLine('UniGetUI: the operation launcher requires a mode and a command.') | ||
| exit 2 | ||
| } | ||
|
|
||
| $mode = [string]$args[0] | ||
| $command = [string]$args[1] | ||
|
|
||
| # Windows PowerShell 5.x defaults to TLS 1.0/1.1, which the PowerShell Gallery rejects. | ||
| if ($mode -eq 'tls12') | ||
| { | ||
| try | ||
| { | ||
| [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 | ||
| } | ||
| catch | ||
| { | ||
| [Console]::Error.WriteLine('UniGetUI: could not select TLS 1.2.') | ||
| } | ||
| } | ||
|
|
||
| $commandInfo = $null | ||
| try | ||
| { | ||
| $commandInfo = Get-Command -Name $command -ErrorAction Stop | ||
| } | ||
| catch | ||
| { | ||
| # Left null: without metadata nothing is coerced, and the call below reports the real error. | ||
| } | ||
|
|
||
| # Whether $name names a switch on the command about to be invoked. Only a switch may have its | ||
| # value coerced, because an ordinary string parameter can legitimately be given the text "$false" | ||
| # - a repository named that, for instance - and must reach the cmdlet unchanged. | ||
| function Test-IsSwitchParameter([string]$name) | ||
| { | ||
| if ($null -eq $commandInfo) | ||
| { | ||
| return $false | ||
| } | ||
|
|
||
| $parameter = $commandInfo.Parameters[$name] | ||
| if ($null -eq $parameter) | ||
| { | ||
| $parameter = $commandInfo.Parameters.Values | | ||
| Where-Object { $_.Aliases -contains $name } | | ||
| Select-Object -First 1 | ||
| } | ||
|
|
||
| if ($null -eq $parameter) | ||
| { | ||
| return $false | ||
| } | ||
|
|
||
| return $parameter.ParameterType -eq [System.Management.Automation.SwitchParameter] | ||
| } | ||
|
|
||
| $named = @{} | ||
| $rest = @() | ||
|
|
||
| for ($i = 2; $i -lt $args.Count; $i++) | ||
| { | ||
| $item = [string]$args[$i] | ||
|
|
||
| # powershell.exe splits "-Switch:$false" into "-Switch" and the literal text "$false" before | ||
| # this script runs, and splatting cannot bind that text to a switch. Such a pair is turned | ||
| # into a real boolean and bound by name through a hashtable, which does accept one. | ||
| if ($item -match '^-([A-Za-z][A-Za-z0-9_]*)$' -and ($i + 1) -lt $args.Count) | ||
| { | ||
| $switchName = $Matches[1] | ||
| $next = [string]$args[$i + 1] | ||
|
|
||
| if (($next -eq '$false' -or $next -eq '$true') -and (Test-IsSwitchParameter $switchName)) | ||
| { | ||
| $named[$switchName] = ($next -eq '$true') | ||
| $i++ | ||
| continue | ||
| } | ||
| } | ||
|
|
||
| $rest += $args[$i] | ||
| } | ||
|
|
||
| # A terminating error, such as a parameter that the cmdlet does not accept, would otherwise be | ||
| # written to the error stream and leave this script to exit 0, reporting a failed operation as a | ||
| # success. Running under -Command used to fail the process for us, so it is done explicitly here. | ||
| try | ||
| { | ||
| & $command @named @rest | ||
|
GabrielDuf marked this conversation as resolved.
|
||
| $succeeded = $? | ||
| } | ||
| catch | ||
| { | ||
| # The whole record, not just the message: the caller matches on the error id to decide | ||
| # whether to retry elevated or without -Scope, and that id is only in the full record. | ||
| Write-Error -ErrorRecord $_ | ||
| exit 1 | ||
| } | ||
|
|
||
| # Running under -Command also failed the process when the command reported failure without | ||
| # throwing. Not every caller binds the error variable below - PowerShell 7 operations and source | ||
| # operations do not - so without this a failed operation would be reported as a success. | ||
| if (-not $succeeded) | ||
| { | ||
| exit 1 | ||
| } | ||
|
|
||
| # PowerShellGet reports some failures as non-terminating errors that leave $? true, so the caller | ||
| # binds -ErrorVariable to this name and it is checked as well. | ||
| if ($UniGetUIOperationError) | ||
| { | ||
| exit 1 | ||
| } | ||
|
GabrielDuf marked this conversation as resolved.
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.