Escape single quotes in PowerShell login script inputs - #599
Open
MaddyMicrosoft wants to merge 2 commits into
Open
Escape single quotes in PowerShell login script inputs#599MaddyMicrosoft wants to merge 2 commits into
MaddyMicrosoft wants to merge 2 commits into
Conversation
Apply the same single-quote escape already used for the service principal secret to the remaining values interpolated into the generated PowerShell login script: tenant-id, subscription-id, client-id, federated token, and the AzureStack resourceManagerEndpointUrl. Factor the escape into a shared helper (escapePSSingleQuoted) so every interpolation site uses the same treatment, and add regression tests that assert each field is escaped across all supported auth paths. No behaviour change for valid inputs; legitimate values contain no single quotes.
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
What
Apply the same single-quote escape already used for
servicePrincipalSecretto the remaining values interpolated into the generated Azure PowerShell login script:tenant-id,subscription-id,client-id,federated token, and (on the AzureStack path)resourceManagerEndpointUrl. Factor the escape into a shared helper (escapePSSingleQuoted) so every interpolation site uses the same treatment.No behaviour change for legitimate inputs — real GUIDs, domain names, and https URLs contain no single quotes.
Why
AzPSScriptBuilderbuilds a PowerShell script by string-concatenating action inputs into single-quoted'...'literals, then hands the result topwsh -Command. TheclientSecretfield already escaped single quotes; the other four fields did not. A value containing a single quote would break out of the string context and could execute as PowerShell.This is a defense-in-depth patch. The Azure CLI path (which uses argv arrays via
child_process.spawn) already blocks this class of attack for most auth flows, but the escape closes the remaining PS-side surface for consistency and to protect users whose workflow bypasses CLI validation (e.g. via AzureStack cloud registration).Scope
Only
AzPSScriptBuilder.tsand its test are touched.AzureCliLogin.ts,LoginConfig.ts, and the environment allowlist are unchanged — no other code paths were vulnerable.Verification
SECURITY:regression tests covering all four affected fields across every auth path (SP+secret, OIDC, user-assigned MI, system-assigned MI, AzureStack)LoginConfig+AzPSScriptBuilderwith adversarial values in all four fields. Every interpolation site produced doubled single quotes (''), making the payload inert data inside the surrounding'...'string literalssubscription-idpayload (abc' ; Set-Content ... ; $x='). The whole payload was transported as literal string data to Azure — Az CLI rejected the subscription with an "invalid subscription" error containing the exact string. No process execution, no side-effect file was createdBackport plan
The escape fix backports cleanly to
releases/v2— the affected file is nearly identical between v2 and master. A separate PR againstreleases/v2will follow.