Skip to content

Reject unsafe action pins and resolve critical alert triage - #70616

Merged
pelikhan merged 4 commits into
mainfrom
pelikhan-issue-69882-aw-top-10-07-resolve-critical-code-scan-89dec1
Oct 20, 2026
Merged

pelikhan merged 4 commits into
mainfrom
pelikhan-issue-69882-aw-top-10-07-resolve-critical-code-scan-89dec1

Conversation

@pelikhan

@pelikhan pelikhan commented Oct 20, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Fixes #69882. Reviews source reports #68742, #69063, and #70442 against current code; the full alert-by-alert dispositions are recorded in artifact 1 on #69882.

ADR: ADR-70616: Reject Unsafe Action Pins with Explicit Errors Instead of Escaping

  • Reject unsupported control characters, Unicode line separators, and GitHub Actions expressions in mapped action-pin references and comments, whether the source uses quoted or unquoted YAML. Quote mapped references with YAML punctuation while preserving ordinary safe output.
  • Validate maintenance resolver results at the root generation boundary, independent of label triggers, and propagate errors without returning unsafe YAML. Cover default labels-disabled generation, permission-check paths, and setup action pins.
  • Extend the existing Actions/AW action-pin lint rule to enforce formatting: malformed references are errors even for native Actions and non-strict AW. Reject invalid UTF-8, control characters, Unicode whitespace/line separators, malformed paths/refs/digests, and expressions. Valid but mutable refs retain their existing policy severity. No duplicate lint rule is registered.
  • Preserve apostrophe escaping, tab-separated mapping comments, and valid quoted/plain pins with YAML round-trip coverage.
  • Expand package-name rejection tests for option-like inputs and verify shell-looking Pi subagent tasks travel only through stdin, not executable arguments.
  • Finalize the generated ADR with alternatives, compatibility evidence, and explicit maintainer-approval limits.

Run the pin check directly on either source format with gh aw lint --rules action-pin path/to/workflow.yml or the corresponding .md file. Diagnostics identify the configuration path without exposing the pin value.

Alert dispositions

  • Code scanning 1030/1031 were already dismissed for correct single-quote escaping. Retain those decisions and harden multiline comments as defense in depth; no attacker-controlled exploit was demonstrated.
  • Code scanning 1032/1033 are already fixed by fix: avoid filesystem races in inventory regression assertions #69411. Current filesystem tests use private temporary directories and descriptor-based checks.
  • Sighthound's pip/uv command-injection findings are false positives: literal executable names are resolved/validated, package names are validated, and execution is shell-free.
  • The Pi subagent finding is a false positive: declared agent selection, trusted runtime executable/arguments, shell: false, and task-only stdin.
  • The add-comment eval finding is confined to repository-owned test source and test-authored configuration; handler payloads are passed afterward as data. The close-issue finding points to mocked API calls, not shell execution.

No live security-alert state was changed. Human-review requirements for critical dismissals remain with maintainers.

Validation

Latest commit cb519e9a78:

  • Complete Actions/AW lint package test suite passed.
  • CLI regressions confirm malformed pins cause nonzero lint results for native Actions and non-strict AW, while diagnostics remain value-free.
  • Pin-format regressions cover authored AW execution scopes, reusable workflows, local actions, remote SHAs, Docker digests, all three quoting styles, version comments, and malformed encoding/control/separator cases.
  • make build, make fmt, and the full make agent-report-progress gate passed, including Go lint, change-scoped custom Go lint, JavaScript lint/typecheck, and impacted tests. The shared-lint-lock limitation from the prior batch is cleared by this successful gate.
  • Full workflow drift check compiled all 345 workflows successfully and confirmed every lock file remains in sync.

Earlier focused validation also passed the mapped/maintenance boundary regressions, all 246 tests across the reported JavaScript suites, and all 13 lint-monster inventory tests.

The existing branch name is retained because the shared repository's packed-refs.lock blocked the requested rename; no shared lock was removed.

Harden generated maintenance action pins against multiline comments and Actions expressions, propagate validation failures, and cover package option rejection and subagent stdin isolation.

Refs #69882

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@pelikhan
pelikhan marked this pull request as ready for review October 20, 2026 19:29
Copilot AI max review requested due to automatic review settings October 20, 2026 19:29
@github-actions

github-actions Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

✅ PR Code Quality Reviewer completed the code quality review.

🔎 Code quality review by PR Code Quality Reviewer

@github-actions

github-actions Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

✅ Ponytail Reviewer completed successfully!

Ponytail Reviewer

Outcome: reported_no_action

The agent completed and reported no action. A no-op output alone does not verify that all required work was completed or that publication was possible.

Agent messages are omitted from this comment. The category uses structured run status, not interpretation of agent prose.

Generated from Ponytail Reviewer · gpt56 · 5.98 AIC · ⌖ 5.34 AIC · ⊞ 14.7K · ◷

Generated by Ponytail Reviewer for #70616

@github-actions

github-actions Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

✅ Design Decision Gate 🏗️ completed the design decision gate check. See the comment below for the result and any generated ADR draft.

Commit pushed: 9278347

