If you want the least access, have contractors work from forks and send pull requests, so they never hold write access to your repository. If speed and CI integration matter more, use short lived branches with write access behind strict branch rules. Pick by the sensitivity of the code, not by habit.
What a fork gives you
GitHub describes a fork as a separate repository with its own settings, permissions and collaboration space, connected to the original (the upstream) so changes flow back through pull requests. A fork is the right choice, GitHub says, when you do not have write access.
For a contractor, that means they can propose any change without being able to push to anything in your repository. A mistake or a stolen laptop in their fleet cannot directly touch your branches.
What a branch gives you
A branch lives inside a single repository, and GitHub recommends branches when you have write access and collaborate in a shared repository. Branches are simpler: the pull request runs in your repository, CI behaves the way it does for staff, and review requests from CODEOWNERS arrive normally.
The price is that the contractor holds Write. As the role guide notes, Write reads repository secrets and can push new branches that trigger workflows.
Comparison of the two approaches
| Factor | Fork and pull request | Branch with Write |
|---|---|---|
| Contractor can push to your repo | No | Yes, to unprotected branches |
| Setup effort | Higher | Lower |
| CI on the pull request | Needs care with secrets | Normal |
| Cleanup at offboarding | Remove access, fork stays theirs | Remove access, delete stale branches |
| Best for | Sensitive or regulated code, short tasks | Embedded engineers, long engagements |
The CI catch with forks
Forks introduce one real hazard. Workflows that run on pull requests from forks are a classic route for secret theft if they are configured badly. GitHub's Actions security guidance warns that the pull_request_target and workflow_run triggers, used together with checking out an untrusted pull request, expose the repository to compromise, because those workflows are privileged and may have write access and access to secrets. It advises avoiding those triggers with untrusted pull requests and never explicitly checking out untrusted code in them.
So a fork model only helps if your pull request workflows run with no secrets and read only tokens. If you must run privileged steps, do them in a separate stage after a maintainer has reviewed the change.
A simple decision guide
- Does the repository hold regulated data logic, signing code or payment flows? Prefer a fork.
- Is the engagement under a month, with a narrow task? Prefer a fork.
- Does the contractor need to run your full CI with secrets to do the work? Prefer a branch, with environment approvals.
- Is the person effectively staff, embedded for many months? Prefer a branch, with the controls below.
Controls that apply either way
- Require pull request review and, where it fits, review from code owners. GitHub notes that a pull request from a fork uses the CODEOWNERS file from the base branch in the upstream repository, so ownership routing still works.
- Dismiss stale approvals when new commits are pushed, so approved work cannot be changed afterwards without a fresh review.
- Keep workflow files under code owner review. See using CODEOWNERS to protect workflow files.
Safeguard's policies and gates can run dependency and vulnerability checks on every pull request, whether it comes from a fork or a branch. A free scan shows what it finds in your repository today.
Try it yourself
Click through it at your own pace, or open it full screen.
Click through the gate and notice that the same checks apply whether a change arrives from a fork or a branch.
Quick check
Does a fork stop a contractor reading my private code?
No. To fork a private repository they need read access first. A fork limits what they can change, not what they can see.
Are pull requests from forks risky for CI?
They can be, if workflows run privileged triggers on untrusted code. GitHub advises avoiding pull_request_target and workflow_run with untrusted pull requests.
Sources
Last reviewed: 19 October 2026.