Skip to content

fix: exclude job-output credential env vars from agent sandbox (--exclude-env) - #46076

Merged
pelikhan merged 8 commits into
mainfrom
copilot/aw-job-output-exclude-env
Jul 17, 2026
Merged

fix: exclude job-output credential env vars from agent sandbox (--exclude-env)#46076
pelikhan merged 8 commits into
mainfrom
copilot/aw-job-output-exclude-env

Conversation

CopilotAI commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

ComputeAWFExcludeEnvVarNames only detected ${{ secrets.* }} as credential-bearing, so env vars set via job outputs (e.g. GH_TOKEN: ${{ needs.fetch_token.outputs.token }}) were never passed to --exclude-env, leaving ephemeral tokens fully visible inside the AWF container.

Changes

  • secret_extraction.go — adds jobOutputExprPattern regex and ContainsJobOutputExpr() helper that detects ${{ needs.JOB.outputs.OUTPUT }} anywhere in a value string
  • awf_helpers.go — extends the credential check in all three env sections (mcp-scripts, engine.env, agent.env) to OR ContainsJobOutputExpr() with the existing secrets. check; updates doc comment on ComputeAWFExcludeEnvVarNames
  • Tests — new table-driven cases in awf_helpers_test.go and secret_extraction_test.go covering job-output exclusion, static-value pass-through, and mixed secrets+outputs

Example: the following mcp-scripts env block now produces --exclude-env GH_TOKEN in the compiled lock file, matching the behaviour of GH_TOKEN: ${{ secrets.SOME_PAT }}:

mcp-scripts:
example:
env:
GH_TOKEN: ${{ needs.fetch_token.outputs.token }}

…lude-env)
Extend ComputeAWFExcludeEnvVarNames to treat needs.*.outputs.* expressions
as credential-bearing (same as secrets.*), so env vars set from job outputs
(e.g. GH_TOKEN: ${{ needs.fetch_token.outputs.token }}) are excluded from
the agent container via AWF --exclude-env.
Closes#46012
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
CopilotAI changed the title [WIP] Fix exclusion of job-output token values from agent sandboxfix: exclude job-output credential env vars from agent sandbox (--exclude-env)Jul 16, 2026
CopilotAI requested a review from pelikhanJuly 16, 2026 20:00
@pelikhan
pelikhan marked this pull request as ready for review July 16, 2026 21:11
CopilotAI review requested due to automatic review settings July 16, 2026 21:11

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Extends AWF sandbox credential protection to job-output-derived environment variables.

Changes:

  • Detects needs.JOB.outputs.OUTPUT expressions.
  • Excludes matching MCP, engine, and agent environment variables.
  • Adds unit tests and a patch changeset.
Show a summary per file
FileDescription
pkg/workflow/secret_extraction.goAdds job-output expression detection.
pkg/workflow/secret_extraction_test.goTests expression matching.
pkg/workflow/awf_helpers.goApplies detection to sandbox exclusions.
pkg/workflow/awf_helpers_test.goTests environment-variable exclusions.
.changeset/patch-exclude-job-output-credential-env-vars.mdDocuments the security fix.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 5/5 changed files
  • Comments generated: 1
  • Review effort level: Medium

