Skip to content

[BUG]: PowerShell@2 silently removes explicitly mapped SECRET_* environment variables without warning #22531

Description

Task name

PowerShell@2

Task version

2.279.1

Issue Description

An explicitly mapped environment variable named SECRET_VALUE is silently removed before the user's PowerShell script starts. The script observes an empty/missing value even when the environment variable was populated before task SDK initialization.

This report concerns diagnostics and discoverability, not a request to remove secret protection or make reserved prefixes unrestricted.

The symptom looks like a missing password, incorrect variable-group scope, or an authorization problem. I spent hours investigating the wrong configuration layer because there was no diagnostic identifying the environment-variable name collision.

Environment

  • Azure DevOps Services (dev.azure.com)
  • Self-hosted Windows agent
  • PowerShell@2 with pwsh: true, launching PowerShell 7
  • Exact agent and Windows versions are not included in this report.

Minimal pipeline example

This example uses only a synthetic, non-secret value. No variable group or credential is required to illustrate the collision.

trigger: none
pr: none

pool:
  vmImage: windows-latest

steps:
  - task: PowerShell@2
    inputs:
      targetType: inline
      pwsh: true
      script: |
        $present = -not [string]::IsNullOrWhiteSpace($env:SECRET_VALUE)
        Write-Host "SECRET_VALUE present: $present"
        if (-not $present) {
          throw 'The explicitly mapped environment variable is missing.'
        }
    env:
      SECRET_VALUE: offline-fixture-not-a-real-password

Workaround: rename the explicit environment mapping to a name without the reserved prefix, such as APP_AUTH_PASSWORD, and update the script to read $env:APP_AUTH_PASSWORD.

The real failure was observed on a self-hosted Windows agent. The simplified windows-latest pipeline above has not been queued; the controlled reproduction below was executed locally against the SDK shipped in the exact task version.

Verified local reproduction

To avoid waiting for a busy agent pool, I downloaded the PowerShell task package for version 2.279.1 from Azure DevOps and used its actual ps_modules\VstsTaskSdk\InputFunctions.ps1.

In a disposable PowerShell process, initialize a synthetic value, run the SDK's Initialize-Inputs, and then launch a child PowerShell process. The initialization function modifies the current process environment, so this should not be run inside a session containing real task credentials.

param(
    [Parameter(Mandatory)]
    [string]$TaskPackageDirectory
)

. (Join-Path $TaskPackageDirectory 'ps_modules\VstsTaskSdk\InputFunctions.ps1')

$env:SECRET_VALUE = 'offline-fixture-not-a-real-password'
$env:APP_AUTH_PASSWORD = 'offline-fixture-not-a-real-password'

Write-Host "Before: SECRET_VALUE present=$(-not [string]::IsNullOrWhiteSpace($env:SECRET_VALUE))"
Write-Host "Before: APP_AUTH_PASSWORD present=$(-not [string]::IsNullOrWhiteSpace($env:APP_AUTH_PASSWORD))"

Initialize-Inputs

pwsh -NoLogo -NoProfile -NonInteractive -Command {
    Write-Host "Child: SECRET_VALUE present=$(-not [string]::IsNullOrWhiteSpace($env:SECRET_VALUE))"
    Write-Host "Child: APP_AUTH_PASSWORD present=$(-not [string]::IsNullOrWhiteSpace($env:APP_AUTH_PASSWORD))"
}

In the executed controlled test, the original script was also run in a child pwsh process with external operations mocked. Changing only the mapped environment name and its script references produced:

Mapping Before SDK initialization After SDK initialization Child script
SECRET_VALUE Present Missing Failed with the same missing-value error
Non-reserved name (RABBITMQ_AUTH_PASSWORD in the test) Present Present Passed; the dummy value reached the mocked command intact

No actual credential was needed, inspected, or changed for this reproduction. No deployment was performed.

Relevant log output

The original task's user-script guard reported:

The configured secret value is empty or missing.
PowerShell exited with code '1'.

The local reproduction showed:

Before SDK initialization: SECRET_VALUE present=True
After SDK initialization: SECRET_VALUE present=False
Verified child exit code: 1

Before SDK initialization: RABBITMQ_AUTH_PASSWORD present=True
After SDK initialization: RABBITMQ_AUTH_PASSWORD present=True
PASS: configured password reached the child process and mocked secret creation.
Verified child exit code: 0

Full private pipeline logs are intentionally omitted. The synthetic reproduction isolates the behavior without infrastructure details or secrets.

Source-level explanation

In the SDK bundled with PowerShell 2.279.1, InputFunctions.ps1:

  • Line 459 enumerates Env:ENDPOINT_?*, Env:INPUT_?*, Env:SECRET_?*, and Env:SECUREFILE_?*.
  • Matching values are stored in the SDK's internal vault.
  • Line 483 removes each matching environment variable with Remove-Item.

VstsTaskSdk.psm1, line 158 in that package, calls Initialize-Inputs before invoking the task script. The Windows PowerShell task subsequently launches the user's pwsh process, which no longer inherits SECRET_VALUE.

The same mechanism is visible in the public source:

Expected behavior / requested improvement

Please detect collisions in user-supplied explicit env: mappings, at a layer that can distinguish them from legitimate SDK-internal variables, and provide an actionable warning or validation error. For example:

The explicitly mapped environment variable 'SECRET_VALUE' uses a reserved task SDK prefix and will not be available to the child script. Rename the environment mapping to a non-reserved name.

The diagnostic must not print the value. It should not warn indiscriminately about normal internal SECRET_* variables.

A task-specific documentation example and a regression test for explicit mappings would also help prevent this misleading failure mode.

Related issue

microsoft/azure-pipelines-task-lib#544 describes the broader reserved-prefix collision, primarily for pipeline variables beginning with Input.. This report adds an exact-version Windows PowerShell@2 reproduction for an explicit env: SECRET_VALUE mapping and requests actionable diagnostics.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions