dnpm: Secure Docker NPM Wrapper That Blocks Supply Chain Attacks
What Is dnpm and Why Do You Need It?
dnpm is a drop-in npm wrapper that runs every install, build, and dev command inside a hardened Docker container. It adds 12 security layers to your existing npm workflow without changing how you work. Configure your setup in seconds with the free dnpm Configurator and download all files as a ZIP.
In April 2026, compromised versions of axios (1.14.1 and 0.30.4) were published to npm with a remote access trojan hidden in a postinstall script. Anyone who ran npm install on bare metal gave the malware full access to their filesystem, SSH keys, environment variables, and credentials. This was not the first npm supply chain attack, and it will not be the last.
dnpm exists because npm install should not be a security risk. Your package manager should not have unrestricted access to your entire machine.
The Problem: npm install Runs Untrusted Code on Your Machine
Every time you run npm install, npm executes lifecycle scripts (preinstall, postinstall, prepare) from every package in your dependency tree. These scripts run with your full user permissions.
- Full filesystem access — postinstall scripts can read ~/.ssh, ~/.aws, ~/.gnupg, and any file your user can access
- Network access — scripts can exfiltrate data to any remote server
- Process execution — scripts can spawn processes, install backdoors, modify your shell profile
- No isolation — npm provides zero sandboxing by default
- Transitive risk — a compromised sub-dependency 5 levels deep runs with the same permissions as your code
The axios RAT incident proved this is not theoretical. The malicious postinstall script in axios 1.14.1 installed a persistent backdoor that survived package removal. It operated silently, exfiltrating credentials while developers continued working.
How dnpm Solves This: 12 Security Layers
dnpm wraps npm inside a Docker container with defense-in-depth security. Even if malicious code executes inside the container, it cannot reach your host system or exfiltrate data.
Layer 1: Read-Only Project Mount
Your entire project directory is mounted as read-only inside the container. Malicious packages cannot modify your source code, inject backdoors into build scripts, or tamper with configuration files. Only dist/, .astro/, package.json, and package-lock.json are writable (and only during specific operations).
Layer 2: All Linux Capabilities Dropped
Every Linux capability is dropped with cap_drop: ALL. Packages cannot use CAP_NET_RAW (network sniffing), CAP_SYS_ADMIN (filesystem mounting), CAP_DAC_OVERRIDE (bypassing file permissions), or any other privileged operation.
Layer 3: Seccomp Syscall Filtering
A custom seccomp profile restricts the container to a whitelist of safe syscalls. Socket creation is limited to AF_UNIX (local IPC), AF_INET (IPv4), AF_INET6 (IPv6), and AF_NETLINK (needed for Vite). No raw sockets, no packet manipulation, no kernel exploits.
Layer 4: Postinstall Scripts Blocked by Default
The NPM_CONFIG_IGNORE_SCRIPTS=true environment variable disables all lifecycle scripts during installation. The #1 attack vector — the same one used in the axios RAT — is neutralized at the container level.
Layer 5: Offline Builds (Zero Network)
Build and rebuild commands run with network_mode: none. Even if a malicious script somehow executes during the build phase, it has zero network access. It cannot phone home, cannot exfiltrate data, cannot download additional payloads.
Layer 6: Non-Root User
All operations run as the node user (UID 1000), not root. Container breakout exploits that require root privileges are blocked. No setuid, no setgid, no privilege escalation.
Layer 7: no-new-privileges
The no-new-privileges security option prevents any process inside the container from gaining elevated permissions through setuid or setgid binaries, closing another common escalation path.
Layer 8: Registry Pinned to npmjs.org
The npm registry is hardcoded to registry.npmjs.org via environment variable. This prevents dependency confusion attacks where an attacker publishes a malicious package with the same name as your private package on an alternate registry.
Layer 9: noexec /tmp
The /tmp directory is mounted with the noexec flag. A common attack pattern is to download a binary to /tmp and execute it. With noexec, any binary in /tmp is blocked from executing regardless of its permissions.
Layer 10: Resource Limits
Memory, CPU, and PID limits prevent fork bombs and resource exhaustion attacks. A malicious package cannot crash your system by spawning thousands of processes or consuming all available memory. Default limits: 4GB RAM, 4 CPUs, 256 PIDs.
Layer 11: Lockfile Integrity Check
Before every install, dnpm scans package-lock.json for non-npmjs.org resolved URLs. If any dependency resolves to a suspicious registry, dnpm warns you and asks for confirmation. This detects lockfile poisoning attacks where an attacker modifies resolved URLs to point to malicious packages.
Layer 12: Two-Phase Install
Dependencies are installed in two isolated phases:
- Phase 1: Download —
npm ciruns with scripts disabled and network enabled. Packages are downloaded but no lifecycle scripts execute. - Phase 2: Rebuild —
npm rebuildruns with scripts enabled but zero network access. Native modules compile, but even if a malicious postinstall runs, it cannot reach the internet.
This separation ensures that code execution and network access never happen simultaneously.
Step-by-Step: Setting Up dnpm
Step 1: Configure Your Setup
Visit the dnpm Configurator and select your project settings. Choose your framework (Astro, Next.js, Vite, Remix, or generic Node.js), Node.js version, dev server port, and resource limits. The configurator generates all four files in real-time.
Step 2: Download the Files
Click "Download All Files (.zip)" to get:
- dnpm — the shell script wrapper (goes in project root)
- Dockerfile — hardened Node.js container (goes in
.dnpm/) - seccomp-profile.json — syscall whitelist (goes in
.dnpm/) - docker-compose.node.yml — service definitions (goes in project root)
Step 3: Make dnpm Executable
chmod +x dnpm
Step 4: Run Setup
./dnpm setup
This builds the Docker image, installs dependencies with scripts disabled, then runs postinstall scripts with zero network access. Takes about 30 seconds for the initial build, under 10 seconds for subsequent installs.
Setup also automatically prepends dnpm usage instructions to your project's CLAUDE.md file (or creates one if it doesn't exist). This ensures AI coding assistants like Claude Code know to use ./dnpm instead of bare npm. The injection is idempotent — running setup multiple times won't duplicate the instructions.
After installation completes, setup automatically runs dnpm check — a 6-point security scan of your dependencies (see below).
Step 5: Start Developing
./dnpm run dev # Start dev server ./dnpm install axios # Add packages (sandboxed) ./dnpm run build # Build with zero network ./dnpm check # Run 6-point security scan ./dnpm shell # Debug shell inside container
Every command you know from npm works identically. dnpm just adds the security container around it.
Security Scanning with dnpm check
dnpm check runs a comprehensive 6-point security scan on your installed dependencies, all inside the Docker container:
-
Lockfile integrity — verifies that all resolved URLs in
package-lock.jsonpoint to the official npm registry. Detects lockfile poisoning attacks where resolved URLs are swapped to malicious registries. -
npm audit — runs the standard
npm auditvulnerability check against the npm advisory database. Reports known CVEs in your dependency tree. -
Signature verification — verifies npm package signatures using
npm audit signatures. Ensures packages haven't been tampered with after publishing. -
Socket.dev behavioral analysis — uses the Socket.dev CLI to perform behavioral analysis on your dependencies. Detects install scripts, network access, filesystem access, shell execution, environment variable reading, and other suspicious behaviors that traditional vulnerability scanners miss.
-
Deprecated packages — identifies any deprecated packages in your dependency tree that should be replaced.
-
Container image CVEs — scans the Docker image itself for known vulnerabilities using Trivy, ensuring the container runtime is not introducing security risks.
Reports
Every scan saves a clean-text report (no ANSI color codes) to .dnpm/reports/:
.dnpm/reports/security-check-{timestamp}.txt— timestamped report for audit trails.dnpm/reports/latest.txt— always points to the most recent scan result
You can review the latest report at any time:
cat .dnpm/reports/latest.txt
dnpm check runs automatically after dnpm setup, so your first install always includes a full security audit. You can also run it manually at any time — after adding packages, before deploying, or as part of your CI pipeline.
dnpm vs npm vs bun: Security Comparison
| Protection | npm | bun | dnpm |
|---|---|---|---|
| Runs postinstall by default | Yes | No | No |
| Read-only project mount | No | No | Yes |
| Offline builds (no network) | No | No | Yes |
| Seccomp syscall filtering | No | No | Yes |
| Non-root container user | No | No | Yes |
| All capabilities dropped | No | No | Yes |
| noexec /tmp | No | No | Yes |
| Lockfile integrity check | No | No | Yes |
| Registry pinned | No | No | Yes |
| Resource limits | No | No | Yes |
| Filesystem isolation | No | No | Yes |
| Two-phase install | No | No | Yes |
bun's approach of skipping postinstall scripts is a good first step, but it only blocks one attack vector. The malicious code is still downloaded to node_modules, and bun provides no filesystem isolation, no network restrictions, and no syscall filtering. dnpm provides defense-in-depth: even if one layer fails, the other 11 still protect you.
FindUtils provides the dnpm Configurator completely free, with no signup required. Generate your secure npm setup in seconds.
Real-World Scenarios
Scenario 1: The axios RAT Attack
With bare npm, running npm install [email protected] would execute the malicious postinstall script with full access to your machine. With dnpm:
- Postinstall scripts are disabled during download (Phase 1)
- During rebuild (Phase 2), the script runs but has zero network access
- Even if the RAT installs, it cannot exfiltrate data
- Your project files are read-only — the RAT cannot modify your source code
Scenario 2: Dependency Confusion
An attacker publishes @your-company/internal-pkg on a public registry. With npm, your lockfile might resolve to the malicious public version. With dnpm:
- Registry is pinned to npmjs.org only
- Lockfile integrity check flags non-npmjs.org resolved URLs
- Even if the package installs, scripts are blocked
Scenario 3: Cryptominer in postinstall
A popular package's maintainer account is compromised. The new version includes a postinstall script that downloads and runs a cryptominer. With dnpm:
/tmphas noexec — binaries cannot execute from temp- Network is disabled during rebuild — the miner cannot be downloaded
- Resource limits prevent CPU exhaustion even if it somehow runs
Scenario 4: React Native / Expo Projects
React Native and Expo require node_modules on the host filesystem because Metro bundler and Xcode/Gradle need direct access to the files. But you still want sandboxed installs. dnpm sync bridges this gap:
./dnpm setup # Install deps in Docker sandbox ./dnpm sync # Copy sandboxed node_modules to host npx expo start # Metro can now access the modules
dnpm sync copies the sandboxed node_modules from the Docker volume to your host project directory. Your install stays protected by all 12 security layers, and the native toolchain gets the filesystem access it needs.
Scenario 5: CI/CD Pipeline Protection
Your CI server runs npm ci on every push. A compromised dependency could access CI secrets, deployment keys, and production credentials. With dnpm:
- All 12 security layers protect the CI environment
./dnpm cidrops to the same two-phase install- Add
--no-rebuildto skip postinstall entirely for maximum safety
Common Mistakes to Avoid
Mistake 1: Running npm install on Bare Metal
The most common mistake is simply running npm install without any isolation. Every postinstall script in your dependency tree executes with your full user permissions. Use ./dnpm install instead.
Mistake 2: Trusting --ignore-scripts Alone
Setting --ignore-scripts blocks postinstall, but it does not provide filesystem isolation, network restrictions, or any other protection. If a malicious package contains harmful runtime code (not just install scripts), --ignore-scripts does nothing.
Mistake 3: Assuming bun Is Fully Secure
bun skips postinstall by default, which is better than npm. But bun still downloads malicious code to node_modules, provides no filesystem isolation, and the code still executes at runtime when you import it. bun mitigates one attack vector; dnpm provides 12 layers of protection.
Mistake 4: Not Checking Your Lockfile
A compromised lockfile can redirect packages to malicious registries. Always review package-lock.json changes in PRs. dnpm automates this with its lockfile integrity check.
Mistake 5: Disabling Security for Convenience
When a native module fails to compile, the temptation is to disable security features. Instead, use ./dnpm rebuild — it enables scripts but keeps network disabled. This lets native modules compile while still blocking exfiltration.
Mistake 6: Running docker compose Directly
Never run docker compose commands directly to manage the dnpm container. Use ./dnpm nuke to rebuild from scratch, ./dnpm shell for debugging, and ./dnpm ci for clean installs. Running docker compose bypasses dnpm's security checks, lockfile validation, and two-phase install logic.
Tools Used in This Guide
- dnpm Configurator — Generate a hardened Docker-based npm wrapper with 12 security layers
- Password Generator — Generate strong passwords for npm tokens and registry authentication
- Random Key Generator — Create secure API keys and tokens for CI/CD environments
- Data Sanitizer — Clean sensitive data from configuration files before committing
FAQ
Q1: Does dnpm replace npm?
A: No. dnpm wraps npm inside a secure Docker container. Every npm command you know still works — ./dnpm install, ./dnpm run dev, ./dnpm run build. dnpm adds isolation and security layers without changing your workflow.
Q2: Is there a performance impact?
A: Minimal. The initial Docker image build takes about 30 seconds. After that, ./dnpm run dev starts as fast as native npm. File watching uses polling on macOS (configurable), which uses slightly more CPU. Builds run at native speed inside the container.
Q3: Does dnpm work with yarn or pnpm? A: The generated setup targets npm, but you can modify the Dockerfile and compose file to use yarn or pnpm. The security model (read-only mount, seccomp, capability dropping, offline builds) works identically regardless of the package manager.
Q4: Why not just use bun? A: bun skips postinstall scripts by default, which blocks the #1 attack vector. But malicious code still gets downloaded to node_modules, bun provides no filesystem isolation or network restrictions, and the code executes at runtime when imported. dnpm provides 12 layers of defense-in-depth protection that bun does not offer.
Q5: Is the dnpm configurator free? A: Yes. FindUtils dnpm Configurator is completely free with no signup, no usage limits, and no ads. Configure your setup, preview all generated files, and download everything as a ZIP.
Q6: Can I use dnpm in CI/CD pipelines?
A: Absolutely. Replace npm ci with ./dnpm ci in your CI scripts. Add --no-rebuild to skip postinstall scripts entirely for maximum security. The Docker layer caches make subsequent runs fast.
Q7: What if a native module needs postinstall to compile?
A: dnpm handles this with its two-phase install. Phase 1 downloads packages with scripts disabled. Phase 2 runs npm rebuild with scripts enabled but zero network access. Native modules compile normally, but malicious scripts cannot phone home.
Q8: What does dnpm check scan for?
A: dnpm check runs a 6-point security scan: lockfile integrity (detects registry poisoning), npm audit (known CVEs), signature verification (tamper detection), Socket.dev behavioral analysis (suspicious runtime behaviors like shell execution or network access), deprecated package detection, and container image CVE scanning via Trivy. Reports are saved to .dnpm/reports/ with timestamped files and a latest.txt symlink.
Q9: Does dnpm modify my CLAUDE.md?
A: Yes, dnpm setup automatically prepends dnpm usage instructions to your project's CLAUDE.md so that AI coding assistants know to use ./dnpm instead of bare npm. If no CLAUDE.md exists, one is created. The injection is idempotent — running setup multiple times will not duplicate the instructions.
Next Steps
- Complete Guide to Online Developer Tools — Explore the full suite of free developer tools on findutils.com
- Free Developer Tools That Replace Paid Software — More free alternatives for your development workflow
- dnpm Configurator — Configure and download your secure npm setup now