From 8b7927e03d4e4d288fbb44686a793e2e90597add Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 14 May 2026 03:41:01 +0000 Subject: [PATCH 1/2] feat: add CTR-015 compiler warning for bare * in safe-outputs allowed-labels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When glob pattern support was added to allowed-labels filters for safe-outputs (#32027), a bare "*" pattern became valid but semantically equivalent to omitting the field entirely — all labels are permitted and the restriction is ineffective. A permissive allowed-labels can allow the agent to apply labels that trigger unintended label-driven automation in the repository (e.g., auto-merge, agent-assignment labels). Changes: - pkg/workflow/safe_outputs_allowed_labels_validation.go: new CTR-015 validator that warns when "*" appears in allowed-labels for create-issue, create-discussion, update-discussion, create-pull-request, or merge-pull-request safe-output configs - pkg/workflow/compiler_validators.go: wire CTR-015 validator into the compiler validation pipeline - pkg/workflow/safe_outputs_allowed_labels_validation_test.go: test coverage for all five affected safe-output types and negative cases - specs/compiler-threat-detection-spec.md: bump to v1.0.5, add CTR-015 to rule catalog (§4.1), implementation mapping (§6.1), test catalog (§7.1), and change log (§9) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- pkg/workflow/compiler_validators.go | 4 + .../safe_outputs_allowed_labels_validation.go | 66 ++++++++++ ..._outputs_allowed_labels_validation_test.go | 121 ++++++++++++++++++ specs/compiler-threat-detection-spec.md | 11 +- 4 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 pkg/workflow/safe_outputs_allowed_labels_validation.go create mode 100644 pkg/workflow/safe_outputs_allowed_labels_validation_test.go diff --git a/pkg/workflow/compiler_validators.go b/pkg/workflow/compiler_validators.go index 90f26b558bb..bb4ae467d3e 100644 --- a/pkg/workflow/compiler_validators.go +++ b/pkg/workflow/compiler_validators.go @@ -155,6 +155,10 @@ func (c *Compiler) validateToolConfiguration(workflowData *WorkflowData, markdow log.Printf("Validating push-to-pull-request-branch configuration") c.validatePushToPullRequestBranchWarnings(workflowData.SafeOutputs, workflowData.CheckoutConfigs) + // Emit warnings for bare "*" in allowed-labels (CTR-015) + log.Printf("Validating safe-outputs allowed-labels glob scope") + c.validateSafeOutputsAllowedLabelsGlobScope(workflowData.SafeOutputs) + // Validate network allowed domains configuration log.Printf("Validating network allowed domains") if err := c.validateNetworkAllowedDomains(workflowData.NetworkPermissions); err != nil { diff --git a/pkg/workflow/safe_outputs_allowed_labels_validation.go b/pkg/workflow/safe_outputs_allowed_labels_validation.go new file mode 100644 index 00000000000..e6cab03409e --- /dev/null +++ b/pkg/workflow/safe_outputs_allowed_labels_validation.go @@ -0,0 +1,66 @@ +package workflow + +import ( + "fmt" + "os" + "strings" + + "github.com/github/gh-aw/pkg/console" +) + +var safeOutputsAllowedLabelsValidationLog = newValidationLogger("safe_outputs_allowed_labels") + +// validateSafeOutputsAllowedLabelsGlobScope emits warnings when any safe-outputs +// allowed-labels field contains a bare "*" glob pattern (CTR-015). +// +// A bare "*" in allowed-labels is semantically equivalent to omitting the field +// entirely: all labels are permitted and the restriction is ineffective. This is +// almost always accidental. Authors should use specific names or narrower patterns +// such as "team-*" or "priority-*" instead. +func (c *Compiler) validateSafeOutputsAllowedLabelsGlobScope(config *SafeOutputsConfig) { + if config == nil { + return + } + + type labelledConfig struct { + name string + labels []string + } + + var configs []labelledConfig + + if config.CreateIssues != nil && len(config.CreateIssues.AllowedLabels) > 0 { + configs = append(configs, labelledConfig{"safe-outputs.create-issue.allowed-labels", config.CreateIssues.AllowedLabels}) + } + if config.CreateDiscussions != nil && len(config.CreateDiscussions.AllowedLabels) > 0 { + configs = append(configs, labelledConfig{"safe-outputs.create-discussion.allowed-labels", config.CreateDiscussions.AllowedLabels}) + } + if config.UpdateDiscussions != nil && len(config.UpdateDiscussions.AllowedLabels) > 0 { + configs = append(configs, labelledConfig{"safe-outputs.update-discussion.allowed-labels", config.UpdateDiscussions.AllowedLabels}) + } + if config.CreatePullRequests != nil && len(config.CreatePullRequests.AllowedLabels) > 0 { + configs = append(configs, labelledConfig{"safe-outputs.create-pull-request.allowed-labels", config.CreatePullRequests.AllowedLabels}) + } + if config.MergePullRequest != nil && len(config.MergePullRequest.AllowedLabels) > 0 { + configs = append(configs, labelledConfig{"safe-outputs.merge-pull-request.allowed-labels", config.MergePullRequest.AllowedLabels}) + } + + for _, lc := range configs { + for _, pattern := range lc.labels { + if strings.TrimSpace(pattern) == "*" { + msg := fmt.Sprintf( + "CTR-015: %s contains a bare \"*\" wildcard that matches any label, "+ + "effectively disabling the label restriction.\n\n"+ + "Using \"*\" in allowed-labels has the same effect as omitting the field entirely "+ + "and may allow the agent to apply labels that trigger unintended automation.\n"+ + "Replace with specific label names or narrower patterns (e.g., \"team-*\", \"priority-*\") "+ + "to restrict which labels the agent is allowed to apply.", + lc.name, + ) + safeOutputsAllowedLabelsValidationLog.Printf("Warning: %s", msg) + fmt.Fprintln(os.Stderr, console.FormatWarningMessage(msg)) + c.IncrementWarningCount() + } + } + } +} diff --git a/pkg/workflow/safe_outputs_allowed_labels_validation_test.go b/pkg/workflow/safe_outputs_allowed_labels_validation_test.go new file mode 100644 index 00000000000..95cdc9074e5 --- /dev/null +++ b/pkg/workflow/safe_outputs_allowed_labels_validation_test.go @@ -0,0 +1,121 @@ +//go:build !integration + +package workflow + +import ( + "os" + "path/filepath" + "testing" + + "github.com/github/gh-aw/pkg/testutil" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestCTR015AllowedLabelsGlobScope tests that the compiler warns (CTR-015) when +// a bare "*" wildcard appears in any safe-outputs allowed-labels field. +func TestCTR015AllowedLabelsGlobScope(t *testing.T) { + basePermissions := ` +permissions: + contents: read + issues: read + +on: + issues: + types: [opened] + +engine: claude +strict: false +` + + tests := []struct { + name string + safeOutputs string + expectWarn bool + }{ + { + name: "create-issue with bare * in allowed-labels triggers warning", + safeOutputs: `safe-outputs: + create-issue: + allowed-labels: ["*"] +`, + expectWarn: true, + }, + { + name: "create-discussion with bare * triggers warning", + safeOutputs: `safe-outputs: + create-discussion: + allowed-labels: ["*"] +`, + expectWarn: true, + }, + { + name: "create-pull-request with bare * triggers warning", + safeOutputs: `safe-outputs: + create-pull-request: + allowed-labels: ["*"] +`, + expectWarn: true, + }, + { + name: "merge-pull-request with bare * triggers warning", + safeOutputs: `safe-outputs: + merge-pull-request: + allowed-labels: ["*"] +`, + expectWarn: true, + }, + { + name: "update-discussion with bare * triggers warning", + safeOutputs: `safe-outputs: + update-discussion: + allowed-labels: ["*"] +`, + expectWarn: true, + }, + { + name: "specific label names do not trigger warning", + safeOutputs: `safe-outputs: + create-issue: + allowed-labels: ["bug", "enhancement"] +`, + expectWarn: false, + }, + { + name: "prefix glob pattern does not trigger warning", + safeOutputs: `safe-outputs: + create-issue: + allowed-labels: ["team-*", "priority-*"] +`, + expectWarn: false, + }, + { + name: "mixed specific and bare * triggers warning", + safeOutputs: `safe-outputs: + create-issue: + allowed-labels: ["bug", "*", "enhancement"] +`, + expectWarn: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tmpDir := testutil.TempDir(t, "ctr015-test") + + content := "---\n" + basePermissions + tt.safeOutputs + "---\n\n# Test Workflow\n\nTest body.\n" + wfPath := filepath.Join(tmpDir, "test.md") + err := os.WriteFile(wfPath, []byte(content), 0o600) + require.NoError(t, err, "Should write test workflow file") + + compiler := NewCompiler() + _, _ = compiler.Compile(wfPath) + + if tt.expectWarn { + assert.Greater(t, compiler.GetWarningCount(), 0, + "CTR-015: expected warning for bare \"*\" in allowed-labels") + } + }) + } +} + diff --git a/specs/compiler-threat-detection-spec.md b/specs/compiler-threat-detection-spec.md index 9e4098f5ffa..a81459f2b51 100644 --- a/specs/compiler-threat-detection-spec.md +++ b/specs/compiler-threat-detection-spec.md @@ -7,7 +7,7 @@ sidebar: # GitHub Actions Compiler Threat Detection Specification -**Version**: 1.0.4 +**Version**: 1.0.5 **Status**: Candidate Recommendation **Latest Version**: https://github.com/github/gh-aw/blob/main/specs/compiler-threat-detection-spec.md **Editors**: GitHub Next (GitHub, Inc.) @@ -122,6 +122,7 @@ A conforming implementation MUST include detection coverage for at least the fol - **CTR-012 Safe-Outputs Wildcard Push Scope**: Detect misconfiguration patterns when `safe-outputs.push-to-pull-request-branch: target: "*"` is used; warn when no wildcard fetch pattern is present in checkout (suppressed for public repos) and when no access constraints (`title-prefix` or `labels`) are configured. - **CTR-013 Argument Injection via Package/Image Names**: Detect package or container image names that start with `-` (hyphen) in npm/npx, pip/uv, and Docker frontmatter configurations; reject these names before they are passed to `exec.Command` calls where they would be interpreted as CLI flags, enabling argument injection. - **CTR-014 Supply Chain Attack via Install Scripts**: Detect when `run-install-scripts: true` is configured in workflow frontmatter (globally or per-runtime); warn in non-strict mode and reject in strict mode to protect against malicious npm pre/post install hooks that can exfiltrate secrets or corrupt the runner environment. +- **CTR-015 Allowed Label Glob Scope**: Detect bare `*` wildcard patterns in `safe-outputs.*.allowed-labels` fields (`create-issue`, `create-discussion`, `update-discussion`, `create-pull-request`, `merge-pull-request`); warn when such a pattern is present because it renders the label restriction ineffective and may allow the agent to apply labels that trigger unintended label-driven automation in the repository. ### 4.2 Compiler Response Requirements @@ -209,6 +210,7 @@ Implementations MUST maintain a clear mapping from each active `CTR-*` rule to c | CTR-012 Safe-Outputs Wildcard Push Scope | `pkg/workflow/push_to_pull_request_branch_validation.go` | `pkg/workflow/push_to_pull_request_branch_test.go`, `pkg/workflow/push_to_pull_request_branch_warning_test.go` | | CTR-013 Argument Injection via Package/Image Names | `pkg/workflow/name_validation.go` (shared helper `rejectHyphenPrefixPackages`), `pkg/workflow/npm_validation.go`, `pkg/workflow/pip_validation.go`, `pkg/workflow/docker_validation.go` | `pkg/workflow/argument_injection_test.go` | | CTR-014 Supply Chain Attack via Install Scripts | `pkg/workflow/run_install_scripts_validation.go` (`validateRunInstallScripts`, `resolveRunInstallScripts`) | `pkg/workflow/run_install_scripts_validation_test.go` | +| CTR-015 Allowed Label Glob Scope | `pkg/workflow/safe_outputs_allowed_labels_validation.go` (`validateSafeOutputsAllowedLabelsGlobScope`) | `pkg/workflow/safe_outputs_allowed_labels_validation_test.go` | The mappings above are pattern-based references and MUST be validated against concrete file paths whenever this specification is updated. @@ -247,6 +249,7 @@ The following test IDs map one-to-one to the CTR rules in Section 4.1. Each test | **T-CTR-012** | CTR-012 Safe-Outputs Wildcard Push Scope | Workflow uses `safe-outputs.push-to-pull-request-branch: target: "*"` without a wildcard fetch pattern in checkout (for non-public repos) or without `title-prefix` or `labels` access constraints | Compilation warning identifying the unconstrained wildcard scope and the missing checkout fetch pattern or access constraint; suppressed for public repositories | `CTR-012` | | **T-CTR-013** | CTR-013 Argument Injection via Package/Image Names | A workflow frontmatter declares an npm/npx package, a pip/uv package, or a Docker container image name that starts with `-` (e.g., `--privileged`, `-exploit`) | Compilation failure with error identifying the invalid name, the affected tool kind, and instructing the user to fix the package or image name | `CTR-013` | | **T-CTR-014** | CTR-014 Supply Chain Attack via Install Scripts | A workflow frontmatter sets `run-install-scripts: true` (globally or under `runtimes.node`) | Compilation warning in non-strict mode identifying the supply chain risk and advising removal of `run-install-scripts: true`; compilation failure in strict mode | `CTR-014` | +| **T-CTR-015** | CTR-015 Allowed Label Glob Scope | A workflow frontmatter sets `safe-outputs.*.allowed-labels` to `["*"]` (bare wildcard) for any safe-output type that supports the field (`create-issue`, `create-discussion`, `update-discussion`, `create-pull-request`, `merge-pull-request`) | Compilation warning identifying the field name, explaining that `"*"` disables label restrictions and may permit unintended label-driven automation, and recommending specific names or narrower patterns | `CTR-015` | ### 7.2 Test Coverage Requirements @@ -268,6 +271,12 @@ The following test IDs map one-to-one to the CTR rules in Section 4.1. Each test ## 9. Change Log +### 1.0.5 (2026-05-14) + +- Added CTR-015 Allowed Label Glob Scope (compiler warning when `safe-outputs.*.allowed-labels` contains a bare `"*"` wildcard that effectively disables label restrictions and may permit unintended label-driven automation; triggered by the new glob pattern support for `allowed-labels` introduced in gh-aw #32027) +- Added T-CTR-015 test ID entry in Section 7.1 +- Extended Section 6.1 baseline rule mapping table with CTR-015 implementation references (`safe_outputs_allowed_labels_validation.go`) + ### 1.0.4 (2026-05-13) - Added CTR-014 Supply Chain Attack via Install Scripts (warn/reject when `run-install-scripts: true` is configured; protects against malicious npm pre/post install hooks) From 8ebd1bef6f8ae11774ec814b01ae09ec5445c893 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 14 May 2026 05:13:55 +0000 Subject: [PATCH 2/2] feat: upgrade CTR-015 bare * in allowed-labels from warning to error Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/workflow/compiler_validators.go | 6 ++- .../safe_outputs_allowed_labels_validation.go | 15 +++--- ..._outputs_allowed_labels_validation_test.go | 49 ++++++++++--------- specs/compiler-threat-detection-spec.md | 6 +-- 4 files changed, 40 insertions(+), 36 deletions(-) diff --git a/pkg/workflow/compiler_validators.go b/pkg/workflow/compiler_validators.go index bb4ae467d3e..39a2647c56c 100644 --- a/pkg/workflow/compiler_validators.go +++ b/pkg/workflow/compiler_validators.go @@ -155,9 +155,11 @@ func (c *Compiler) validateToolConfiguration(workflowData *WorkflowData, markdow log.Printf("Validating push-to-pull-request-branch configuration") c.validatePushToPullRequestBranchWarnings(workflowData.SafeOutputs, workflowData.CheckoutConfigs) - // Emit warnings for bare "*" in allowed-labels (CTR-015) + // Reject bare "*" in allowed-labels (CTR-015) log.Printf("Validating safe-outputs allowed-labels glob scope") - c.validateSafeOutputsAllowedLabelsGlobScope(workflowData.SafeOutputs) + if err := c.validateSafeOutputsAllowedLabelsGlobScope(workflowData.SafeOutputs); err != nil { + return formatCompilerError(markdownPath, "error", err.Error(), err) + } // Validate network allowed domains configuration log.Printf("Validating network allowed domains") diff --git a/pkg/workflow/safe_outputs_allowed_labels_validation.go b/pkg/workflow/safe_outputs_allowed_labels_validation.go index e6cab03409e..6a58669cbe4 100644 --- a/pkg/workflow/safe_outputs_allowed_labels_validation.go +++ b/pkg/workflow/safe_outputs_allowed_labels_validation.go @@ -2,24 +2,21 @@ package workflow import ( "fmt" - "os" "strings" - - "github.com/github/gh-aw/pkg/console" ) var safeOutputsAllowedLabelsValidationLog = newValidationLogger("safe_outputs_allowed_labels") -// validateSafeOutputsAllowedLabelsGlobScope emits warnings when any safe-outputs +// validateSafeOutputsAllowedLabelsGlobScope returns an error when any safe-outputs // allowed-labels field contains a bare "*" glob pattern (CTR-015). // // A bare "*" in allowed-labels is semantically equivalent to omitting the field // entirely: all labels are permitted and the restriction is ineffective. This is // almost always accidental. Authors should use specific names or narrower patterns // such as "team-*" or "priority-*" instead. -func (c *Compiler) validateSafeOutputsAllowedLabelsGlobScope(config *SafeOutputsConfig) { +func (c *Compiler) validateSafeOutputsAllowedLabelsGlobScope(config *SafeOutputsConfig) error { if config == nil { - return + return nil } type labelledConfig struct { @@ -57,10 +54,10 @@ func (c *Compiler) validateSafeOutputsAllowedLabelsGlobScope(config *SafeOutputs "to restrict which labels the agent is allowed to apply.", lc.name, ) - safeOutputsAllowedLabelsValidationLog.Printf("Warning: %s", msg) - fmt.Fprintln(os.Stderr, console.FormatWarningMessage(msg)) - c.IncrementWarningCount() + safeOutputsAllowedLabelsValidationLog.Printf("Error: %s", msg) + return fmt.Errorf("%s", msg) } } } + return nil } diff --git a/pkg/workflow/safe_outputs_allowed_labels_validation_test.go b/pkg/workflow/safe_outputs_allowed_labels_validation_test.go index 95cdc9074e5..cccc607bc63 100644 --- a/pkg/workflow/safe_outputs_allowed_labels_validation_test.go +++ b/pkg/workflow/safe_outputs_allowed_labels_validation_test.go @@ -12,7 +12,7 @@ import ( "github.com/stretchr/testify/require" ) -// TestCTR015AllowedLabelsGlobScope tests that the compiler warns (CTR-015) when +// TestCTR015AllowedLabelsGlobScope tests that the compiler rejects (CTR-015) when // a bare "*" wildcard appears in any safe-outputs allowed-labels field. func TestCTR015AllowedLabelsGlobScope(t *testing.T) { basePermissions := ` @@ -31,71 +31,71 @@ strict: false tests := []struct { name string safeOutputs string - expectWarn bool + expectError bool }{ { - name: "create-issue with bare * in allowed-labels triggers warning", + name: "create-issue with bare * in allowed-labels triggers error", safeOutputs: `safe-outputs: create-issue: allowed-labels: ["*"] `, - expectWarn: true, + expectError: true, }, { - name: "create-discussion with bare * triggers warning", + name: "create-discussion with bare * triggers error", safeOutputs: `safe-outputs: create-discussion: allowed-labels: ["*"] `, - expectWarn: true, + expectError: true, }, { - name: "create-pull-request with bare * triggers warning", + name: "create-pull-request with bare * triggers error", safeOutputs: `safe-outputs: create-pull-request: allowed-labels: ["*"] `, - expectWarn: true, + expectError: true, }, { - name: "merge-pull-request with bare * triggers warning", + name: "merge-pull-request with bare * triggers error", safeOutputs: `safe-outputs: merge-pull-request: allowed-labels: ["*"] `, - expectWarn: true, + expectError: true, }, { - name: "update-discussion with bare * triggers warning", + name: "update-discussion with bare * triggers error", safeOutputs: `safe-outputs: update-discussion: allowed-labels: ["*"] `, - expectWarn: true, + expectError: true, }, { - name: "specific label names do not trigger warning", + name: "specific label names do not trigger error", safeOutputs: `safe-outputs: create-issue: allowed-labels: ["bug", "enhancement"] `, - expectWarn: false, + expectError: false, }, { - name: "prefix glob pattern does not trigger warning", + name: "prefix glob pattern does not trigger error", safeOutputs: `safe-outputs: create-issue: allowed-labels: ["team-*", "priority-*"] `, - expectWarn: false, + expectError: false, }, { - name: "mixed specific and bare * triggers warning", + name: "mixed specific and bare * triggers error", safeOutputs: `safe-outputs: create-issue: allowed-labels: ["bug", "*", "enhancement"] `, - expectWarn: true, + expectError: true, }, } @@ -109,11 +109,16 @@ strict: false require.NoError(t, err, "Should write test workflow file") compiler := NewCompiler() - _, _ = compiler.Compile(wfPath) + compileErr := compiler.CompileWorkflow(wfPath) - if tt.expectWarn { - assert.Greater(t, compiler.GetWarningCount(), 0, - "CTR-015: expected warning for bare \"*\" in allowed-labels") + if tt.expectError { + assert.Error(t, compileErr, + "CTR-015: expected error for bare \"*\" in allowed-labels") + assert.Contains(t, compileErr.Error(), "CTR-015", + "CTR-015: error message should reference the rule ID") + } else { + assert.NoError(t, compileErr, + "CTR-015: did not expect error for valid allowed-labels") } }) } diff --git a/specs/compiler-threat-detection-spec.md b/specs/compiler-threat-detection-spec.md index a81459f2b51..35ebe9bf611 100644 --- a/specs/compiler-threat-detection-spec.md +++ b/specs/compiler-threat-detection-spec.md @@ -122,7 +122,7 @@ A conforming implementation MUST include detection coverage for at least the fol - **CTR-012 Safe-Outputs Wildcard Push Scope**: Detect misconfiguration patterns when `safe-outputs.push-to-pull-request-branch: target: "*"` is used; warn when no wildcard fetch pattern is present in checkout (suppressed for public repos) and when no access constraints (`title-prefix` or `labels`) are configured. - **CTR-013 Argument Injection via Package/Image Names**: Detect package or container image names that start with `-` (hyphen) in npm/npx, pip/uv, and Docker frontmatter configurations; reject these names before they are passed to `exec.Command` calls where they would be interpreted as CLI flags, enabling argument injection. - **CTR-014 Supply Chain Attack via Install Scripts**: Detect when `run-install-scripts: true` is configured in workflow frontmatter (globally or per-runtime); warn in non-strict mode and reject in strict mode to protect against malicious npm pre/post install hooks that can exfiltrate secrets or corrupt the runner environment. -- **CTR-015 Allowed Label Glob Scope**: Detect bare `*` wildcard patterns in `safe-outputs.*.allowed-labels` fields (`create-issue`, `create-discussion`, `update-discussion`, `create-pull-request`, `merge-pull-request`); warn when such a pattern is present because it renders the label restriction ineffective and may allow the agent to apply labels that trigger unintended label-driven automation in the repository. +- **CTR-015 Allowed Label Glob Scope**: Detect bare `*` wildcard patterns in `safe-outputs.*.allowed-labels` fields (`create-issue`, `create-discussion`, `update-discussion`, `create-pull-request`, `merge-pull-request`); reject compilation when such a pattern is present because it renders the label restriction ineffective and may allow the agent to apply labels that trigger unintended label-driven automation in the repository. ### 4.2 Compiler Response Requirements @@ -249,7 +249,7 @@ The following test IDs map one-to-one to the CTR rules in Section 4.1. Each test | **T-CTR-012** | CTR-012 Safe-Outputs Wildcard Push Scope | Workflow uses `safe-outputs.push-to-pull-request-branch: target: "*"` without a wildcard fetch pattern in checkout (for non-public repos) or without `title-prefix` or `labels` access constraints | Compilation warning identifying the unconstrained wildcard scope and the missing checkout fetch pattern or access constraint; suppressed for public repositories | `CTR-012` | | **T-CTR-013** | CTR-013 Argument Injection via Package/Image Names | A workflow frontmatter declares an npm/npx package, a pip/uv package, or a Docker container image name that starts with `-` (e.g., `--privileged`, `-exploit`) | Compilation failure with error identifying the invalid name, the affected tool kind, and instructing the user to fix the package or image name | `CTR-013` | | **T-CTR-014** | CTR-014 Supply Chain Attack via Install Scripts | A workflow frontmatter sets `run-install-scripts: true` (globally or under `runtimes.node`) | Compilation warning in non-strict mode identifying the supply chain risk and advising removal of `run-install-scripts: true`; compilation failure in strict mode | `CTR-014` | -| **T-CTR-015** | CTR-015 Allowed Label Glob Scope | A workflow frontmatter sets `safe-outputs.*.allowed-labels` to `["*"]` (bare wildcard) for any safe-output type that supports the field (`create-issue`, `create-discussion`, `update-discussion`, `create-pull-request`, `merge-pull-request`) | Compilation warning identifying the field name, explaining that `"*"` disables label restrictions and may permit unintended label-driven automation, and recommending specific names or narrower patterns | `CTR-015` | +| **T-CTR-015** | CTR-015 Allowed Label Glob Scope | A workflow frontmatter sets `safe-outputs.*.allowed-labels` to `["*"]` (bare wildcard) for any safe-output type that supports the field (`create-issue`, `create-discussion`, `update-discussion`, `create-pull-request`, `merge-pull-request`) | Compilation failure with error identifying the field name, explaining that `"*"` disables label restrictions and may permit unintended label-driven automation, and recommending specific names or narrower patterns | `CTR-015` | ### 7.2 Test Coverage Requirements @@ -273,7 +273,7 @@ The following test IDs map one-to-one to the CTR rules in Section 4.1. Each test ### 1.0.5 (2026-05-14) -- Added CTR-015 Allowed Label Glob Scope (compiler warning when `safe-outputs.*.allowed-labels` contains a bare `"*"` wildcard that effectively disables label restrictions and may permit unintended label-driven automation; triggered by the new glob pattern support for `allowed-labels` introduced in gh-aw #32027) +- Added CTR-015 Allowed Label Glob Scope (compilation error when `safe-outputs.*.allowed-labels` contains a bare `"*"` wildcard that effectively disables label restrictions and may permit unintended label-driven automation; triggered by the new glob pattern support for `allowed-labels` introduced in gh-aw #32027) - Added T-CTR-015 test ID entry in Section 7.1 - Extended Section 6.1 baseline rule mapping table with CTR-015 implementation references (`safe_outputs_allowed_labels_validation.go`)