Yes, an ESLint plugin is code you trust, because it is a JavaScript module your configuration imports and ESLint runs. Adding one to the config is a dependency change with code execution on every developer machine and CI job that lints. Review it before you merge, not after a warning appears.
Definition
An ESLint plugin is a package that extends ESLint with extra rules, processors or configs. In the current flat config format, the ESLint docs show a plugin being imported at the top of eslint.config.js and registered under a namespace in the config object. By convention the namespace is the package name without the eslint-plugin- prefix. The docs also note that plugins do not need to be published to npm: a local plugin is just a JavaScript object in your own repository.
The consequence: the config file is executable JavaScript, and every plugin it imports is loaded into the same process as the linter. There is no permission model between them.
What a lint plugin can touch
| Context | Exposure |
|---|---|
| Developer machine | Files the user can read, environment variables, network |
| CI lint job | Checked out source, and any secrets present in that job |
| Pre-commit hook | Staged files and the developer's environment |
| Editor integration | The editor process, which also has the user's permissions |
Most plugins only walk the syntax tree. Nothing in the plugin format forces that, though, so the safe assumption is the same as for any package.
How to review a plugin change
- Look at the pull request diff for
package.json, the lock file and the ESLint config together. A new plugin should show up in all three. - Open the package page and the repository. Maintainers, release history and open issues are quick signals.
- Check the package's own install scripts. Lint plugins rarely need any.
- Check the dependency list. A rule plugin that depends on an HTTP client is a question to ask.
- Prefer plugins maintained by the framework or tool authors you already trust, and avoid plugins that exist for one trivial rule when you could write the rule locally in a few lines.
- Pin and review upgrades. Upgrades to lint tooling are easy to merge on autopilot because they feel low risk.
Reduce the exposure in CI
Run linting in a job that has no deployment credentials. A lint job needs the source and nothing more. If your CI system provides job scoped tokens, give the lint job the read only variety. Separating "run untrusted code" from "have secrets" is the single most useful move, and it covers formatters, test plugins and build plugins as well.
Another approach is to run lint in a container with no network. If a plugin needs the network to function, you have learned something.
Shared configs deserve the same treatment
Teams often publish a shared ESLint config package that pulls in a set of plugins. A change to that package changes every repo that depends on it. Review releases of the shared config as you would a library release, and consider pinning exact versions in each consuming repo until the update is reviewed.
Try it yourself
Click through it at your own pace, or open it full screen. Look at how many packages come with each tool you add to the lint toolchain.
Where Safeguard fits
Safeguard's SBOM and dependency scanning covers the npm packages behind your lint toolchain, and policies and gates can check dependency changes before merge. Try the free scan at gold.safeguard.sh/scan.
Quick check
Can a lint plugin read environment variables in CI?
It runs in the same process as ESLint, so it can read whatever that process can read, including any secrets present in the job.
Do plugins have to come from npm?
No. The ESLint docs say a plugin can be a local JavaScript object in your own project.
Sources
Last reviewed: 19 October 2026.