Carry the patch as a small, separate, documented change on top of a pinned upstream version. Record the upstream issue, assign an owner, test it on every upgrade, and set a review date. When the project merges an equivalent fix, delete your copy so you are not maintaining a private fork by accident.
Definition
A carried patch (also called a local patch or downstream patch) is a change you apply to an open source dependency that is not yet in an official release. It is a stopgap between finding a problem and receiving the project's own fix. Done well it is a controlled, temporary exception. Done badly it becomes an undocumented fork.
Steps
- Send it upstream first. The Linux Foundation guide recommends an upstream-first policy so you avoid re-engineering after every release. Open the issue or pull request before you patch locally, and link it. For a vulnerability, use the project's private reporting route.
- Keep the patch minimal. Fix the problem, nothing else. Smaller patches apply cleanly after upgrades and review faster upstream.
- Store it as a patch file or a clearly named branch. Not as edits buried in vendored code. A reviewer should be able to see exactly what differs from upstream.
- Pin the dependency version. Your patch was tested against one version. Pin it, so an automatic upgrade does not silently drop or break the patch.
- Add a test. Write a test that fails without the patch. When the upstream fix lands, the test keeps proving the behavior.
- Record it in a register. One row per patch, as below.
- Review on every upgrade. Reapply, rebuild, run the test. If upstream merged it, remove it.
The patch register
| Field | Example |
|---|---|
| Component and version | libexample 2.4.1 |
| Why we patch | Fix for a parsing flaw that upstream confirmed |
| Upstream link | Issue or pull request URL |
| Owner | A named engineer |
| Test | Name of the test that fails without the patch |
| Review date | Date within the next quarter |
| Removal condition | Remove when version 2.4.2 or later is adopted |
Risks to manage
- Forgotten patches. Without a review date, a stopgap lives for years.
- Scanner confusion. Your build reports the upstream version, but the code is patched. A scanner may flag a vulnerability you already fixed. Record the exception with evidence so the finding can be accepted with a reason. See a security exception template for an open source dependency.
- License and confidentiality slip. A patch you plan to publish must not contain proprietary code. Have the same review you would give any outbound contribution.
- Supply chain confusion. If you publish your patched build to a private registry, name it so nobody mistakes it for the original package.
When to stop carrying and fork
If upstream rejects the change or the project is unmaintained, a long-lived patch is really a fork. Decide that on purpose: assign an owner, a security watcher and an exit plan. See what to do with a dependency whose maintainers have left.
Where Safeguard fits
Safeguard's SBOM and dependency scanning records which versions you ship, reachability analysis helps decide whether the flaw you patched is actually exercised, and policies let you record an accepted exception. A free scan is available at gold.safeguard.sh/scan.
Try it yourself
Click through it at your own pace, or open it full screen. Find the component versions you would pin, then think about where your register entry would live.
Quick check
How long is too long to carry a patch?
There is no fixed rule. A quarterly review date forces a decision: remove it, escalate upstream, or admit it is a fork.
Should the patch be in our repository or a fork?
A patch file or small branch with a register entry is easier to review and remove than a full fork.
Sources
Last reviewed: 19 October 2026.