Skip to content

Strict mode blocks secrets.* in step env: bindings — no secure path for workflows that need external secret managers #25710

@susmahad

Description

@susmahad

Problem

gh-aw strict mode (default for Copilot engine workflows) blocks all secrets.* expressions inside the user-defined steps: section, including when they are used in step-level env: bindings. This creates a gap for reusable agent workflows that need to pass tool credentials (API tokens, OAuth keys) to CLI tools via environment variables.

Current Behavior

# csdl-pm.md (agent workflow)
steps:
  - name: Export secrets as env vars
    env:
      SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}   # <-- strict mode ERROR
    run: |
      echo "SONAR_TOKEN=${SONAR_TOKEN}" >> "$GITHUB_ENV"

Compilation fails with:

error: strict mode: secrets expressions detected in 'steps' section may be leaked
to the agent job. Found: ${{ secrets.SONAR_TOKEN }}, ...
Operations requiring secrets must be moved to a separate job outside the agent job

Why This Is a Problem

Agent workflows that call external APIs (SonarQube, Corona, CIAM, CDETS, Solis, etc.) need tool-specific credentials available as environment variables at runtime. The only way CLI tools can consume these is via process.env / $GITHUB_ENV.

The "move to a separate job" guidance does not work here because:

  1. The agent job IS the job — there is no separate non-agent job in a workflow_call agent workflow that can run setup steps with secrets access.

  2. The workaround of passing secrets as a string input (secrets_json) is insecure — string inputs and job outputs are not masked by GitHub Actions. This defeats the purpose of strict mode by laundering secrets through a less-protected channel.

  3. The secrets: block on workflow_call is the correct, masked transport — but the values can't be consumed because strict mode blocks them in steps.

Workarounds Evaluated

Approach Security Drawback
strict: false in frontmatter Secure (secrets flow via secrets: block, masked by GitHub) Opts out of all strict mode protections, not just this one
Pass secrets as secrets_json string input from a caller pre-job Insecure — string inputs are not masked in logs Defeats the purpose of strict mode entirely

We are currently using strict: false as the least-bad option, but this is a blunt instrument that disables protections we'd like to keep.

Proposed Solutions

Option A: Allow secrets.* in step-level env: bindings

Step-level env: bindings are a controlled, non-leaky surface. The secret value is bound to a named environment variable for that step only. It's functionally equivalent to what the framework's own generated jobs already do. Strict mode should distinguish between:

  • env: FOO: ${{ secrets.FOO }}safe (controlled binding, masked)
  • run: echo ${{ secrets.FOO }}unsafe (inline interpolation, potential leak)

Option B: Provide a pre-steps: section

Add a pre-steps: section to the .md frontmatter that runs before the agent job's main steps, with full secrets access. This would allow secret retrieval and $GITHUB_ENV export in a controlled phase that strict mode can audit separately.

pre-steps:
  - name: Export tool credentials
    env:
      SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
    run: echo "SONAR_TOKEN=${SONAR_TOKEN}" >> "$GITHUB_ENV"

steps:
  - name: Install CLI tools
    run: cd .github/workflows/agents/csdl-pm/tools && npm ci

Real-World Use Case

Our csdl-pm agent workflow is a reusable workflow_call agent that orchestrates security scans across 6+ external APIs (SonarQube, Corona, CIAM, CDETS, Solis, Security Insights). It requires 10+ distinct tool credentials:

SONAR_TOKEN, CORONA_TOKEN, CIAM_CLIENT_ID, CIAM_CLIENT_SECRET,
CIAM_TOKEN_URL, CIAM_USER, SOLIS_TOKEN, SI_TOKEN,
CDETS_CONSUMER_KEY, CDETS_CONSUMER_SECRET

Each credential is passed via the secrets: block (properly masked by GitHub) and needs to be exported to $GITHUB_ENV so the agent's bash tool invocations can access them. Setting strict: false is our current workaround, but we lose the other protections strict mode provides.

Environment

  • gh-aw version: v0.68.0
  • Engine: copilot
  • Affected workflow: csdl-pm.md (reusable workflow_call agent with 10+ tool credentials)

Impact

Any agent workflow that calls external APIs with tool-specific credentials is affected. This pattern is common in:

  • Security automation (CSDL scanning, vulnerability management)
  • Migration tooling (calling external CI/CD APIs)
  • CI/CD orchestration agents (registry pushes, deployment APIs)
  • Any agent that integrates with enterprise services behind authentication

Metadata

Metadata

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions