Skip to content

Commit 176b904

Browse files
[New Rule] GitHub Actions Workflow Injection Blocked
Fixes #5431
1 parent 793ecfe commit 176b904

File tree

1 file changed

+120
-0
lines changed

1 file changed

+120
-0
lines changed
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
[metadata]
2+
creation_date = "2025/12/05"
3+
integration = ["github"]
4+
maturity = "production"
5+
updated_date = "2025/12/05"
6+
7+
[rule]
8+
author = ["Elastic"]
9+
description = """
10+
Detects when a GitHub Actions workflow attempts to create or modify workflow files in a protected branch but is blocked
11+
due to insufficient permissions. This behavior is indicative of a supply chain attack where a malicious package or
12+
compromised CI/CD pipeline attempts to inject persistent backdoor workflows into a repository. The Shai Hulud 2.0 attack
13+
demonstrated this technique by using npm preinstall hooks to push malicious workflow files that enable command injection
14+
or secrets exfiltration.
15+
"""
16+
false_positives = [
17+
"""
18+
Legitimate CI/CD automation that requires workflow file modifications may trigger this alert if not properly
19+
configured with the necessary permissions. Review the workflow configuration and ensure the GITHUB_TOKEN or PAT has
20+
the required 'workflows' permission if the modification is intentional.
21+
""",
22+
]
23+
from = "now-9m"
24+
interval = "8m"
25+
language = "esql"
26+
license = "Elastic License v2"
27+
name = "GitHub Actions Workflow Injection Blocked"
28+
note = """## Triage and analysis
29+
30+
### Investigating GitHub Actions Workflow Injection Blocked
31+
32+
This rule detects attempts to push workflow files to a GitHub repository from within a GitHub Actions workflow that are blocked by GitHub's security controls. This is a key indicator of supply chain attacks where malicious code attempts to establish persistence by injecting backdoor workflows.
33+
34+
### Possible investigation steps
35+
36+
- Review the `github.repo` field to identify which repository was targeted.
37+
- Examine the `github.actor` to determine if the action was triggered by a bot (`github-actions[bot]`) or a user account (PAT-based).
38+
- Check recent workflow runs in the repository for suspicious activity, especially in jobs that run `npm install` or other package manager commands.
39+
- Review the repository's dependencies for recently added or updated packages that may contain malicious preinstall/postinstall hooks.
40+
- Examine the `github.reasons.message` field for details on which workflow file was being created or modified.
41+
- Search for other repositories in the organization that may have the same malicious dependency.
42+
- Review GitHub audit logs for successful workflow file modifications that may have occurred before protections were enabled.
43+
44+
### False positive analysis
45+
46+
- Legitimate automation tools that manage workflow files may trigger this alert. Verify if the repository uses tools like Dependabot, Renovate, or custom automation that modifies workflows.
47+
- CI/CD pipelines that intentionally update workflow files should use a PAT with the 'workflows' scope and be documented.
48+
49+
### Response and remediation
50+
51+
- If this is a confirmed attack attempt, immediately audit all dependencies in the affected repository.
52+
- Remove any suspicious packages and regenerate lock files.
53+
- Rotate any secrets that may have been exposed during the CI run.
54+
- Review and revoke any PATs that may have been compromised.
55+
- Enable branch protection rules requiring pull request reviews for workflow file changes.
56+
- Consider implementing CODEOWNERS for `.github/workflows/` directory.
57+
- Search for indicators of compromise such as unexpected workflow files (e.g., `discussion_*.yaml`, `formatter_*.yml`).
58+
"""
59+
references = ["https://www.wiz.io/blog/shai-hulud-2-0-ongoing-supply-chain-attack"]
60+
risk_score = 47
61+
rule_id = "e8b37f18-4804-4819-8602-4aba1169c9f4"
62+
severity = "medium"
63+
tags = [
64+
"Domain: Cloud",
65+
"Use Case: Threat Detection",
66+
"Tactic: Persistence",
67+
"Tactic: Execution",
68+
"Data Source: Github",
69+
"Resources: Investigation Guide",
70+
]
71+
timestamp_override = "event.ingested"
72+
type = "esql"
73+
74+
query = '''
75+
from logs-github.audit-* metadata _id, _index, _version
76+
| where
77+
data_stream.dataset == "github.audit" and
78+
event.action == "protected_branch.rejected_ref_update" and
79+
github.category == "protected_branch" and
80+
github.reasons.code == "workflow_updates" and
81+
match(github.reasons.message::STRING, "refusing to allow a GitHub App to create or update workflow")
82+
| keep *
83+
'''
84+
85+
86+
[[rule.threat]]
87+
framework = "MITRE ATT&CK"
88+
[[rule.threat.technique]]
89+
id = "T1195"
90+
name = "Supply Chain Compromise"
91+
reference = "https://attack.mitre.org/techniques/T1195/"
92+
[[rule.threat.technique.subtechnique]]
93+
id = "T1195.002"
94+
name = "Compromise Software Supply Chain"
95+
reference = "https://attack.mitre.org/techniques/T1195/002/"
96+
97+
98+
[[rule.threat.technique]]
99+
id = "T1546"
100+
name = "Event Triggered Execution"
101+
reference = "https://attack.mitre.org/techniques/T1546/"
102+
103+
104+
[rule.threat.tactic]
105+
id = "TA0003"
106+
name = "Persistence"
107+
reference = "https://attack.mitre.org/tactics/TA0003/"
108+
[[rule.threat]]
109+
framework = "MITRE ATT&CK"
110+
[[rule.threat.technique]]
111+
id = "T1059"
112+
name = "Command and Scripting Interpreter"
113+
reference = "https://attack.mitre.org/techniques/T1059/"
114+
115+
116+
[rule.threat.tactic]
117+
id = "TA0002"
118+
name = "Execution"
119+
reference = "https://attack.mitre.org/tactics/TA0002/"
120+

0 commit comments

Comments
 (0)