Comment threadpkg/workflow/secret_extraction.go Outdated
// jobOutputExprPattern matches a ${{ needs.JOB.outputs.OUTPUT }} expression anywhere in a string.
// Used to detect job-output credential references for --exclude-env, treating them
// the same as ${{ secrets.* }} references.
jobOutputExprPattern = regexp.MustCompile(`\$\{\{\s*needs\.[A-Za-z_][A-Za-z0-9_-]*\.outputs\.[A-Za-z_][A-Za-z0-9_-]*`)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit. ContainsJobOutputExpr now uses InlineExpressionPattern to extract all ${{ ... }} blocks in the value, then searches within each expression body using two patterns:

  • jobOutputBodyDotPattern\bneeds\.[A-Za-z_][A-Za-z0-9_-]*\.outputs\.[A-Za-z_][A-Za-z0-9_-]* — matches dot notation anywhere in the expression body, so ${{ github.ref && needs.auth.outputs.token }} now returns true.
  • jobOutputBodyBracketPattern\bneeds\[['"][A-Za-z_][A-Za-z0-9_-]*['"]\](?:\.outputs\b|\[['"]outputs['"]\]) — matches single- and double-quote bracket notation, so ${{ needs['auth'].outputs['token'] }} and ${{ needs['auth']['outputs']['token'] }} now return true.

Regression tests added for: sub-expression with &&, sub-expression with ||, bracket with single quotes, bracket with double quotes, full bracket notation (['JOB']['outputs']['OUTPUT']), and bracket notation after another token.

@github-actions

This comment has been minimized.

@github-actions

Copy link
Copy Markdown
Contributor

Hey @app/copilot-swe-agent -- great catch on the ${{ needs.JOB.outputs.OUTPUT }} gap in ComputeAWFExcludeEnvVarNames! Ephemeral tokens flowing through job outputs are just as sensitive as secrets.* references, so closing this exclusion gap is an important security fix.

The PR looks well-structured: the change is tightly scoped to the credential-detection path, the new ContainsJobOutputExpr() helper is cleanly separated, and the table-driven tests cover the key scenarios (job-output exclusion, static-value pass-through, and mixed secrets+outputs). This looks ready for review.

Generated by ✅ Contribution Check · 155.6 AIC · ⌖ 8.97 AIC · ⊞ 6.2K ·

@pelikhan

Copy link
Copy Markdown
Collaborator

/matt

@github-actions

github-actionsBot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

github-actions[bot]
github-actionsBot previously requested changes Jul 16, 2026

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skills-Based Review

Applied /diagnosing-bugs — requesting changes for one broken test.

📋 Key Themes & Highlights

Issue

  • Broken test case: "job output embedded in a larger string" uses a value without ${{, so ContainsJobOutputExpr returns false but want: true — the test will always fail.

Positive Highlights

  • ✅ Clean, focused fix addressing a real security gap (ephemeral token leakage).
  • ✅ Good table-driven test coverage across all three env sections (mcp-scripts, engine.env, agent.env).
  • ✅ Regex correctly handles extra whitespace and hyphenated job names.
  • ✅ Doc comment on ComputeAWFExcludeEnvVarNames is updated accurately.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · 17.7 AIC · ⌖ 7.73 AIC · ⊞ 6.7K
Comment /matt to run again

@github-actions

Copy link
Copy Markdown
Contributor

🤖 PR Triage

FieldValue
Categorybug (security)
Risk🔴 High
Score91/100
Action🚀 fast_track

Score breakdown: Impact 45 + Urgency 30 + Quality 16

Rationale: Security-sensitive fix — credential env vars from job outputs were not excluded from agent sandbox --exclude-env, leaving ephemeral tokens visible inside AWF containers. CI passes (30 checks, all green). Small focused change (5 files, +167/-11). Top-priority open PR.

Run §29545908133

Generated by 🔧 PR Triage Agent · 181.7 AIC · ⌖ 5.04 AIC · ⊞ 5.6K ·

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot add frontmatter field to specify additional envs to exclude.

excluded-env: list of string

those get added to the awf excludes env list

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
CopilotAIand others added 2 commits July 17, 2026 03:44
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

CopilotAI commented Jul 17, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot ensure support for imported agentic workflows to unionize the list of excluded envs. Deduplicate, Sort for stability

Done in commit feat: union excluded-env from imported workflows with dedup and sort.

Imported workflow excluded-env lists are now unioned with the main workflow's list in buildInitialWorkflowData:

  • ImportsResult gains MergedExcludedEnv []string populated by the import BFS accumulator via mergeExcludedEnv() (deduplicates across imports using a seen-set)
  • mergeExcludedEnvVarNames(fromImports, fromMain) in workflow_builder.go unions both slices, deduplicates, and sorts for stability before assigning to WorkflowData.ExcludedEnv

The pkg/cli test failures visible in CI are pre-existing and unrelated to these changes.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address the unresolved review thread below, and rerun checks once updated.

Unresolved review feedback:

Generated by 👨‍🍳 PR Sous Chef · 5.77 AIC · ⌖ 5.81 AIC · ⊞ 7.5K ·
Comment /souschef to run again

…ainsJobOutputExpr
- Replace `jobOutputExprPattern` (anchored to `${{ needs.`) with two body
patterns checked within `InlineExpressionPattern` extractions:
* `jobOutputBodyDotPattern`: `\bneeds.JOB.outputs.OUTPUT` (dot notation,
anywhere in expression body)
* `jobOutputBodyBracketPattern`: `needs['JOB'].outputs` / `needs['JOB']['outputs']`
(single- and double-quote bracket notation)
- `ContainsJobOutputExpr` now iterates `${{ ... }}` blocks found by
`InlineExpressionPattern` and tests each body, matching the approach
used by `ExtractSecretsFromValue`
- Adds 7 new test cases covering sub-expressions (`github.ref && needs.*`),
bracket notation (single/double quote, full bracket), and embedded bracket
after another token
Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot update main json schema with new field

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

CopilotAI commented Jul 17, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot update main json schema with new field

Done in commit feat: add excluded-env field to main workflow JSON schema. The excluded-env array field has been added to pkg/parser/schemas/main_workflow_schema.json after check-for-updates, with a description explaining its purpose and merge/dedup behaviour, plus examples.

@pelikhan
pelikhan merged commit b944311 into mainJul 17, 2026
28 checks passed
@pelikhan
pelikhan deleted the copilot/aw-job-output-exclude-env branch July 17, 2026 06:53
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.82.12

github-actionsBot added a commit that referenced this pull request Jul 17, 2026
Add excluded-env frontmatter field definition introduced in
fix: exclude job-output credential env vars from agent sandbox (#46076).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
pelikhan pushed a commit that referenced this pull request Jul 17, 2026
Add excluded-env frontmatter field definition introduced in
fix: exclude job-output credential env vars from agent sandbox (#46076).
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[aw] Job-output github-token values are not excluded from the agent sandbox (--exclude-env)

4 participants

@pelikhan@gh-aw-bot