lote.guide
esc
  • npm lifecycle scriptsscripts field in package.jsonNode.js
  • setup.py arbitrary code executionsetup.py in source distributions (sdist)Python
  • NODE_OPTIONS preload injectionNODE_OPTIONS environment variable, CLI flags, or .env files loaded via --env-fileNode.js
  • .pth file import execution*.pth files on sys.path (commonly site-packages)Python
  • binding.gyp / node-gyp native compilationbinding.gyp file in the package rootNode.js
  • Corepack (packageManager field)"packageManager" field in package.json, COREPACK_HOME cache directoryNode.js
  • .npmrc registry manipulation.npmrc file (project, user, or global)Node.js
  • overrides / resolutions dependency swapoverrides (npm) or resolutions (Yarn) field in package.jsonNode.js
  • pnpm hooks (pnpmfile.cjs).pnpmfile.cjs in the project rootNode.js
  • .yarnrc.yml plugins and registry.yarnrc.yml in the project rootNode.js
  • pyproject.toml build backendspyproject.toml [build-system] tablePython
  • sitecustomize / usercustomize auto-importsitecustomize.py / usercustomize.py on sys.path (usually site-packages)Python
  • .node native addon loading.node files in node_modules/ (typically under build/Release/ or prebuilds/)Node.js
  • Yarn Plug'n'Play (.pnp.cjs).pnp.cjs in the project rootNode.js
  • __init__.py execution on import__init__.py in any package directory on sys.pathPython
  • .pyc bytecode cache poisoning.pyc files in __pycache__/ directories alongside source modulesPython
  • PYTHONPATH / PYTHONHOME module shadowingPYTHONPATH / PYTHONHOME environment variablesPython
  • npx / npm exec remote executionnpx, npm exec, npm create / npm init (initializer flows)Node.js
  • conftest.py auto-loading (pytest)conftest.py files in any directory pytest traversesPython
  • NODE_PATH environment variableNODE_PATH environment variableNode.js
  • "imports" field (subpath imports)imports field in package.jsonNode.js
  • require.extensions / Module._extensionsrequire.extensions / Module._extensions in any loaded moduleNode.js
  • .egg files and EGG-INFO scripts.egg files in site-packages (registered via easy-install.pth)Python
  • Zip imports (zipimport).zip / .pyz files on sys.path, or passed directly to the interpreterPython
  • PYTHONSTARTUP environment variablePYTHONSTARTUP environment variablePython
  • node_modules/.hooks/ directorynode_modules/.hooks/ directoryNode.js
Node.js
Module resolution/File on disk

Yarn Plug'n'Play (.pnp.cjs)

On every Node process that loads it (yarn node, yarn run, or explicit --require)

Lives in
.pnp.cjs in the project root
Attacker needs
Supply-chain foothold
Lifecycle
Install
Startup
your code
Module load
Runtime
REPL

Runs on import or require, for every module the app loads.

How it runs

Yarn Berry (v2+) replaces node_modules with Plug'n'Play. A generated .pnp.cjs file acts as a custom module resolver by patching Node's Module._resolveFilename. In effect it's a universal preload that controls all module resolution for the process.

.pnp.cjs is JavaScript. It's checked into the repo, as Yarn recommends, and loaded on every Node invocation through Yarn tooling. It's usually thousands of lines of generated code, so a one-line backdoor blends into what looks like a normal regen diff.

node --require ./.pnp.cjs app.js   # yarn node / yarn run add this automatically

Two areas of a diff matter for security. Near the top, the RAW_RUNTIME_STATE blob lists each package's packageLocation and packageDependencies. Repoint a location at an attacker directory and you've swapped what resolves without touching node_modules in the classic way. Further down, Yarn wraps _resolveFilename. A malicious diff can add an early return for specific requests and bypass the registry entirely. And because .pnp.cjs is executable JavaScript, any statement in it runs the moment Node loads the shim, before your entrypoint.

Defend

Review .pnp.cjs diffs beyond the boilerplate. Watch packageLocation, packageDependencies, and _resolveFilename patches; regenerate from trusted installs only.