When is it safe to delete an npm override?
August 19, 2026 · 8 min read
You have an override in your package.json that someone added during an incident. Deleting it is either a one-line cleanup or a silent reintroduction of a vulnerability, and the file gives you no way to tell which.
The decision reduces to four questions. Work through them in order; the first no ends the investigation.
tough-cookie to 4.1.3, added for GHSA-72xf-g2v4-qvf3 (prototype pollution). The project depends on @cypress/[email protected], which is where tough-cookie comes from.1. What was this override actually for?
Not every override is a security fix. Some pin a package to dodge a bug, force a duplicate dependency down to one copy, or work around a broken release. Those have different removal criteria entirely, and you need to know which kind you are holding.
If it is a security pin, find the advisory. The pinned version is your best clue — it is almost always the first patched version:
# What advisories exist for the version below your pin?
npm audit --json | jq '.vulnerabilities["tough-cookie"]'
# Or query OSV directly for the version you suspect was vulnerable
curl -s https://api.osv.dev/v1/query \
-H 'Content-Type: application/json' \
-d '{"package":{"name":"tough-cookie","ecosystem":"npm"},"version":"4.1.2"}'You are looking for the advisory's patched range. For our example that is >=4.1.3, which confirms the pin was a security fix and tells you the bar any replacement has to clear.
If you cannot find an advisory
Check the commit that introduced the override and its pull request. If there is no advisory and no explanation, treat it as unknown rather than safe — an override with no recoverable reason is the single most common way a fix gets reverted by accident.
2. Who pulls this package in, and where are they now?
An override is only removable if every path to the vulnerable package now resolves to something safe without it. Start by finding the parents:
npm ls tough-cookie
[email protected]
└─┬ @cypress/[email protected]
└── [email protected] overriddenOne parent here, which is the easy case. Multiple parents is common and matters: the override can only go when all of them have caught up. One straggler keeps the pin alive.
Now check what the newest parent actually depends on:
npm view @cypress/[email protected] dependencies.tough-cookie
# ^4.1.3@cypress/[email protected] asks for ^4.1.3. That satisfies the advisory's >=4.1.3 — the parent has caught up — but an exact pin of 4.1.3 is not the same as a caret range. With the override gone, npm could resolve tough-cookie to 4.1.4. That is a version bump, not a no-op, so Backpatch reports StillNeeded. Review whether the pin is still earning its place; do not treat the parent bump as SafeToRemove.
3. Can you actually take that parent version?
This is the question that most often turns a “yes” into a “not yet.” The fix exists, but it may sit behind an upgrade you are not ready to make.
Compare the parent version you need against the range you currently allow:
- Already in range. You depend on
@cypress/request@^2.88.11and need2.88.12. Same major, satisfied by your existing range — a lockfile update, nothing more. For an exact pin, that still means review, notSafeToRemove. - In-major bump needed. You are pinned to
2.88.11and need2.88.12. Widen the range and re-lock. Low risk, but it is a real change that should go through review and CI. - Major upgrade needed. The safe transitive only arrives with the parent's next major. This is no longer override cleanup — it is a migration, with breaking changes to read and code to touch. The override stays until you do that work deliberately.
4. Does the lockfile agree once the override is gone?
The first three questions are about declared ranges. The lockfile is what actually gets installed, and it is the only thing that settles the argument. Verify rather than reason:
# Remove the override entry, then re-resolve from scratch
rm -rf node_modules package-lock.json
npm install
# What did we actually get?
npm ls tough-cookie
# └─┬ @cypress/[email protected]
# └── [email protected] ← advisory-clear, but not the exact pin
npm audit
npm testA clean re-resolve matters. Updating in place can leave the old resolution pinned in the lockfile, which makes a still-needed override look removable — the most dangerous possible false positive.
If npm ls shows a version at or above the advisory's patched range and npm audit is clean, the pin may have done its advisory job — still review before you delete, especially when the installed version moved.
The short version
| Question | Answer that lets you delete |
|---|---|
| What was it for? | A known advisory, with a patched range you can check against |
| Who pulls it in? | Every parent now resolves to a safe version unaided |
| Can you take that parent? | It is within your range, or an in-major bump you are willing to make |
| Does the lockfile agree? | A clean re-resolve installs the safe version and audit is quiet |
Doing this without the ten minutes per entry
The four questions are mechanical, which means they can be answered for you. Backpatch walks the same path — advisory lookup, parent resolution, in-major versus major classification — for every entry in a package.json at once:
curl -X POST https://api.backpatch.dev/analyze_overrides \
-H "X-API-Key: $BACKPATCH_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @package.json[
{
"packageName": "tough-cookie",
"overriddenVersion": "4.1.3",
"status": "StillNeeded",
"suggestedParentUpgrade": null,
"advisoryId": "GHSA-72xf-g2v4-qvf3",
"reason": "@cypress/[email protected] requires tough-cookie@^4.1.3, which sits entirely above the pinned 4.1.3 rather than inside it."
}
]That is the honest report for this exact pin: StillNeeded, even after the parent bump. SafeToRemove is reserved for cases where removal is a no-op — we are not showing a green example here until Research confirms a fixture. NeedsMajorUpgrade is a third status — and pass your lockfile alongside the package.json when you have one. Question four still belongs to you: re-resolve and run your tests before you merge any deletion.
Backpatch answers this question automatically.
It checks whether the parent dependency already pulls in a safe version, for every override in your package.json, and tells you which ones you can delete. Works as a REST API or an MCP server.