Edit seven things before the first commit: narrow the triggers, add a permissions block, pin or review each action, remove unused secrets, set a job timeout, name an owner in CODEOWNERS, and test on a branch. Each takes a minute and removes a common source of surprise.
The seven edits
1. Narrow the triggers
Templates usually run on pushes and pull requests to the default branch. GitHub substitutes a placeholder for the default branch name when you pick a template, so check the result is the branch you really protect. If the file runs on every branch and you do not want that, say so in the on block.
2. Add a permissions block
The workflow token can do whatever its permissions allow. GitHub's guidance is to set read access for repository contents as the default and raise it per job when a job needs more. Add this near the top:
permissions:
contents: read
Then give a single job extra scopes only if it needs them, such as writing issues or pull request comments.
3. Pin or review each action
Every uses line is code from another repository running with your token. GitHub says pinning to a full length commit SHA helps mitigate a backdoor being added to the action, and that a tag can be moved or deleted if a bad actor gains access to the action repository. If you keep tags, trust the owner and read the source. See pinning third party actions for the trade offs.
4. Remove secrets you do not need
Some templates reference secrets, for example a package registry token. If your workflow only builds and tests, delete the publish step and the secret reference with it. A secret that is never used cannot leak.
5. Set a job timeout
A hung or hijacked job keeps running and burning minutes. Add timeout-minutes to each job with a value that matches normal run time plus some slack.
6. Name an owner
Add the workflows directory to CODEOWNERS so changes need review from people who understand CI. GitHub documents code owners as a way to control how changes are made to workflow files.
7. Test on a branch
Open a pull request and watch the run. Read the log. Check that nothing prints a secret and that the job does what you think it does.
A before and after sketch
| Item | Typical starter | After your edits |
|---|---|---|
| Permissions | Not set or broad | Contents read at top, raised per job |
| Actions | Version tags | Reviewed, pinned where practical |
| Secrets | Whatever the template mentions | Only those the job uses |
| Timeout | Platform default | Explicit per job |
| Owner | Anyone with write access | CODEOWNERS entry |
Keep it current
Pinning needs a refresh routine, otherwise old versions linger. GitHub notes Dependabot can keep action references up to date. Turn that on once the file is in place.
Try it yourself
Click through it at your own pace, or open it full screen. Notice how a gate turns a pull request into a pass or fail decision before merge.
Quick check
Is a permissions block really needed if the default is read only?
The default token permissions are a repository or organization setting, so check yours. An explicit block in the file makes the intent visible and survives a settings change.
Do I have to pin every action to a SHA?
Not always. Pinning is the stronger choice for third party actions. For actions you trust, a tag plus a source review and Dependabot is a common middle path.
Sources
- Using workflow templates, GitHub Docs
- Secure use reference, GitHub Docs
- Use GITHUB_TOKEN for authentication in workflows, GitHub Docs
Last reviewed: 19 October 2026.