Skip to content

AdamGonda/ward

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

19 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

WARD 🔒⬇️✅

Run [ npm i ] safely, audit installs inside a docker container.

macOS · Linux · Windows  |  Go stdlib only  |  MIT

# instead of: npm i
ward .

Run npm install inside an isolated Docker container on macOS, Linux, or Windows. ward captures outbound traffic (including lifecycle scripts), prints a safe / not safe summary, and only copies node_modules to your machine after you approve.

Requirements

Install

Clone the repo and build ward on your machine:

git clone https://github.com/AdamGonda/ward.git
cd ward
go build -o ward ./cmd/ward

Or install into your Go bin directory (must be on PATH):

go install ./cmd/ward

Then run ward --help.

Usage

ward <project-directory> [--json] [--verbose] [--auto-approve]

Example

cd my-app
ward .
  1. Builds the Docker image (node:22-alpine + tcpdump) from embedded assets if needed
  2. Runs npm install in a container with your project mounted at /workspace
  3. Captures DNS/HTTP/HTTPS traffic during install (including lifecycle scripts)
  4. Prints a security summary (safe or not safe) with unexpected destinations
  5. Prompts: Approve install [y/N]
  6. On approval, copies node_modules from the container to your project

Artifacts are written under <project>/.ward/:

  • tcpdump.log — raw capture log
  • npm-install.log — npm output (lifecycle script detection)
  • install-phases.json — capture/install timing markers
  • network-summary.json — install metadata from the container
  • network-report.txt — full semantic security report

Add to your app .gitignore:

.ward/

Options

Flag Description
--json Print security report as JSON (destinations, phases, approval state)
--verbose Include internal/Docker network traffic in the report
--strict Exit with error if the security report is not safe (use with --auto-approve in CI)
--auto-approve Approve and copy node_modules without prompting (use with --strict in CI)
-h, --help Show help

CI

Use --auto-approve and --strict together: no prompt, fail if the security report is not safe, then copy node_modules. On Linux runners the container matches the host (native addons like sharp work after copy). Add --json to read approved and copied in scripts.

ward . --auto-approve --strict

Example (Docker required on the runner):

- run: go build -o ward ./cmd/ward
- run: ./ward . --auto-approve --strict

Security report

The tool produces human-readable output instead of raw packet dumps:

Full report: .ward/network-report.txt

SAFE

  ✓ Only known hosts contacted
  ✓ No postinstall requests

When something looks wrong (e.g. unknown domain during postinstall):

Full report: .ward/network-report.txt

NOT SAFE

  ⚠ Unexpected domain contacted during lifecycle script

Unexpected destinations (1):
  ⚠ example.com — Unexpected outbound traffic (not on allowlist)
    Phase: lifecycle:postinstall

The full report in network-report.txt groups traffic by install phase (package fetch vs lifecycle scripts), labels known hosts (npm registry, GitHub, etc.), and includes a detailed risk breakdown for auditing.

Exit codes

Code Meaning
0 Completed — install reviewed; node_modules copied if you approved, otherwise left unchanged
1 Security report is not safe (--strict)
2 Usage/prerequisite error
3 npm install failed in container

Declining the copy prompt is not an error (exit 0). Use --json and check approved / copied in scripts.

Important: native modules when host ≠ Linux

The container runs Linux (Alpine). On macOS or Windows, packages with native binaries (e.g. sharp, esbuild, @swc/core) are built for Linux inside the container. Copying node_modules to your machine may cause runtime errors on the host.

On Linux (including CI), the container and host match — copied native modules work as expected.

This tool is especially useful for:

  • Auditing network behavior during install (any platform)
  • CI pipelines on Linux (--auto-approve --strict)
  • Mostly pure-JavaScript dependency trees on macOS/Windows
  • Teams that accept re-running npm rebuild or a host-side install after review on macOS/Windows

How it works

sequenceDiagram
    participant CLI as GoCLI
    participant Docker as Docker
    participant Container as AlpineContainer

    CLI->>Docker: embed_extract_and_build
    CLI->>Docker: docker_run_mount_project
    Container->>Container: tcpdump_npm_install
    CLI->>CLI: analysis_BuildSecurityReport
    CLI->>CLI: prompt_approve_deny
    alt approved
        CLI->>Docker: docker_cp_node_modules
    end
    CLI->>Docker: docker_rm
Loading

Examples

Smoke test project (lodash only):

ward examples/smoke

Postinstall network fixture (wget to example.com during postinstall):

ward examples/postinstall-network

Development

go test ./...

Docker image assets live in docker/ and are embedded at compile time via docker/assets.go.

Roadmap

Future enhancements (not yet implemented):

  • Process monitoring — detect curl, wget, bash spawned during lifecycle scripts
  • --sandbox mode — restricted filesystem and network egress
  • Multi-ecosystem — pnpm, bun, pip, cargo with the same analysis engine

License

MIT

About

Run [ npm i ] safely, audit installs inside a docker container.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors