Patch what you can't upgrade

Remove a CVE from a dependency without changing its version, using Socket Certified Patches.

Some CVEs can't be fixed by upgrading. The maintainer hasn't released a fix, the fix is a breaking major version, or the package is abandoned. A Socket Certified Patch changes only the vulnerable code inside the installed package. The version in your manifest and lockfile stays the same, so nothing else in the tree moves. Patches are plain text, live in your repository under .socket/, and are reapplied after every install.

Without a Socket tokenWith your organization's token
Free patches only, from Socket's public patch serviceFree patches plus the paid patches your plan includes

Before you start:

  • npm install -g socket. The socket patch commands ship with it.
  • Dependencies installed. Patches apply to installed packages: node_modules for npm, and for Python the .venv in the project folder or the virtual environment that's active.
  • For paid patches, export SOCKET_CLI_API_TOKEN=... and add --org your-org to each command.
  • Network access to patches-api.socket.dev (no token) or api.socket.dev (with a token).

1. Find CVEs that have a patch

Across every repository, list the reachable CVEs that have a patch available:

curl -s -H "Authorization: Bearer $SOCKET_CLI_API_TOKEN" \
  "https://api.socket.dev/v0/orgs/your-org/historical/alerts?range=-30d&per_page=100&filters.cvePatchStatus=patch_available&filters.alertReachabilityType=reachable" \
  | jq -r '[.items[]? | "\(.repoSlug)  \(.artifact.name)@\(.artifact.version)  \(.alert.props.cveId)"] | unique[]'

Drop filters.alertReachabilityType=reachable to see every patchable CVE, not just reachable ones. The query returns up to 100 rows. A larger organization gets more on later pages: the response carries an endCursor for the next one, and without it the list is cut off silently.

For one project, list the patches available for what's installed:

cd /path/to/your-app
npm ci
socket patch scan --json > patches.json
jq '{scannedPackages, packagesWithPatches, freePatches, paidPatches}' patches.json

The packages list in patches.json names each package with a patch and the patch's UUID. Nothing in the project changes.

🚧

Always use --json with scan

Without --json, socket patch scan offers to download and apply every patch it finds. When it isn't run in a terminal (CI, a script, piped output) it doesn't ask: it applies them all and writes .socket/manifest.json.

2. Apply a patch

Get the patch by package name, or by the UUID from patches.json. get downloads it, saves it under .socket/, and applies it to the installed version:

socket patch get minimist                                  # by package name
socket patch get your-patch-uuid                           # or by patch UUID
socket patch list             # shows the package, patch UUID, tier and the CVEs it fixes
npm test

Both forms save exactly one patch, for the version you have installed.

📘

Getting a patch by CVE ID saves every version

socket patch get CVE-... also works, but it saves a patch for every affected version of the package, not just yours. In one test, a single CVE added 27 entries to .socket/manifest.json and applied only the installed one. socket patch list then shows all 27, and socket patch remove takes them out one version at a time. Use the package name or UUID unless you want that.

Review the change before you commit it. .socket/manifest.json lists each patched file with a beforeHash and an afterHash, and file contents are stored by hash in .socket/blobs/. The blob named by a file's afterHash is the patched version. To see exactly what the patch changes, diff it against the same file in an unpatched install (npm ci --ignore-scripts leaves packages unpatched).

3. Reapply it after every install

A fresh npm ci puts the original package back, so the patch has to be reapplied each time dependencies are installed. For npm, add it as a postinstall step:

socket patch setup --yes

This adds "postinstall": "socket patch apply --silent --ecosystems npm" to package.json. Commit package.json and the whole .socket/ folder. With the patched files committed, socket patch apply has nothing to download; add --offline to make it fail rather than fetch if a file is ever missing.

🚧

The postinstall step needs the Socket CLI

Every machine that runs npm install or npm ci for this project, including CI runners and Docker builds, now needs socket on its PATH, or the install fails. Installs run with --ignore-scripts skip postinstall, so the patch isn't applied there; run socket patch apply explicitly after those.

For Python there's no postinstall hook. Run the apply step after installing, from the project folder that holds .venv, or with the virtual environment you install into activated:

uv sync                       # or: pip install -r requirements.txt
socket patch apply --ecosystems pypi

4. Check it in CI

socket patch apply --json reports "status": "success" even when it patched nothing, for example when node_modules is missing or the installed version no longer matches the patch. So the gate checks the counts as well as the status:

out=$(socket patch apply --json)
echo "$out" | jq -e '.status == "success" and (.patchesApplied + .alreadyPatched) > 0' >/dev/null \
  || { echo "Socket patch apply: $(echo "$out" | jq -c '{status, patchesApplied, alreadyPatched, failed}')"; exit 1; }

alreadyPatched counts patches the postinstall step already applied. Other status values are partial_failure, no_manifest and error.

Undo a patch

socket patch rollback "pkg:npm/[email protected]"   # restore the original files, keep the patch saved
socket patch remove "pkg:npm/[email protected]"     # roll back and delete it from .socket/

Omit the identifier on rollback to roll back every patch.

Verify

  • socket patch list shows the patch and the CVE it fixes
  • Your tests pass with the patch applied
  • After rm -rf node_modules && npm ci, socket patch apply --json shows alreadyPatched of 1 or more, because postinstall reapplied the patch
  • socket patch rollback restores the original files, and socket patch apply patches them again

Troubleshooting

SymptomCauseFix
scan reports 0 patches everywhereThe patch service can't be reached. scan doesn't report connection errorsCheck access to patches-api.socket.dev or api.socket.dev. socket patch get with a package name does show the error
Python packages aren't found, or the wrong ones areNo .venv in the folder and none active, so scan reads the system Python's packagesRun from the folder that holds .venv, or activate the venv you install into
Only free patches are offeredNo token, or no orgSet SOCKET_CLI_API_TOKEN and pass --org your-org
The patch silently stops applying (patchesApplied 0, status still success)The installed version isn't the one the patch was made for, usually after an upgradeEach patch is for one exact version. socket patch remove it and check whether the new version still needs one. The step 4 gate catches this
socket patch list shows versions you don't haveThe patch was fetched by CVE IDRemove the extra versions with socket patch remove, or fetch by package name next time
npm install or npm ci fails with npm error code 127 and npm error command sh -c socket patch apply --silent --ecosystems npmThe postinstall step ran where the Socket CLI isn't installedInstall socket on that machine or image

Reference


Did this page help you?