> For the complete documentation index, see [llms.txt](https://docs.nullify.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.nullify.ai/capabilities/pentests/engagement-workflow.md).

# Engagement Workflow

You can launch a pentest from the Nullify dashboard or with the Nullify CLI.

Before you start, work through [Preparing for an Engagement](/capabilities/pentests/preparing-for-an-engagement.md).

## Dashboard

1. Go to **Applications**, select **Add application**, and enter its name and description.
2. On **Targets**, select **Add target**, enter the host, port and protocol, and select the application. Give any API path prefix to your Nullify contact. Each application resolves to one target URL.
3. Attach one credential per identity, then validate each one before starting.
4. If prompted, select **Run readiness check** before starting.
5. Start the run. Review progress and results in the dashboard. Configure ticketing and notifications as described in [Configuration – General](/configuration/configuration-general.md).

![Launch a new pentest](https://3946391995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FId2OtLCL6O6V3XSRYxtr%2Fuploads%2Fgit-blob-d30234dfdaf1f30cf1dfb3d4b4e1e464123f9290%2Flaunch-api-engagement.png?alt=media)

Creating applications and credentials requires the **Admin** role. Starting and stopping scans requires **Editor**. Contact your Nullify contact to arrange dashboard access.

Nullify discovers your API specification automatically where it can (see [Supported Targets](/capabilities/pentests/supported-targets.md)). To supply a specification file directly, use the CLI or send it to your Nullify contact.

## CLI

Use the CLI to run a pentest from your own environment, to wire one into a pipeline, or to test a service that is not reachable from the internet.

Install the CLI and authenticate:

```bash
curl -sSfL https://raw.githubusercontent.com/Nullify-Platform/cli/main/install.sh | sh -s -- --host api.<TENANT>.nullify.ai
nullify auth login --host api.<TENANT>.nullify.ai
```

In CI, set `NULLIFY_TOKEN` to a service-account token instead of logging in. See [API Configuration](/configuration/configuration-api.md) for how to generate one. Inside GitHub Actions you can pass the workflow's GitHub token with `--github-token` and the CLI exchanges it for a Nullify token — see [CLI Authentication](/cli/cli/authentication.md).

Run a pentest:

```bash
nullify pentest \
  --app-name      "Payments API" \
  --spec-path     "./openapi.json" \
  --target-host   "https://api.example.dev" \
  --github-owner  "my-org" \
  --github-repo   "payments-service" \
  --header        "Authorization: Bearer 1234" \
  --header        "X-Custom-Header: abcxyz"
```

`--spec-path` is required. Repeat `--header` once per header you want the pentester to send.

### Testing more than one identity

Static headers test one identity. For cross-identity authorization testing, provide credentials as described in [Preparing for an Engagement](/capabilities/pentests/preparing-for-an-engagement.md). Pass a config file with `--auth-config`:

```bash
nullify pentest \
  --app-name    "Payments API" \
  --spec-path   "./openapi.json" \
  --target-host "https://api.example.dev" \
  --auth-config "./pentest-auth.json"
```

`--auth-config` takes a JSON file — unlike `--spec-path`, this file is not parsed as YAML. The top-level `users` array holds one entry per identity; give each entry a distinct `roleName`:

```json
{
  "users": [
    {
      "roleName": "admin",
      "roleDescription": "Administrator with full access",
      "authConfig": {
        "method": "bearer",
        "token": "<admin token>"
      }
    },
    {
      "roleName": "user",
      "roleDescription": "Standard user",
      "authConfig": {
        "method": "bearer",
        "token": "<user token>"
      }
    },
    {
      "roleName": "guest",
      "roleDescription": "Unauthenticated",
      "authConfig": {
        "method": "none"
      }
    }
  ]
}
```

The CLI does not expand `${VAR}` or template this file — whatever you write into `token` or `password` is read and sent as-is. Do not commit a populated auth-config file to source control: generate it at run time from your secret store (for example, write it to a temporary path in your CI job just before the `nullify pentest` step, then delete it) or keep it in a path covered by `.gitignore`.

### Running against a private network

Add `--local` to run the pentester inside your own network against hosts only you can reach. See [Running in Private Networks](/capabilities/pentests/private-networks.md).

## Continuous Integration

Run the CLI in your pipeline. In GitHub Actions, pass the workflow token and the CLI handles the rest:

```yaml
- name: Nullify pentest
  run: |
    nullify pentest \
      --github-token "${{ secrets.GITHUB_TOKEN }}" \
      --app-name     "Payments API" \
      --spec-path    "./openapi.json" \
      --target-host  "https://api.staging.example.dev"
```

Use `nullify ci gate` to fail a build on new findings and `nullify ci report` to publish results.

Run pentests on release branches or a schedule.

## What to expect

Each confirmed finding carries the request and response that proved it, plus a reproduction script. Download the PDF report from the run page once the engagement completes.