🏗️ ADR gate enforced by Design Decision Gate 🏗️

@github-actions

github-actions Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

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

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer

@github-actions

github-actions Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

✅ Test Quality Sentinel completed test quality analysis.

Test Quality Sentinel

Outcome: reported_no_action

The agent completed and reported no action. A no-op output alone does not verify that all required work was completed or that publication was possible.

Agent messages are omitted from this comment. The category uses structured run status, not interpretation of agent prose.

Generated from Test Quality Sentinel · haiku45 · 4.32 AIC · ⌖ 9.53 AIC · ◇ 3 AIC · ⊞ 9.2K · ◷

🧪 Test quality analysis by Test Quality Sentinel

@github-actions

Copy link
Copy Markdown
Contributor

Comment Memory

Peek at saved memory (pr-code-quality-reviewer)
reviewed_at: 2026-10-20T19:34:00Z
review_event: REQUEST_CHANGES
top_themes:
  - action-pin validation bypass for unquoted uses entries
files_reviewed:
  - pkg/workflow/action_pins.go
  - pkg/workflow/maintenance_workflow_yaml_jobs.go
  - actions/setup/js/pi_subagent_extension.cjs
comment_count: 1

Note

This comment is managed by comment memory.

Expand the saved memory block to view or edit the persistent context for this thread.
Edit only the text inside the backtick fences; workflow metadata and the footer are regenerated automatically.

Learn more about comment memory

🔎 Code quality review by PR Code Quality Reviewer · copilot · gpt50 · 2.22 AIC · ⌖ 0.621 AIC · ⊞ 1.6K · ◷
Comment /review to run again

@github-actions

Copy link
Copy Markdown
Contributor

🏗️ Design Decision Gate — ADR Required

This PR adds 153 lines of core business logic under pkg/ (more than the 100-line threshold), but it does not link to an Architecture Decision Record (ADR).

📄 Draft ADR committed: docs/adr/70616-reject-unsafe-action-pins-with-explicit-errors.md. Review and complete it before merging.

