Tailsnitch
A security auditor for Tailscale configurations. Scans your tailnet for misconfigurations, overly permissive access controls, and security best practice violations.
Install / Use
/learn @Adversis/TailsnitchREADME
Tailsnitch
A security auditor for Tailscale configurations. Tailsnitch scans your tailnet for 50+ misconfigurations, overly permissive access controls, and security best practice violations.
Quick Start
# 1. Set your Tailscale API credentials
export TS_API_KEY="tskey-api-..."
# 2. Run audit
tailsnitch
# 3. See only high-severity findings
tailsnitch --severity high
# 4. Fix some issues ~interactively~ yolo mode
tailsnitch --fix
Installation
Download Pre-built Binary
Download the latest release from GitHub Releases.
macOS users: Remove quarantine attribute after download:
sudo xattr -rd com.apple.quarantine tailsnitch
Install via Go
go install github.com/Adversis/tailsnitch@latest
Build from Source
git clone https://github.com/Adversis/tailsnitch.git
cd tailsnitch
go build -o tailsnitch .
Authentication
Tailsnitch supports two authentication methods. OAuth is preferred when both are configured.
Option 1: OAuth Client (Recommended)
OAuth clients provide scoped, auditable access that doesn't expire when employees leave.
export TS_OAUTH_CLIENT_ID="..."
export TS_OAUTH_CLIENT_SECRET="tskey-client-..."
Create an OAuth client at: https://login.tailscale.com/admin/settings/oauth
Required scopes for read-only audit:
all:read(simplest), or individually:policy_file:read- ACL policydevices:core:read- Device listdns:read- DNS configurationauth_keys:read- Auth keys (for AUTH checks)
Additional scopes for fix mode:
devices:core- Delete devices, modify tags (requires tag selection)auth_keys- Delete auth keys
Option 2: API Key
API keys operate as the user who created them and inherit that user's permissions.
export TS_API_KEY="tskey-api-..."
Create an API key at: https://login.tailscale.com/admin/settings/keys
Usage Examples
Basic Audit
# Run full audit
tailsnitch
# Show passing checks too (verbose)
tailsnitch --verbose
# Output as JSON for processing
tailsnitch --json
# Audit a specific tailnet (when OAuth client has access to multiple)
tailsnitch --tailnet mycompany.com
Filter Results
# Only show critical and high severity issues
tailsnitch --severity high
# Filter by category
tailsnitch --category access # ACL issues
tailsnitch --category auth # Authentication & keys
tailsnitch --category device # Device security
tailsnitch --category network # Network exposure
tailsnitch --category ssh # SSH rules
tailsnitch --category log # Logging & admin
# Run specific checks only
tailsnitch --checks ACL-001,AUTH-001,DEV-010
tailsnitch --checks stale-devices,tailnet-lock-not-enabled
# List all available checks
tailsnitch --list-checks
Interactive Fix Mode
Fix mode allows you to remediate issues directly via the Tailscale API:
# Interactive fix mode
tailsnitch --fix
# Preview what would be fixed (dry run)
tailsnitch --fix --dry-run
# Auto-select safe fixes (still requires confirmation)
tailsnitch --fix --auto
# Disable audit logging of fix actions
tailsnitch --fix --no-audit-log
API-fixable items:
| Check | Action | |-------|--------| | AUTH-001, AUTH-002, AUTH-003 | Delete auth keys | | AUTH-004 | Replace with ephemeral keys | | DEV-002 | Remove tags from user devices | | DEV-004 | Delete stale devices | | DEV-005 | Authorize pending devices |
Fix mode also provides direct links to the admin console for issues that require manual intervention.
SOC 2 Evidence Export
Generate evidence reports for SOC 2 audits with Common Criteria (CC) control mappings:
# Export as JSON
tailsnitch --soc2 json > soc2-evidence.json
# Export as CSV (for spreadsheets)
tailsnitch --soc2 csv > soc2-evidence.csv
The SOC 2 report includes:
- Per-resource test results (each device, key, ACL rule tested individually)
- CC code mappings (CC6.1, CC6.2, CC6.3, CC6.6, CC7.1, CC7.2, etc.)
- Pass/Fail/N/A status for each control test
- Timestamp for audit trail
Example CSV output:
resource_type,resource_id,resource_name,check_id,check_title,cc_codes,status,details,tested_at
device,node123,prod-server,DEV-001,Tagged devices with key expiry disabled,CC6.1;CC6.3,PASS,Tags: [tag:server] key expiry enabled,2025-01-05T10:30:00Z
key,tskey-auth-xxx,tskey-auth-xxx,AUTH-001,Reusable auth keys exist,CC6.1;CC6.2;CC6.3,FAIL,Reusable key expires in 45 days,2025-01-05T10:30:00Z
Ignore Known Risks
Create a .tailsnitch-ignore file to suppress findings for known-accepted risks:
# .tailsnitch-ignore
# Ignore informational checks
ACL-008 # We intentionally don't use groups
ACL-009 # Legacy ACLs are fine for our use case
# Ignore specific medium checks with justification
DEV-006 # External devices are approved contractors
LOG-001 # Flow logs require Enterprise plan
Ignore file locations (checked in order):
.tailsnitch-ignorein current directory~/.tailsnitch-ignorein home directory
# Use a specific ignore file
tailsnitch --ignore-file /path/to/ignore
# Disable ignore file processing entirely
tailsnitch --no-ignore
JSON Export and Processing
# Export full report
tailsnitch --json > audit.json
# Extract failed checks as TSV
tailsnitch --json | jq -r '
.suggestions
| map(select(.pass == false))
| .[]
| [.id, .title, .severity, .remediation]
| @tsv
' > findings.tsv
# Summary by severity
tailsnitch --json | jq '
.suggestions
| map(select(.pass == false))
| group_by(.severity)
| map({severity: .[0].severity, count: length})
'
# List critical/high issues with admin links
tailsnitch --json | jq -r '
.suggestions
| map(select(.pass == false and (.severity == "CRITICAL" or .severity == "HIGH")))
| .[]
| "\(.id): \(.title)\n Fix: \(.fix.admin_url // "manual")\n"
'
Command Reference
| Flag | Description |
|------|-------------|
| --json | Output as JSON |
| --severity | Filter by minimum severity: critical, high, medium, low, info |
| --category | Filter by category: access, auth, network, ssh, log, device, dns |
| --checks | Run specific checks (comma-separated IDs or slugs) |
| --list-checks | List all available checks and exit |
| --tailnet | Specify tailnet to audit (default: from API key) |
| --verbose | Show passing checks too |
| --fix | Enable interactive fix mode |
| --auto | Auto-select safe fixes (requires --fix) |
| --dry-run | Preview fix actions without executing (requires --fix) |
| --no-audit-log | Disable audit logging of fix actions |
| --soc2 | Export SOC 2 evidence: json or csv |
| --tailscale-path | Path to tailscale CLI (for Tailnet Lock checks) |
| --ignore-file | Path to ignore file |
| --no-ignore | Disable ignore file processing |
| --version | Show version information |
Security Checks
Tailsnitch performs 52 security checks across 7 categories. See docs/CHECKS.md for detailed documentation of each check.
Critical Severity
| ID | Check | Risk | |----|-------|------| | ACL-001 | Default 'allow all' policy | All devices have unrestricted access | | ACL-002 | SSH autogroup:nonroot misconfiguration | SSH as any non-root user | | ACL-006 | tagOwners too broad | Privilege escalation via tags | | ACL-007 | autogroup:danger-all usage | Access granted to external users |
High Severity
| ID | Check | Risk | |----|-------|------| | AUTH-001 | Reusable auth keys | Unlimited device additions if stolen | | AUTH-002 | Long expiry auth keys | Extended exposure window | | AUTH-003 | Pre-authorized keys | Bypass device approval | | DEV-001 | Tagged devices without key expiry | Indefinite access | | DEV-002 | User devices tagged | Persist after user removal | | DEV-010 | Tailnet Lock disabled | No protection against stolen keys | | DEV-012 | Pending Tailnet Lock signatures | Unsigned nodes need review | | NET-001 | Funnel exposure | Public internet access | | NET-003 | Subnet router trust boundary | Unencrypted traffic on local network | | SSH-002 | Root SSH without check mode | No re-authentication required |
Medium Severity
| ID | Check | Risk | |----|-------|------| | ACL-004 | autogroup:member usage | External users included | | ACL-005 | AutoApprovers configured | Bypass route approval | | AUTH-004 | Non-ephemeral CI/CD keys | Stale devices accumulate | | DEV-003 | Outdated clients | Potential vulnerabilities | | DEV-004 | Stale devices | Unused attack surface | | DEV-005 | Unauthorized devices | Pending approval queue | | DEV-007 | Sensitive machine names | CT log exposure | | DEV-009 | Device approval config | May not be enabled | | NET-004 | HTTPS CT log exposure | Machine names public | | NET-005 | Exit node traffic visibility | Operator sees all traffic | | NET-006 | Serve exposure | Local services on tailnet | | SSH-003 | Recorder UI exposure | Sessions visible to network |
Informational
Checks for logging configuration, DNS settings, user roles, and manual verification items.
Output Example
+=====================================================================+
| TAILSNITCH SECURITY AUDIT |
| Tailnet: example.com |
| Version: 1.0.0 (build: abc123) |
+=====================================================================+
Using ignore file: .tailsnitch-ignore (3 rules)
=== ACCESS CONTROLS ===================================================
[CRITICAL] ACL-001: Default 'allow all' policy active
Your ACL policy omits the 'acls' field. Tailscale applies a
default 'allow all' policy, granting all devices full access.
Remediation:
Define explicit ACL rules following least privilege principle.
Source: https://tailscale.com/kb/1192/acl-samples
-----------------------
Related Skills
node-connect
341.0kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
84.4kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
341.0kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
84.4kCommit, push, and open a PR
