# Security Scanner API

Bun's package manager can scan packages before installing them, to catch supply chain attacks and known vulnerabilities.

---

## Quick Start

Configure a security scanner in your `bunfig.toml`:

```toml bunfig.toml icon="settings"
[install.security]
scanner = "@oven/bun-security-scanner" # example name, replace with your scanner's package
```

With a scanner configured, Bun:

- Scans all packages before installation
- Displays security warnings and advisories
- Cancels installation if the scanner finds fatal advisories

---

## How It Works

Security scanners analyze packages during `bun install`, `bun add`, and every other command that installs packages, such as `bun patch`, `bun link` and `bun dedupe`. They can detect:

- Known security vulnerabilities (CVEs)
- Malicious packages
- License compliance issues

Every command sends the scanner all packages of the project, with one exception. `bun add <package>`, `bun install <package>`, and `bun update <package>` in a project that has a lockfile and a `node_modules` directory send only the packages they name, the dependencies of those packages, and the packages whose version the command changes. Run `bun install` to send everything.

### Security Levels

Scanners report issues at two severity levels:

- **`fatal`** - Installation stops immediately, exits with non-zero code
- **`warn`** - In interactive terminals, prompts to continue; in CI, exits immediately

---

## Using Pre-built Scanners

Security companies publish Bun security scanners as npm packages.

### Installing a Scanner

Install a security scanner from npm:

```bash terminal icon="terminal"
bun add -d @oven/bun-security-scanner
```

<Note>
  `@oven/bun-security-scanner` is an example package name, not a real package. Replace it with the scanner you want to
  use, and consult that scanner's documentation for the exact package name and installation instructions. You install
  most scanners with `bun add`.
</Note>

### Configuring the Scanner

After installation, configure it in your `bunfig.toml`:

```toml bunfig.toml icon="settings"
[install.security]
scanner = "@oven/bun-security-scanner" # example name, replace with your scanner's package
```

### Enterprise Configuration

Some enterprise scanners take authentication and other configuration from environment variables:

```bash terminal icon="terminal"
# This might go in ~/.bashrc, for example
export SECURITY_API_KEY="your-api-key"

# The scanner will now use these credentials automatically
bun install
```

Consult your scanner's documentation for which environment variables to set and any other required configuration.

### Authoring your own scanner

For a complete example with tests and CI setup, see the official template:
[github.com/oven-sh/security-scanner-template](https://github.com/oven-sh/security-scanner-template)

A scanner is a module that exports a `scanner` object implementing `Bun.Security.Scanner`. Bun calls `scan()` with every package it is about to install, including transitive dependencies, and cancels the install if any returned advisory is `fatal`:

```ts scanner.ts icon="/icons/typescript.svg"
export const scanner: Bun.Security.Scanner = {
  version: "1",
  async scan({ packages }) {
    const advisories: Bun.Security.Advisory[] = [];

    for (const pkg of packages) {
      if (pkg.name === "event-stream" && Bun.semver.satisfies(pkg.version, ">=3.3.6 <4.0.0")) {
        advisories.push({
          level: "fatal",
          package: pkg.name,
          url: "https://blog.npmjs.org/post/180565383195/details-about-the-event-stream-incident",
          description: "event-stream 3.3.6 shipped a compromised dependency",
        });
      }
    }

    return advisories;
  },
};
```

Each entry in `packages` describes one resolved package:

| Field            | Description                                                                                                                                                                                                     |
| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`           | The package name.                                                                                                                                                                                               |
| `version`        | The exact version (`4.1.2`) of a registry package. For other sources, the resolved specifier as in `bun.lock`: `github:user/repo#<commit>`, `https://example.com/pkg.tgz`, `./pkg.tgz`, `file:pkg`, `link:pkg`. |
| `requestedRange` | What `package.json` or the command line asked for: `^4.0.0`, `latest`, `github:user/repo`, `file:./pkg`.                                                                                                        |
| `tarball`        | The URL (or local path) of the tarball. For `github:` dependencies, the GitHub API tarball URL of the resolved commit. Empty for `git+` dependencies and local directories.                                     |

Packages from every source are included: registry, git, GitHub, remote and local tarballs, local directories. Workspace packages are part of the project and are not included. Outside a registry `version` is not semver; `Bun.semver.satisfies()` returns `false` for it.

The `user:password@` part and the query string of a URL are removed from all three fields. The `tarball` of a registry package keeps its query string, because some registries sign their tarball URLs.

## Related

- [Configuration (bunfig.toml)](https://bun.aphrody.app/docs/runtime/bunfig#installsecurityscanner)
- [Package Manager](https://bun.aphrody.app/docs/pm/cli/install)
- [Security Scanner Template](https://github.com/oven-sh/security-scanner-template)
