To review a project's GitHub Actions before adopting it, open the .github/workflows folder and check four things: whether untrusted text flows into shell commands, whether the token is limited to read-only, whether third-party actions are pinned to a full commit SHA, and whether privileged triggers check out pull request code.
Why the workflow matters to you
Your dependency's release is made by its CI. If an attacker can run code in that CI, they can alter what gets published, and you install it. OpenSSF Scorecard treats this seriously: its Dangerous-Workflow check carries the highest weight in the aggregate. Reading the files yourself takes ten minutes.
The four checks
1. Script injection
GitHub's hardening guide warns against interpolating untrusted values, such as a pull request title, directly into an inline script. The safe pattern is to pass the value through an env: entry and reference the environment variable in the shell. Search the files for github.event inside a run: block.
2. Token permissions
GitHub recommends setting the default token permission to read-only and raising it only for jobs that need more. Look for a permissions: block near the top of each workflow. A missing block is not proof of a problem, since the repository default may be restrictive, but it is a question to ask.
3. Pinned actions
GitHub advises pinning each third-party action to a full-length commit SHA, because a tag can be moved or deleted. Seeing uses: owner/action@v3 is common and less strict. It tells you how much the maintainers worry about a compromised action.
4. Privileged triggers
GitHub tells authors not to use pull_request_target unless they need its privileged context, and not to check out untrusted pull request code in workflows that use it. workflow_run is the recommended alternative for privilege separation.
A quick table
| Look for | Good sign | Question to ask |
|---|---|---|
run: with event data | Values passed through env | Is any title, branch or body used inline? |
permissions: | Read-only default | Which job gets write access, and why? |
uses: | Full SHA | Is a tag trusted without review? |
pull_request_target | Absent, or no checkout of PR code | Does it run fork code with secrets? |
npm publish | Trusted publishing or provenance | Does a long-lived token publish? |
Trusted publishing on npm uses short-lived OpenID Connect credentials tied to a workflow instead of long-lived tokens, which removes the risk of a leaked write token. If you see it, note it as a plus. Our post on the AsyncAPI pipeline hijack shows why you still keep reviewing.
What a bad result means
You do not have to reject the project. You can choose to vendor, pin, or ask the maintainer to fix it. Many maintainers welcome a polite issue, and private vulnerability reporting is available where enabled.
Safeguard can help here. Its SBOM and dependency scanning, reachability analysis and policy gates cover the checks that should repeat after adoption, and the free scan at gold.safeguard.sh/scan shows what a project already depends on.
Quick check
Do I need to be a CI expert to do this?
No. Searching for four patterns is enough for a first pass. Escalate to a security engineer if you find privileged triggers with untrusted checkout.
Does a clean workflow mean a safe release?
It lowers one class of risk. Account takeover and malicious maintainers are separate problems.
Sources
- GitHub Docs: security hardening for GitHub Actions
- OpenSSF Scorecard repository
- npm Docs: trusted publishing
Last reviewed: 19 October 2026.