Decision inferred from the diff: validate action pins and version comments before emitting YAML, and fail closed. validateYAMLActionPin rejects control characters, U+2028/U+2029, and ${{. quoteYAMLActionPin now returns (string, error), and the error propagates through the maintenance label job builders and mapPinnedUsesLine. Unsafe values are rejected rather than escaped.

🔒 This PR cannot merge until an ADR is linked in the PR body.

📋 What to do next
  1. Review the draft ADR on your branch. It was generated from the PR diff.
  2. Resolve the [TODO: verify] markers: deciders, which alternatives you actually considered, and whether any legitimate pins could hit the new rejection rule.
  3. Commit the finalized ADR to docs/adr/ on your branch.
  4. Reference the ADR in the PR body, for example:

    ADR: ADR-70616: Reject Unsafe Action Pins with Explicit Errors Instead of Escaping

Once an ADR is linked in the PR body, this gate will re-run and check that the implementation matches the decision.

❓ Why ADRs Matter

ADRs create a permanent, searchable record of why the codebase looks the way it does. This change makes action-pin emission fail closed and alters the maintenance builder signatures. That is a security policy future YAML emitters should follow, so the rationale belongs in the record.

📋 Michael Nygard ADR Format Reference

An ADR must contain these four sections:

  • Context: What is the problem? What forces are at play?
  • Decision: What did you decide, and why?
  • Alternatives Considered: What else could have been done?
  • Consequences: What are the trade-offs, positive and negative?

All ADRs are stored in docs/adr/ as Markdown files named by PR number.

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · pi · opus55 · 28.4 AIC · ⌖ 40.4 AIC · ⊞ 1.9K · ◷
Comment /review to run again

@github-actions github-actions Bot 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.

Verdict

Request changes. The new action-pin hardening is bypassable for unquoted uses: entries.

Details
  • pkg/workflow/action_pins.go:225: validation and safe quoting are gated on the source line having an opening quote; unquoted mapped references/comments are still emitted raw, allowing YAML or expression injection.

🔎 Code quality review by PR Code Quality Reviewer · copilot · gpt50 · 2.22 AIC · ⌖ 0.621 AIC · ⊞ 1.6K
Comment /review to run again

Comment thread pkg/workflow/action_pins.go Outdated

@github-actions github-actions Bot 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 — the fix patches the symptom in the quoted uses: pin path but leaves the same injection vector open for unquoted pins.

📋 Key Themes & Highlights

Key Themes

  • Root cause not fully addressed: mapPinnedUsesLine in pkg/workflow/action_pins.go only calls validateYAMLActionPin when captures[2] != "" (the original line was already quoted). When the source uses: line is unquoted, the function returns indentation + reference + comment, nil at line 234 without ever validating reference/comment. I reproduced this locally with the exact attack pattern used in the PR's own new regression test (TestMapPinnedUsesRejectsUnsafeQuotedPins), just starting from an unquoted input line — the malicious prefix mapping injects a run: key into the generated YAML with no error returned.
  • Positive: the quoted-pin fix itself (validateYAMLActionPin + quoteYAMLActionPin returning errors, propagated through buildMaintenanceLabelDisableJob/buildMaintenanceLabelApplySafeOutputsJob/buildMaintenanceLabelTriggeredJobs/buildMaintenanceWorkflowYAML) is solid and well-tested — control characters, Unicode line separators, and ${{ }} expressions are all correctly rejected, with both unit tests (TestQuoteYAMLActionPin*) and integration tests (TestMaintenanceLabelJobsRejectUnsafeActionPins) passing.
  • Test coverage gap: there is no regression test exercising the unquoted path with an unsafe mapped/resolved reference, which is likely why this gap wasn't caught — all new tests start from an already-quoted source line.

Positive Highlights

  • ✅ Good defense-in-depth reasoning in the PR description distinguishing dismissed vs. newly-fixed alerts.
  • ✅ Pip/uv and Pi-subagent test additions are correct and verified passing (TestValidatePipCommandPackageArg, new stdin-only test in pi_subagent_extension.test.cjs).
  • ✅ Error propagation plumbing through the maintenance workflow builders is clean and consistent with existing patterns.

Requesting changes to close the unquoted-pin gap in action_pins.go before merge, since it undermines the PR's stated goal of rejecting unsafe pins across the board. See inline comment for a concrete repro and fix.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · copilot · sonnet50 · 81.8 AIC · ⌖ 15 AIC · ⊞ 10.1K
Comment /matt to run again

Comment thread pkg/workflow/action_pins.go

Copilot AI 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.

🔵 Needs a closer look

Validation gaps remain, and critical-alert dispositions require maintainer verification.

2 open issues
What changed in this PR

Hardens quoted action-pin handling in gh-aw’s YAML generators and adds regression coverage supporting security-alert triage.

Changes:

  • Reject unsafe quoted pins and version comments.
  • Propagate validation errors through maintenance generation and pin mappings.
  • Expand package-argument and subagent-stdin safety tests.
File Description
pkg/​workflow/​safe_outputs_job_identity_test.go Handles the label builder’s new error return.
pkg/​workflow/​maintenance_workflow_yaml.go Propagates label-job generation errors.
pkg/​workflow/​maintenance_workflow_yaml_jobs.go Validates quoted pins and returns errors.
pkg/​workflow/​maintenance_workflow_labels_test.go Tests quoting, rejection, and error propagation.
pkg/​workflow/​argument_injection_test.go Covers additional option-like package names.
pkg/​workflow/​action_pins.go Validates quoted mapped pins and comments.
pkg/​workflow/​action_pins_test.go Tests unsafe quoted mapping rejection.
actions/​setup/​js/​pi_subagent_extension.test.cjs Verifies shell-looking tasks remain stdin data.

Review effort: Max

Comment thread pkg/workflow/action_pins.go Outdated
Comment thread pkg/workflow/maintenance_workflow_yaml.go
Validate mapped pins regardless of quoting, check maintenance resolver results independent of label triggers, and finalize ADR-70616 with compatibility evidence.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@pelikhan

Copy link
Copy Markdown
Collaborator Author

In reply to #70616 (comment): Accepted the review outcome. The unquoted mapped-pin validation bypass is fixed and covered alongside the quoted cases.

@pelikhan

Copy link
Copy Markdown
Collaborator Author

In reply to #70616 (comment): No code change is needed for this no-action notification. The actionable validation gaps from the other reviews are handled in this batch.

@pelikhan

Copy link
Copy Markdown
Collaborator Author

In reply to #70616 (comment): Accepted the generated ADR draft and completed its unresolved verification notes without treating generation as human approval. The finalized ADR is linked from the PR description.

@pelikhan

Copy link
Copy Markdown
Collaborator Author

In reply to #70616 (comment): Accepted the underlying skills-based review finding. Mapped references and comments are now validated regardless of source quoting, with regression coverage for unquoted inputs.

@pelikhan

Copy link
Copy Markdown
Collaborator Author

In reply to #70616 (comment): No code change is needed for this no-action test-analysis notification. This batch adds focused regressions for both reported validation bypasses.

@pelikhan

Copy link
Copy Markdown
Collaborator Author

In reply to #70616 (comment): Accepted the underlying unquoted-pin finding and fixed the validation boundary. The managed comment-memory contents were left unchanged.

@pelikhan

Copy link
Copy Markdown
Collaborator Author

In reply to #70616 (comment): Accepted: the ADR is finalized with verified compatibility limits, alternatives, and consequences, and linked from the PR description. It records quote-independent mapped-pin validation and label-independent maintenance validation.

Reject malformed references as lint errors regardless of strict policy, including Unicode control and whitespace characters in local paths. Retain mutable-ref policy severity and cover both ASTs and CLI failures.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@pelikhan
pelikhan merged commit 44aab31 into main Oct 20, 2026
50 checks passed
@pelikhan
pelikhan deleted the pelikhan-issue-69882-aw-top-10-07-resolve-critical-code-scan-89dec1 branch October 20, 2026 21:04
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.93.0

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[AW Top 10] 07 Resolve critical code scanning and Sighthound alerts

2 participants