{"id":"CVE-2026-121746","kind":"vulnerability","aliases":["CVE-2026-121746"],"related":[],"title":"nvm: symlinked .nvmrc lets --save overwrite files outside repo","description":"Node Version Manager (nvm) is a POSIX-compliant shell function for managing multiple node.js versions. In versions 0.40.0 through 0.40.8, `nvm use --save` and `nvm install --save` (or `-w`) write the resolved version to `$PWD/.nvmrc` with `tee`, which follows a symbolic link. A repository that commits `.nvmrc` as a symlink to a path outside itself (git recreates the link on clone) therefore makes `--save` truncate any file the user can write, such as a shell startup file or `~/.ssh/authorized_keys`, and replace its contents with the version string, or create the target of a dangling link; the link itself is left unchanged, so `git status` stays clean. The attacker does not control the content written, so this is data loss, not code execution. Version 0.41.0 refuses, with a warning, to write when `.nvmrc` in the current directory is a symlink, dangling or not, rather than writing through it or replacing it.","summary":"In nvm versions 0.40.0 through 0.40.8, running `nvm use --save` or `nvm install --save` writes the version through a symbolic link named .nvmrc, so a repository can point it at a file the user can write, such as a shell startup file or authorized_keys. That file gets truncated and overwritten with the version string, which is data loss rather than code execution.","severity":"medium","cvss":6.7,"epss":null,"exploited":false,"exploited_at":null,"products":[],"ecosystems":[],"tags":["developer-workstations","node","nvm","package","shell"],"not_affected_if":["nvm-0.41.0-or-later","save-flag-unused","trusted-repositories"],"how_to_check":"- Run `nvm --version` and check whether it is between `0.40.0` and `0.40.8`.\n- Look for `.nvmrc` in cloned repositories with `ls -l .nvmrc`; a symbolic link pointing outside the repository is the risky case.","fix":"- nvm `0.41.0` refuses to write when `.nvmrc` is a symlink, dangling or not.","status":"open","published_at":"2026-11-04T22:17:54+00:00","first_seen_at":"2026-11-04T23:08:47+00:00","triaged_at":"2026-11-04T23:09:59+00:00","updated_at":"2026-11-04T23:09:59+00:00","category":"package","confidence":0.8,"triage":{"at":"2026-11-04T23:09:59Z","model":"claude-haiku-5-5","output":{"fix":"- nvm `0.41.0` refuses to write when `.nvmrc` is a symlink, dangling or not.","reach":"local","title":"nvm: symlinked .nvmrc lets --save overwrite files outside repo","impact":"low","summary":"In nvm versions 0.40.0 through 0.40.8, running `nvm use --save` or `nvm install --save` writes the version through a symbolic link named .nvmrc, so a repository can point it at a file the user can write, such as a shell startup file or authorized_keys. That file gets truncated and overwritten with the version string, which is data loss rather than code execution.","audience":"developers","category":"package","nicknames":[],"who_cares":["nvm","node","shell","developer-workstations"],"confidence":0.8,"fix_status":"available","needs_auth":"no","worst_case":"Files the user can write get truncated and overwritten with a version string","analyst_note":"","how_to_check":"- Run `nvm --version` and check whether it is between `0.40.0` and `0.40.8`.\n- Look for `.nvmrc` in cloned repositories with `ls -l .nvmrc`; a symbolic link pointing outside the repository is the risky case.","plain_action":"","needs_analyst":false,"not_affected_if":["nvm-0.41.0-or-later","save-flag-unused","trusted-repositories"],"who_is_affected":"Developers who use nvm 0.40.0 through 0.40.8 and run `nvm use --save` or `nvm install --save` inside a repository whose committed .nvmrc is a symbolic link to a path outside the repository. Git recreates the link on clone, so the exposure comes from cloning untrusted code. Teams that do not use the --save flag, or that run nvm 0.41.0 or later, can skip it.","user_interaction":"yes","needs_special_setup":"yes","severity_if_unknown":"medium"},"cost_usd":0.000771,"input_tokens":4473,"output_tokens":648,"severity_before":"medium"},"analyst_status":null,"analyst_note":null,"search":"'-121746':12A,15A '-2026':11A,14A '/.ssh/authorized_keys':165C '0.40.0':26B,104C '0.40.8':28B,106C '0.41.0':210C 'attack':194C 'author':66B 'clean':192C 'clone':147C 'code':84B,207C 'commit':132C 'compliant':94C 'content':169C,199C 'control':197C 'creat':175C 'current':221C 'cve':10A,13A 'dangl':180C,226C 'data':80B,204C 'develop':17B 'developer-workst':16B 'directori':222C 'execut':85B,208C 'file':7A,54B,64B,69B,153C,163C 'follow':125C 'function':96C 'get':70B 'git':142C,189C 'instal':35B,112C 'key':67B 'left':186C 'let':4A 'link':43B,128C,145C,181C,183C 'loss':81B,205C 'make':149C 'manag':88C,98C 'multipl':99C 'name':44B 'node':19B,86C 'node.js':100C 'nvm':1A,20B,24B,30B,34B,89C,107C,111C 'nvmrc':3A,45B,133C,218C 'outsid':8A,140C 'overwrit':6A 'overwritten':73B 'packag':21B 'path':139C 'point':50B 'posix':93C 'posix-compli':92C 'pwd/.nvmrc':121C 'rather':82B,229C 'recreat':143C 'refus':211C 'replac':167C,235C 'repo':9A 'repositori':48B,130C 'resolv':118C 'run':29B 'save':5A,32B,36B,109C,113C,150C 'shell':22B,62B,95C,161C 'startup':63B,162C 'status':190C 'stay':191C 'string':77B,173C 'symbol':42B,127C 'symlink':2A,136C,225C 'target':177C 'tee':123C 'therefor':148C 'truncat':71B,151C 'unchang':187C 'use':31B,108C 'user':56B,155C 'version':25B,39B,76B,87C,101C,103C,119C,172C,209C 'w':115C 'warn':214C 'workstat':18B 'write':37B,58B,116C,157C,216C,231C 'written':200C","nicknames":[],"mitigations":[],"who_affected":"Developers who use nvm 0.40.0 through 0.40.8 and run `nvm use --save` or `nvm install --save` inside a repository whose committed .nvmrc is a symbolic link to a path outside the repository. Git recreates the link on clone, so the exposure comes from cloning untrusted code. Teams that do not use the --save flag, or that run nvm 0.41.0 or later, can skip it.","tier":"C","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"developers","plain_action":null,"pkeys":[],"ptokens":[],"labels":["developerworkstations","medium","node","nvm","package","shell"],"campaign_type":null,"first_public_at":"2026-11-04T21:31:52+00:00","kev":null,"cvss_vector":"CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:A/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","cvss_by":"7ffcee3d-2c14-4c3e-b844-86c6a321a158","poc_count":0,"sources":[{"source":"nvd","external_id":"CVE-2026-121746","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-121746","severity":null,"published_at":"2026-11-04T22:17:54+00:00","modified_at":"2026-11-04T22:17:54+00:00","first_seen_at":"2026-11-04T23:08:47+00:00","fetched_at":"2026-11-04T23:08:47+00:00","note":null}],"documents":[{"id":71130,"url":"https://github.com/nvm-sh/nvm/commit/3f8411e58d40b904e4ff6a96512391f56bd95bf7","title":"Patch: github.com","kind":"other","source":"nvd","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Patch: github.com"},{"id":71131,"url":"https://github.com/nvm-sh/nvm/security/advisories/GHSA-8qjx-8r8m-mpqh","title":"Vendor advisory: github.com","kind":"vendor","source":"nvd","publisher":"vendor","text":null,"published_at":"2026-11-04T21:31:52+00:00","relation":"advisory","confidence":null,"note":"Vendor advisory: github.com"}],"exploit_sources":[],"notice":"Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai"}