Fork only when waiting is unacceptable, no safe override exists, and your team can maintain the fork. Otherwise prefer a temporary override, a vendored patch with a pull request upstream, or a replacement. Every option needs an owner and an exit condition, or it becomes permanent by accident.
The options in order of weight
| Option | What it is | Cost | Typical owner |
|---|---|---|---|
| Wait | Accept risk until upstream releases | Lowest effort, risk stays | Service team, with exception record |
| Override | Force another existing version | Low, but may break compatibility | Owner of the root build |
| Patch upstream | Submit a fix and use it when merged | Medium, depends on maintainers | The team that needs it |
| Source level patch | Point to a patched source copy | Medium to high | Owner of the build |
| Fork | Maintain your own copy long term | High, ongoing | A named team |
| Replace | Switch to a different library | High upfront | Service team |
Several ecosystems support source level patching directly. Cargo's patch section lets you put a fixed version of a crate in place of the original, and its documentation describes this for testing a bugfix or preparing a change that is not yet released. Go's replace directive replaces the contents of a specific version of a module, or all versions, with contents found elsewhere, including a local path.
Questions to ask in order
- Is there a released fix? If yes, upgrade or override. A fork is a bad answer to a problem upstream already solved.
- Is the risk reachable? If the vulnerable path is not called, waiting with an exception may be the cheapest safe choice.
- Is the upstream maintained? Look at recent activity and open pull requests, not guesses. A silent project argues for replacing it.
- Can we submit the fix upstream? A patch that gets merged turns your cost into a shared cost.
- Who will maintain the fork? If you cannot name a team and a budget, do not fork.
What changes when you fork
You take on security monitoring for that code, because scanners and advisories track the original package name and version. You also inherit release work, license obligations and the job of merging upstream changes. Document these duties in the decision record.
Scanning gets more complicated too. A patched or forked package may report a different name or version than the advisory data expects, and tools can disagree on whether it is fixed. Record how you verified the fix, so a later scan result does not restart the dispute.
Exit conditions
Write them at the start:
- Upstream releases a version that includes the fix, and tests pass: remove the patch.
- The patch has been open upstream for an agreed period without a response: revisit replacing the library.
- The fork's maintainer team changes: reassign or retire.
Put the review date on a calendar, not in a document nobody reads.
Try it yourself
Click through it at your own pace, or open it full screen. Notice which findings already have a fixed version available, since those should never need a fork.
Quick check
Is a vendored copy the same as a fork?
Close. A vendored copy lives inside your repository and you carry any local changes. Treat it like a fork for ownership and monitoring purposes.
Can we use an override instead of a fork?
If a released version fixes the problem and works with your code, yes. An override forces an existing version. A fork is for when no suitable release exists.
Sources
Last reviewed: 19 October 2026.