A Babel plugin rewrites your code during the build, and a preset is a shareable bundle of plugins. Both are normal packages that Node.js loads, so they can change every file you compile and can run any code on the build machine. Treat them as trusted production dependencies.
Definitions
Babel's documentation says its code transformations are enabled by applying plugins or presets in a configuration file. If a plugin is on npm, you pass its name and Babel checks that it is installed in node_modules. You can also give a relative or absolute path to a plugin. A preset, per the docs, can act as a sharable set of Babel plugins and options, and many community maintained presets are available on npm.
Frameworks often hide this. The Babel presets page lists Next.js, Nuxt.js, Parcel, Jest and Gatsby as places where you may not configure Babel directly because the tool has its own configuration for it. The plugins still run, you just did not write the list.
What a plugin can change
A plugin receives the syntax tree of each file and returns a modified one. That is the whole point of a transpiler, and it is also the capability a bad actor wants:
- Insert extra code into every bundle, such as a loader for a remote script.
- Rewrite string literals, for example swapping an API endpoint.
- Drop checks, such as a line that validates input.
- Read files or environment variables while it runs, since it is Node code and not sandboxed to the AST.
Most plugins do none of this. The point is that nothing in the mechanism prevents it, so the control has to come from how you choose, pin and review them.
How to review a plugin or preset
- Find out where it is loaded from. Search babel.config files, package.json babel keys and framework config for plugin and preset names.
- Prefer official packages under the @babel scope for common transforms. For others, read the maintainer, release history and dependency list.
- Check what a preset pulls in. A preset can add many plugins, each with their own dependencies. Use npm explain or your lockfile to see the tree.
- Pin the exact version through a committed lockfile and install with npm ci in CI.
- Compare the built output between releases. A new external URL or a block of code that is not in your source is the signal.
- Remove what you do not use. Modern targets need fewer transforms, and fewer plugins means less to trust. A tool that reports unused dependencies helps here, see prove a dependency is unused before you remove it.
A table of risk by plugin type
| Plugin type | Typical risk | Review focus |
|---|---|---|
| Official syntax or env transforms | Low, wide use | Version and lockfile pinning |
| Community macro or codegen plugins | Medium, can inject code | Maintainer and output diff |
| Local plugin in your repo | Same as your code | Normal code review |
| Plugin loaded by path from node_modules | Hidden dependency | Who added it, and why |
What a compromise looks like
Supply chain attacks on build tools tend to arrive through a version bump, not a new package. The practical defence is a lockfile that changes only through reviewed pull requests, and a gate that flags new or updated build dependencies. Our related post on bundler loaders and plugins covers the same pattern for webpack style tooling.
Safeguard's dependency scanning and policy gates treat Babel packages like any other dependency in your SBOM, and you can start with a free scan at gold.safeguard.sh/scan.
Quick check
Is a Babel preset safer than listing plugins myself?
Not by itself. A preset is a convenient bundle of plugins, so it adds their code and dependencies to what you trust.
Can a plugin run code beyond transforming syntax?
Yes. It is a Node.js module, so it runs with the permissions of the build process.
Sources
Last reviewed: 19 October 2026.