Skip to content

Security: env-vars table hard-wraps long values, defeating GitHub's native secret masking #3548

Description

@thomhurst

Category: secret hygiene — Breaking: no

Rotate/expire exposure first if applicable — this defect has already printed a live job token in public run logs.

The startup environment-variables table (Engine/Executors/PipelineInitializer.cs:56-77) renders values in a Spectre table that wraps at the column width (~37 chars). GitHub's runner-side ::add-mask:: masking only matches a whole secret appearing on a single physical line, so any env secret longer than the column width is printed in full across multiple table continuation rows, unmasked. Observed on recent main runs (e.g. 30526435350): the workflow-provided GITHUB_TOKEN (job-scoped, 1h expiry) appears complete across 11 wrapped rows, while short secrets on the same table are correctly masked. The framework's own obfuscator can't help when the value was never registered as a [SecretValue] (here the workflow deliberately unsets the registered copy on main pushes).

Fix: never hard-wrap env values — emit one physical line per value (truncate long values for display instead of wrapping) so runner masking can match; additionally apply name-heuristic masking (TOKEN|SECRET|PASSWORD|KEY|PWD|CREDENTIAL) in the env table regardless of secret registration. Any consumer with a >37-char env secret leaks it permanently today.

Part of #3239 (round 2 addendum). Distinct from #3475 (PipelineLevelLogger path).

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High: real user impact or v4-foundation - work secondbugSomething isn't workingin-progressPicked up by an agent

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions