@htekdev/actions-debugger 1.0.30 → 1.0.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,99 @@
1
+ id: 'permissions-auth-030'
2
+ title: 'tj-actions/changed-files supply chain attack exposed CI/CD secrets in workflow logs (CVE-2025-30066)'
3
+ category: permissions-auth
4
+ severity: error
5
+ tags:
6
+ - supply-chain
7
+ - tj-actions
8
+ - changed-files
9
+ - cve-2025-30066
10
+ - secrets-exposed
11
+ - security
12
+ - third-party-action
13
+ patterns:
14
+ - regex: 'tj-actions/changed-files@(?:v(?:1|35|44)\b|0e58ed8671d6b60d0890c21b07f8835ace038e67)'
15
+ flags: 'i'
16
+ - regex: '(?:memdump\.py|gist\.githubusercontent\.com/nikitastupin)'
17
+ flags: 'i'
18
+ error_messages:
19
+ - 'Unexpected base64-encoded output in tj-actions/changed-files step logs'
20
+ - 'Unauthorized outbound request to gist.githubusercontent.com detected in workflow run'
21
+ root_cause: |
22
+ Between March 14 and March 15, 2025, attackers compromised the tj-actions/changed-files
23
+ GitHub Action (CVE-2025-30066, GHSA-mw4p-6x4p-x5m5) by retroactively modifying multiple
24
+ version tags to reference a malicious commit SHA
25
+ (0e58ed8671d6b60d0890c21b07f8835ace038e67).
26
+
27
+ The malicious commit injected a Python script that:
28
+ 1. Downloaded a memory-dump utility from a public GitHub Gist
29
+ 2. Scanned the GitHub Actions Runner Worker process memory for secrets
30
+ 3. Base64-encoded the extracted memory content
31
+ 4. Printed the encoded secrets directly to the workflow log
32
+
33
+ For repositories with public workflow logs, these secrets were immediately publicly
34
+ accessible. Over 23,000 repositories were affected.
35
+
36
+ The attack exploited a fundamental trust model weakness: when workflows pin to a version
37
+ tag (e.g., @v35 or @v44.5.1) rather than a specific commit SHA, an attacker who gains
38
+ write access to the upstream repository can silently redirect any tag to malicious code.
39
+ The workflow continues to run without any error — it just also exfiltrates secrets.
40
+
41
+ The compromised tags included: v1.0.0, v35.7.7-sec, v44.5.1, and others.
42
+ The vulnerability window was March 14–15, 2025. Tags have since been updated to safe
43
+ code, but any secrets exposed during that window must be treated as compromised.
44
+ fix: |
45
+ Immediate actions if your workflows ran tj-actions/changed-files between March 14-15, 2025:
46
+ 1. Inspect workflow logs for unexpected base64 output in the changed-files step
47
+ 2. Decode any suspicious output: echo 'BLOB' | base64 -d | base64 -d
48
+ 3. Rotate ALL secrets (API keys, tokens, SSH keys, cloud credentials) that were present
49
+ in any workflow that used the affected action during the vulnerability window
50
+
51
+ For all workflows (ongoing prevention):
52
+ - Pin third-party actions to specific commit SHAs instead of version tags
53
+ - Use tools like StepSecurity Harden-Runner to detect unexpected outbound network calls
54
+ - Use tools like pin-github-action or GitHub's allowed-actions list to enforce SHA pinning
55
+ fix_code:
56
+ - language: yaml
57
+ label: 'Pin third-party actions to a specific commit SHA instead of a version tag'
58
+ code: |
59
+ steps:
60
+ # Vulnerable: tag can be silently repointed to malicious code
61
+ # - uses: tj-actions/changed-files@v44
62
+ # - uses: tj-actions/changed-files@v44.5.1
63
+
64
+ # Safe: commit SHA is immutable — attacker cannot redirect it
65
+ - name: Get changed files
66
+ id: changed-files
67
+ uses: tj-actions/changed-files@823fcebdb31bb97eca5b8e3cd20bb12abfa9b68d
68
+ with:
69
+ files: |
70
+ src/**
71
+ - language: yaml
72
+ label: 'Use StepSecurity Harden-Runner to detect unauthorized outbound network calls'
73
+ code: |
74
+ jobs:
75
+ build:
76
+ runs-on: ubuntu-latest
77
+ steps:
78
+ - name: Harden runner
79
+ uses: step-security/harden-runner@v2
80
+ with:
81
+ egress-policy: audit # or 'block' to prevent unauthorized calls
82
+ - name: Get changed files
83
+ uses: tj-actions/changed-files@823fcebdb31bb97eca5b8e3cd20bb12abfa9b68d
84
+ prevention:
85
+ - 'Always pin third-party GitHub Actions to a specific commit SHA, not a version tag'
86
+ - 'Audit your workflows periodically for version-tagged (not SHA-pinned) third-party actions'
87
+ - 'Use StepSecurity Harden-Runner or similar tooling to detect anomalous outbound network requests in CI'
88
+ - 'Subscribe to security advisories for third-party actions your workflows depend on'
89
+ - 'Rotate secrets immediately if a supply chain compromise is announced for any action you use'
90
+ - 'Consider using a private action mirror with controlled updates rather than pulling from public repos'
91
+ docs:
92
+ - url: 'https://github.com/tj-actions/changed-files/security/advisories/GHSA-mw4p-6x4p-x5m5'
93
+ label: 'GHSA-mw4p-6x4p-x5m5: tj-actions/changed-files supply chain attack advisory'
94
+ - url: 'https://www.cve.org/CVERecord?id=CVE-2025-30066'
95
+ label: 'CVE-2025-30066: NVD entry'
96
+ - url: 'https://docs.github.com/en/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions#using-third-party-actions'
97
+ label: 'GitHub Docs: Security hardening — using third-party actions'
98
+ - url: 'https://docs.stepsecurity.io/harden-runner/'
99
+ label: 'StepSecurity Harden-Runner documentation'
@@ -0,0 +1,97 @@
1
+ id: 'runner-environment-085'
2
+ title: 'Self-hosted runner fails to download immutable actions — `pkg.actions.githubusercontent.com` not in network allowlist'
3
+ category: runner-environment
4
+ severity: error
5
+ tags:
6
+ - self-hosted-runner
7
+ - immutable-actions
8
+ - network
9
+ - allowlist
10
+ - firewall
11
+ - pkg.actions.githubusercontent.com
12
+ - action-download
13
+ patterns:
14
+ - regex: 'Failed to download action.*pkg\.actions\.githubusercontent\.com'
15
+ flags: 'i'
16
+ - regex: 'Unable to locate executable.*pkg\.actions\.githubusercontent\.com'
17
+ flags: 'i'
18
+ - regex: 'Error: An error occurred while loading the action.*pkg\.actions'
19
+ flags: 'i'
20
+ - regex: 'connect(?:ion)? (?:refused|timed? ?out).*pkg\.actions\.githubusercontent\.com'
21
+ flags: 'i'
22
+ error_messages:
23
+ - "Error: Failed to download action 'actions/checkout@v4'. Actions requiring immutable action downloads from pkg.actions.githubusercontent.com are blocked."
24
+ - "Error: An error occurred while loading the action. Connection refused: pkg.actions.githubusercontent.com"
25
+ root_cause: |
26
+ Starting February 2025, GitHub began migrating GitHub-hosted runners to use
27
+ "Immutable Actions" — a system where action code is downloaded from a new dedicated
28
+ CDN host (`pkg.actions.githubusercontent.com`) rather than being cloned directly from
29
+ the action's GitHub repository.
30
+
31
+ Self-hosted runners behind corporate firewalls or with strict network egress allowlists
32
+ fail to download actions when this new domain is not permitted, causing the job to fail
33
+ immediately during the action download phase before any user step runs.
34
+
35
+ The failure is distinct from a runtime error: the runner itself cannot fetch the action
36
+ code, so no build output is produced. Logs show a network-level failure during the
37
+ "Getting action download info" or "Download action repository" phase.
38
+
39
+ Organizations that previously configured their allowlist with `*.github.com`,
40
+ `codeload.github.com`, or `github.com` for action downloads must now also add
41
+ `pkg.actions.githubusercontent.com`.
42
+
43
+ Note: If your allowlist already includes `*.actions.githubusercontent.com`, no change
44
+ is required — the wildcard matches the new subdomain.
45
+ fix: |
46
+ Add `pkg.actions.githubusercontent.com` to your self-hosted runner's outbound network
47
+ allowlist. Runners that already allow `*.actions.githubusercontent.com` via wildcard
48
+ do not require any change.
49
+
50
+ For Azure private networking, also update your NSG template with the additional IP
51
+ ranges published by GitHub in the February 2025 changelog.
52
+
53
+ For GitHub Enterprise Server customers using GitHub Connect: update your self-hosted
54
+ runner allowlists to include the new domain before enabling immutable actions.
55
+ fix_code:
56
+ - language: yaml
57
+ label: 'Required network allowlist domains for self-hosted runners (as of Feb 2025)'
58
+ code: |
59
+ # Ensure these domains/IPs are allowed for outbound HTTPS (443) from your runners:
60
+ #
61
+ # Existing required domains (unchanged):
62
+ # github.com
63
+ # api.github.com
64
+ # *.actions.githubusercontent.com <- wildcard covers new subdomain too
65
+ # codeload.github.com
66
+ # results-receiver.actions.githubusercontent.com
67
+ #
68
+ # New domain required for immutable actions (Feb 2025):
69
+ # pkg.actions.githubusercontent.com
70
+ #
71
+ # If you use domain-specific (not wildcard) allowlists, add:
72
+ # pkg.actions.githubusercontent.com
73
+ - language: yaml
74
+ label: 'Verify immutable actions network access with a diagnostic step'
75
+ code: |
76
+ jobs:
77
+ network-check:
78
+ runs-on: [self-hosted]
79
+ steps:
80
+ - name: Check immutable actions domain reachability
81
+ run: |
82
+ curl -sSf --max-time 10 \
83
+ https://pkg.actions.githubusercontent.com \
84
+ -o /dev/null -w "HTTP %{http_code}\n" \
85
+ || echo "BLOCKED: pkg.actions.githubusercontent.com unreachable"
86
+ prevention:
87
+ - 'Use wildcard domain entries (`*.actions.githubusercontent.com`) in your network allowlist rather than enumerating specific subdomains'
88
+ - 'Subscribe to GitHub Changelog (github.blog/changelog) to catch new domain requirements before they cause outages'
89
+ - 'Periodically run network reachability checks against all required GitHub Actions domains from your runner environment'
90
+ - 'Document your runner network requirements in runbooks and tie allowlist updates to a change management process'
91
+ docs:
92
+ - url: 'https://github.blog/changelog/2025-02-12-notice-of-upcoming-deprecations-and-breaking-changes-for-github-actions/'
93
+ label: 'GitHub Changelog 2025-02-12: Immutable Actions migration and network allowlist updates'
94
+ - url: 'https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/about-self-hosted-runners#communication-between-self-hosted-runners-and-github'
95
+ label: 'GitHub Docs: Self-hosted runner network communication requirements'
96
+ - url: 'https://docs.github.com/en/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions#hardening-for-self-hosted-runners'
97
+ label: 'GitHub Docs: Security hardening for self-hosted runners'
@@ -0,0 +1,97 @@
1
+ id: 'silent-failures-036'
2
+ title: '`if: github.ref == ''main''` silently never matches — ref contains full `refs/heads/main` path'
3
+ category: silent-failures
4
+ severity: silent-failure
5
+ tags:
6
+ - github-ref
7
+ - ref-name
8
+ - branch-comparison
9
+ - if-condition
10
+ - refs/heads
11
+ - silent-skip
12
+ patterns:
13
+ - regex: 'github\.ref\s*[!=]=\s*[''"](?:main|master|develop|release|staging)[''"]'
14
+ flags: 'i'
15
+ - regex: 'github\.ref\s*[!=]=\s*[''"][a-z][a-z0-9_/-]*[^/][''"](?!\s*#.*refs/heads)'
16
+ flags: 'i'
17
+ error_messages:
18
+ - "Step was skipped because the condition was false: github.ref == 'main'"
19
+ - "Job skipped: if: github.ref == 'master'"
20
+ root_cause: |
21
+ `github.ref` always returns the full Git reference path, never just the branch name:
22
+ - Push to `main` branch: `refs/heads/main`
23
+ - Pull request: `refs/pull/123/merge`
24
+ - Tag push: `refs/tags/v1.0.0`
25
+
26
+ When a developer writes `if: github.ref == 'main'`, the condition always evaluates
27
+ to false because `'main'` != `'refs/heads/main'`. The step or job is silently skipped
28
+ with no error — only a "skipped" indicator in the UI, which is easy to overlook.
29
+
30
+ This is the most-viewed GitHub Actions question on Stack Overflow (SO #58033366,
31
+ 478,000+ views), confirming how frequently developers encounter this mismatch.
32
+
33
+ Common variants:
34
+ - `if: github.ref == 'main'` → always false
35
+ - `if: github.ref == 'master'` → always false
36
+ - `if: github.ref != 'main'` → always true (everything runs)
37
+ - `if: github.ref == 'refs/heads/main' && github.ref == 'refs/tags/v*'` → impossible
38
+ (a ref cannot be both)
39
+ - On tag push: `if: github.ref == 'refs/heads/main'` → always false (it is `refs/tags/…`)
40
+ fix: |
41
+ Option 1 — Use `github.ref_name` (recommended, available since runner 2.276.0 / Jan 2022):
42
+ `github.ref_name` returns just the branch or tag name without the `refs/heads/` or
43
+ `refs/tags/` prefix, making comparisons intuitive.
44
+
45
+ Option 2 — Compare against the full ref path:
46
+ Use `github.ref == 'refs/heads/main'` instead of `github.ref == 'main'`.
47
+
48
+ Option 3 — Match on event type:
49
+ Use `github.event_name == 'push'` to restrict steps to push (not PR) events, which is
50
+ often the underlying intent.
51
+ fix_code:
52
+ - language: yaml
53
+ label: 'Use github.ref_name for simple branch/tag name comparison'
54
+ code: |
55
+ jobs:
56
+ deploy:
57
+ runs-on: ubuntu-latest
58
+ steps:
59
+ - name: Deploy to production
60
+ # github.ref_name returns 'main', 'v1.0.0', etc. (no refs/ prefix)
61
+ if: github.ref_name == 'main'
62
+ run: echo "Deploying"
63
+ - language: yaml
64
+ label: 'Use full ref path if you need github.ref specifically'
65
+ code: |
66
+ jobs:
67
+ deploy:
68
+ runs-on: ubuntu-latest
69
+ steps:
70
+ - name: Only on main branch push (not tags or PRs)
71
+ if: github.ref == 'refs/heads/main'
72
+ run: echo "Deploying"
73
+ - name: Only on version tags
74
+ if: startsWith(github.ref, 'refs/tags/v')
75
+ run: echo "Releasing"
76
+ - language: yaml
77
+ label: 'Use event_name to distinguish push from pull_request'
78
+ code: |
79
+ jobs:
80
+ deploy:
81
+ runs-on: ubuntu-latest
82
+ steps:
83
+ - name: Only on direct pushes, not PRs
84
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
85
+ run: echo "Deploying"
86
+ prevention:
87
+ - 'Never compare `github.ref` to a bare branch name — it always includes the `refs/heads/` prefix'
88
+ - 'Prefer `github.ref_name` for branch/tag name comparisons when using runner 2.276.0+ (Jan 2022)'
89
+ - 'Verify your `if:` logic by inspecting the actual `github.ref` value in a debug step: `run: echo "${{ github.ref }}"`'
90
+ - 'Use the GitHub Actions context documentation to confirm which format each context variable uses'
91
+ docs:
92
+ - url: 'https://docs.github.com/en/actions/learn-github-actions/contexts#github-context'
93
+ label: 'GitHub Docs: github context — github.ref and github.ref_name'
94
+ - url: 'https://stackoverflow.com/questions/58033366/how-to-get-the-current-branch-within-github-actions'
95
+ label: 'Stack Overflow #58033366 (428 votes, 478K views): How to get the current branch within GitHub Actions'
96
+ - url: 'https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/using-conditions-to-control-job-execution'
97
+ label: 'GitHub Docs: Using conditions to control job execution'
@@ -0,0 +1,121 @@
1
+ id: 'silent-failures-037'
2
+ title: '`github.event.head_commit` is null on `pull_request` and `workflow_dispatch` events — commit message access silently fails'
3
+ category: silent-failures
4
+ severity: silent-failure
5
+ tags:
6
+ - head-commit
7
+ - commit-message
8
+ - pull-request
9
+ - workflow-dispatch
10
+ - event-payload
11
+ - null-context
12
+ - silent-skip
13
+ patterns:
14
+ - regex: 'github\.event\.head_commit\.(?:message|author|id|timestamp)'
15
+ flags: 'i'
16
+ - regex: 'github\.event\.head_commit\s+is\s+null'
17
+ flags: 'i'
18
+ error_messages:
19
+ - "Error: Unhandled error: TypeError: Cannot read properties of null (reading 'message')"
20
+ - "Expression evaluation failed: github.event.head_commit is null"
21
+ - "Step was skipped because the condition was false: contains(github.event.head_commit.message, '[skip ci]')"
22
+ root_cause: |
23
+ `github.event.head_commit` is only populated on `push` events. It is `null` (not an
24
+ empty object) on all other event types, including:
25
+ - `pull_request` and `pull_request_target`
26
+ - `workflow_dispatch`
27
+ - `workflow_call`
28
+ - `schedule`
29
+ - `release`
30
+ - `repository_dispatch`
31
+
32
+ This causes several silent failure patterns:
33
+ 1. **Silent [skip ci] bypass**: A common pattern is
34
+ `if: "!contains(github.event.head_commit.message, '[skip ci]')"`.
35
+ On a `pull_request` event, `github.event.head_commit` is null, so the expression
36
+ evaluates as `!contains(null, '[skip ci]')` → `!false` → `true`. Every PR run
37
+ executes unconditionally, ignoring any [skip ci] intent.
38
+ 2. **Runtime crash in scripts**: GitHub Script or shell steps that access
39
+ `${{ github.event.head_commit.message }}` on PR events receive an empty string
40
+ silently, or throw a TypeError if accessed via JavaScript.
41
+ 3. **Commit metadata loss in multi-event workflows**: Workflows triggered by both
42
+ `push` and `pull_request` may use `head_commit` data in notifications or logs;
43
+ the PR trigger silently produces empty/null values for all commit fields.
44
+
45
+ This is documented in Stack Overflow question #63441440 (Score: 95, 100,000+ views).
46
+ fix: |
47
+ Use a multi-event compatible approach to access commit messages:
48
+ - For `pull_request`: use `github.event.pull_request.head.sha` and fetch the commit
49
+ via the API, or use `github-script` with `octokit.rest.repos.getCommit()`
50
+ - For `push`: `github.event.head_commit.message` works directly
51
+ - For a robust cross-event solution: use `actions/checkout` with fetch-depth and
52
+ run `git log -1 --format=%s` in a shell step — this works regardless of event type
53
+ - For [skip ci] detection: use the `github.event.commits` array (available on `push`)
54
+ or check PR body/title instead of commit message for multi-event workflows
55
+ fix_code:
56
+ - language: yaml
57
+ label: 'Guard head_commit access with event_name check'
58
+ code: |
59
+ steps:
60
+ - name: Get commit message (push events only)
61
+ if: github.event_name == 'push'
62
+ run: echo "Commit: ${{ github.event.head_commit.message }}"
63
+
64
+ - name: Get HEAD commit message (all events via shell)
65
+ run: |
66
+ MSG=$(git log -1 --format='%s')
67
+ echo "Commit: $MSG"
68
+ - language: yaml
69
+ label: 'Cross-event [skip ci] detection using shell git log'
70
+ code: |
71
+ jobs:
72
+ check-skip:
73
+ runs-on: ubuntu-latest
74
+ outputs:
75
+ skip: ${{ steps.skip-check.outputs.skip }}
76
+ steps:
77
+ - uses: actions/checkout@v4
78
+ with:
79
+ fetch-depth: 2
80
+ - id: skip-check
81
+ run: |
82
+ MSG=$(git log -1 --format='%s')
83
+ if echo "$MSG" | grep -q '\[skip ci\]'; then
84
+ echo "skip=true" >> "$GITHUB_OUTPUT"
85
+ else
86
+ echo "skip=false" >> "$GITHUB_OUTPUT"
87
+ fi
88
+
89
+ build:
90
+ needs: check-skip
91
+ if: needs.check-skip.outputs.skip != 'true'
92
+ runs-on: ubuntu-latest
93
+ steps:
94
+ - run: echo "Building"
95
+ - language: yaml
96
+ label: 'Fetch commit message via API for pull_request events'
97
+ code: |
98
+ steps:
99
+ - name: Get PR head commit message
100
+ if: github.event_name == 'pull_request'
101
+ uses: actions/github-script@v7
102
+ with:
103
+ script: |
104
+ const { data } = await github.rest.repos.getCommit({
105
+ owner: context.repo.owner,
106
+ repo: context.repo.repo,
107
+ ref: context.payload.pull_request.head.sha
108
+ });
109
+ console.log('Commit message:', data.commit.message);
110
+ prevention:
111
+ - 'Always guard `github.event.head_commit` access with `if: github.event_name == ''push''`'
112
+ - 'For multi-event workflows needing commit messages, use `git log -1 --format=%s` after checkout rather than the event context'
113
+ - 'Do not use `github.event.head_commit.message` for [skip ci] detection — it silently fails on PRs and dispatches'
114
+ - 'Add `run: echo "${{ toJSON(github.event) }}"` to debug which event fields are available for each trigger'
115
+ docs:
116
+ - url: 'https://docs.github.com/en/webhooks/webhook-events-and-payloads#push'
117
+ label: 'GitHub Docs: push event payload — head_commit field'
118
+ - url: 'https://docs.github.com/en/webhooks/webhook-events-and-payloads#pull_request'
119
+ label: 'GitHub Docs: pull_request event payload (no head_commit field)'
120
+ - url: 'https://stackoverflow.com/questions/63441440/get-github-commit-message-in-pull-request-actions'
121
+ label: 'Stack Overflow #63441440 (95 votes, 100K views): Get GitHub commit message in pull request Actions'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@htekdev/actions-debugger",
3
- "version": "1.0.30",
3
+ "version": "1.0.31",
4
4
  "description": "65+ real GitHub Actions errors, queryable by agents. CLI + MCP server + Copilot skills + error database.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",