> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.pensar.dev/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.pensar.dev/_mcp/server.

# Private Networks (Tailscale)

> Pentest internal targets on your Tailscale tailnet

## Overview

Some applications are only reachable inside a private network. If that network is a [Tailscale](https://tailscale.com) tailnet, Pensar can join it for the length of a pentest and test hosts on it, such as `app.tail1a2b3c.ts.net`.

Each run joins your tailnet as a short-lived, tagged device. You decide exactly which hosts and ports that tag can reach through your tailnet policy.

## Prerequisites

* A Tailscale tailnet with the target host joined to it, reachable by its `.ts.net` name.
* Permission to edit the tailnet's access control policy and create OAuth clients in the Tailscale admin console.
* The target serves HTTP or HTTPS (ports 80 or 443 by default).

## 1. Allow the pentest tag in your policy

In Pensar, open **Settings → Private networks**. Under **Prepare your tailnet**, enter the host or IP the pentest should reach. Pensar generates a policy snippet for the pentest tag (default `tag:pensar-pentest`):

```json
{
  "tagOwners": {
    "tag:pensar-pentest": ["autogroup:admin"]
  },
  "grants": [
    {
      "src": ["tag:pensar-pentest"],
      "dst": ["app.tail1a2b3c.ts.net"],
      "ip": ["tcp:80", "tcp:443"]
    }
  ]
}
```

Merge it into your tailnet policy file in the Tailscale admin console. Grant only the hosts and ports you want tested.

## 2. Create a Tailscale OAuth client

In the Tailscale admin console, go to **Settings → OAuth clients** and create a client with:

* **Auth Keys: write** scope.
* The pentest tag (`tag:pensar-pentest`) selected.

Copy the client ID and secret. The secret is shown only once.

## 3. Connect in Pensar

Back on **Settings → Private networks**, under **Connect**, enter:

| Field               | Value                                                |
| ------------------- | ---------------------------------------------------- |
| Tailnet name        | Your tailnet, for example `tail1a2b3c.ts.net`        |
| OAuth client ID     | From step 2                                          |
| OAuth client secret | From step 2 (stored encrypted)                       |
| Tag                 | The tag from step 1, `tag:pensar-pentest` by default |

Click **Save**. To rotate the secret later, paste the new one; leave it blank to keep the stored secret.

## 4. Add and test your private target

Add the `.ts.net` host as a domain from your attack surface. Because public DNS can't see it, it is verified by tailnet membership instead of a DNS record: the host must be a device in your connected tailnet.

Launch a pentest as usual. Each run uses a fresh, single-use auth key to join your tailnet as an ephemeral device with your pentest tag. The device is removed automatically after the run ends.

The run checks target reachability before testing and stops with an error if a host or port is blocked by your policy.

## Limitations

* Only `.ts.net` hostnames are routed through your tailnet. Raw private IPs and other internal hostnames are not detected as private targets.
* A run that mixes private and public targets doesn't use Pensar's fixed egress IP, so IP allowlists for Pensar won't apply to that run.
* Disconnecting Tailscale in **Settings → Private networks** removes the stored credentials; pentests against `.ts.net` targets will fail until you reconnect.