Skip to content

SEC016 — environment-dump

Severity: warning · Category: Security · Platforms: GitHub Actions, Azure Pipelines

What it checks

Flags a step whose script content runs a bare, unfiltered environment-dump command: printenv or env with no argument naming a specific variable, cmd.exe's bare set, or PowerShell's Get-ChildItem Env: (and its gci/dir/ls aliases) or [Environment]::GetEnvironmentVariables(). Checked wherever a script can live: GitHub Actions' run:, Azure's script:/bash:/powershell:/ pwsh: shorthand steps, and Azure's task-based equivalents (task: CmdLine@2, PowerShell@2, Bash@3, AzureCLI@2) via their inputs.script/inputs.inlineScript.

A command that names a single variable — printenv HOME, env FOO=bar some-command (using env as a prefix to set one variable for one invocation, not to dump anything) — is deliberately not flagged; only the no-argument, dump-everything form is.

Why it matters

Both platforms mask known secret values in log output, but that masking only works for variables the platform actually knows are secret — a variable added to a variable group without checking "keep this value secret" in Azure, or a token passed through env: from a context the platform's masker doesn't scan, prints in plaintext right alongside everything else. Dumping the entire environment as a debug step is a common, usually harmless-feeling habit (printenv next to dotnet --info to sanity-check a build environment), but it means every secret present on the runner — masked or not — ends up in the log, whether the step needed it or not. The fix isn't "never debug your environment," it's "print only what you're actually trying to check."

This is the same reasoning as SEC008 (toJSON(secrets)): dumping everything exposes more than the step needs, independent of whether masking happens to catch it this time.

Found in practice vetting AvaloniaUI/Avalonia's real azure-pipelines.yml, which runs a bare printenv as a debug step in two of its four CI jobs.

Examples

Flagged — dumps everything to sanity-check the environment:

- script: |
    dotnet --info
    printenv
    ./build.sh --target Release
- task: CmdLine@2
  inputs:
    script: |
      dotnet --info
      printenv

Fixed — check only the variable(s) actually in question:

- script: |
    dotnet --info
    printenv DOTNET_ROOT
    ./build.sh --target Release

Suppressing

The finding is reported on the step's line:

      - run: printenv # vlotpipe: ignore[SEC016]

Reasonable for a genuinely secret-free environment (e.g., a job with no secret variables configured at all) — but that's an easy assumption to get wrong later when a secret gets added to the job and nobody remembers this step is still dumping everything.