Originally published on 2026-01-07
Original article (Japanese): Tailscaleの『なんとなく不安』を数値化する:tailsnitchが暴く50の設定ミス
In September 2025, Asahi Group Holdings suffered a ransomware attack. The entry point was a vulnerability in their VPN device. In October, Askul was breached through a VPN account of a contracted service provider, leading to the shutdown of their e-commerce site.
Both incidents were the result of the misconception that "as long as we have a VPN, we are safe."
If you have implemented Tailscale, you might be thinking, "It should be safer than traditional VPNs, so I'm fine."
Indeed, Tailscale has advantages over traditional on-premises VPN gateways. With lightweight and audited encryption via WireGuard, device-level zero-trust authentication, and a SaaS architecture that eliminates the risk of exploiting VPN device vulnerabilities—these designs address the weaknesses of traditional VPNs.
However, Tailscale can also be dangerous if misconfigured. Leaving default ACLs unchecked can allow unrestricted access to all devices, and if reusable authentication keys are leaked, attackers can add unauthorized devices. tailsnitch is a security auditing tool that quantifies such "vague anxiety" with over 50 checks, evaluating them on a scale of Critical/High/Medium/Low/Info.
In this article, we will explain how to use tailsnitch and the dangerous configuration mistakes it can detect.
What is tailsnitch?
tailsnitch is an open-source tool that automatically audits the configuration of a Tailscale network (tailnet). Released on December 24, 2025, it garnered over 430 GitHub Stars in just two weeks.
Key features:
- Over 50 security checks: 7 categories including ACLs, authentication keys, devices, network exposure, SSH, logs, and DNS
- Severity rating in 5 levels: Critical → High → Medium → Low → Info
- SOC 2 audit trail output: CSV/JSON output mapped to controls like CC6.1, CC6.2
- CI/CD integration: Automatic checks during PRs with GitHub Actions
-
Interactive remediation mode: Fix configuration mistakes with the
--fixflag
Developed by the security company Adversis, a Tailscale Hardening Guide is also available.
Installation
You can install tailsnitch using one of the following methods.
Prebuilt Binary (Recommended)
Download the latest version from GitHub Releases:
# Remove quarantine attribute for macOS
sudo xattr -rd com.apple.quarantine tailsnitch
chmod +x tailsnitch
sudo mv tailsnitch /usr/local/bin/
Install with 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 Setup
tailsnitch uses the Tailscale API, so you need authentication credentials. You can use either an OAuth Client (recommended) or an API Key.
OAuth Client (Recommended)
The OAuth Client allows you to restrict permissions with scopes and is logged in the audit logs. There is no risk of API keys being invalidated when employees leave.
- Create an OAuth Client at https://login.tailscale.com/admin/settings/oauth
-
Grant the following scopes for read-only auditing:
-
all:read(the easiest) - Or individually:
policy_file:read,devices:core:read,dns:read,auth_keys:read
-
Set the environment variables:
export TS_OAUTH_CLIENT_ID="..."
export TS_OAUTH_CLIENT_SECRET="tskey-client-..."
API Key
The API Key inherits the permissions of the user who created it.
- Create an API Key at https://login.tailscale.com/admin/settings/keys
- Set the environment variable:
export TSKEY="tskey-api-..."
Basic Usage
Audit All Items
tailsnitch
Example of the first run:
+=====================================================================+
| TAILSNITCH SECURITY AUDIT |
| Tailnet: example.com |
| Version: 1.4.0 (build: d717661) |
+=====================================================================+
=== 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
----------------------------------------------------------------------
[HIGH] AUTH-001: Reusable auth keys exist
Found 2 reusable auth key(s). These can be reused to add
multiple devices if compromised.
Details:
- Key tskey-auth-xxx (expires in 45 days)
- Key tskey-auth-yyy (expires in 89 days)
Remediation:
Store reusable keys in a secrets manager. Prefer one-off keys.
----------------------------------------------------------------------
SUMMARY
======================================================================
Critical: 1 High: 3 Medium: 5 Low: 2 Info: 8
Total findings: 19 | Passed: 33
Filter by Severity
# Show only Critical/High
tailsnitch --severity high
# Specific categories only
tailsnitch --category access # ACL issues
tailsnitch --category auth # Authentication key issues
tailsnitch --category device # Device security
JSON Output and Aggregation with jq
# Output all results in JSON
tailsnitch --json > audit.json
# Extract only failed checks
tailsnitch --json | jq -r '
.suggestions
| map(select(.pass == false))
| .[]
| [.id, .title, .severity, .remediation]
| @tsv
' > findings.tsv
# Aggregate by severity
tailsnitch --json | jq '
.suggestions
| map(select(.pass == false))
| group_by(.severity)
| map({severity: .[0].severity, count: length})
'
Example output:
[
{"severity": "CRITICAL", "count": 1},
{"severity": "HIGH", "count": 3},
{"severity": "MEDIUM", "count": 5}
]
Dangerous Configuration Mistakes Detected
Here are some representative issues that tailsnitch can detect.
Critical: Leaving Default ACLs Unchecked
Issue: If the ACL policy lacks the acls field, Tailscale applies a default 'allow all' policy, granting all devices full access.
[CRITICAL] ACL-001: Default 'allow all' policy active
Impact:
- Unlimited access from a developer's laptop to the production database
- A single compromised device puts the entire tailnet at risk
Remediation:
Define minimal ACLs:
{
"groups": {
"group:engineering": ["alice@company.com"],
"group:devops": ["charlie@company.com"]
},
"tagOwners": {
"tag:dev": ["autogroup:admin"],
"tag:prod": ["autogroup:admin"]
},
"acls": [
{
"action": "accept",
"src": ["group:engineering"],
"dst": ["tag:dev:443", "tag:dev:8080"]
},
{
"action": "accept",
"src": ["group:devops"],
"dst": ["tag:prod:22", "tag:prod:443"]
}
]
}
High: Reusable Authentication Keys Exist
Issue: If reusable authentication keys are leaked, attackers can add devices without restriction.
[HIGH] AUTH-001: Reusable auth keys exist
Found 2 reusable auth key(s):
- Key tskey-auth-xxx (expires in 45 days)
Impact:
- Breach through an authentication key committed to a GitHub repository
- Unauthorized device addition with keys stolen from a CI/CD pipeline
Remediation:
- Delete existing reusable keys
- Switch to ephemeral (temporary) keys:
# Generate an ephemeral key (usable once)
tailscale up --authkey tskey-auth-xxx --ephemeral
- Use OAuth Client in CI/CD
High: Tailnet Lock Disabled
Issue: If Tailnet Lock is disabled, an attacker can add unauthorized devices if the Tailscale coordination server is compromised.
[HIGH] DEV-010: Tailnet Lock disabled
Impact:
- Trust in the control plane is required
- Risk of man-in-the-middle attacks by advanced attackers
Remediation:
Enable Tailnet Lock (requires a signing node):
# Initialize lock on a trusted node
tailscale lock init tlpub:<SIGNING_NODE_KEY>
# New devices will require signing
tailscale lock sign nodekey:<NEW_NODE_KEY>
Note: Tailnet Lock can impose operational burdens, hence it is suited for defense industries or companies with strict compliance requirements.
Medium: Outdated Clients Detected
Issue: Older Tailscale clients may have known vulnerabilities.
[MEDIUM] DEV-003: Outdated clients detected
Found 3 devices running Tailscale < 1.50.0
Remediation:
Enforce version checks with Device Posture:
{
"postures": {
"posture:baseline": [
"node:tsVersion >= '1.50.0'"
]
},
"acls": [
{
"action": "accept",
"src": ["group:devops"],
"srcPosture": ["posture:baseline"],
"dst": ["tag:prod:22"]
}
]
}
Medium: Stale Devices Detected
Issue: Devices that have not been used for over 60 days pose a risk of being compromised if they belong to former employees.
[MEDIUM] DEV-004: Stale devices detected
Found 5 devices not seen in 60+ days
Remediation:
Interactively delete with --fix mode:
tailsnitch --fix
Or delete manually:
tailscale logout --device <device-id>
Interactive Remediation Mode (--fix)
Using the --fix flag allows you to interactively correct issues that can be fixed via the API.
tailsnitch --fix
Fixable items include:
| Check | Remediation |
|---|---|
| AUTH-001, AUTH-002, AUTH-003 | Delete authentication keys |
| AUTH-004 | Replace with ephemeral keys |
| DEV-002 | Remove tags from user devices |
| DEV-004 | Delete stale devices |
| DEV-005 | Approve unauthorized devices |
For items requiring manual intervention, links to the management console will be displayed.
Dry Run (preview changes):
tailsnitch --fix --dry-run
SOC 2 Audit Trail Output
tailsnitch can output the necessary audit trails for SOC 2 in CSV/JSON format.
# CSV format
tailsnitch --soc2 csv > soc2-evidence.csv
# JSON format
tailsnitch --soc2 json > soc2-evidence.json
Example output (CSV):
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
Each check is mapped to the following SOC 2 controls (CC):
- CC6.1: Logical Access Controls
- CC6.2: Granting Access Rights
- CC6.3: Removing Access Rights
- CC6.6: Network Segmentation
- CC7.1: Detection of Security Events
- CC7.2: Monitoring Security Incidents
Automated Auditing in CI/CD Pipeline
Example of running automatic checks during ACL changes with GitHub Actions:
# .github/workflows/tailscale-acl.yml
name: Tailscale ACL CI
on:
pull_request:
paths: ['policy.hujson']
push:
branches: [main]
paths: ['policy.hujson']
jobs:
test-acl:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run tailsnitch
env:
TS_OAUTH_CLIENT_ID: ${{ secrets.TS_OAUTH_CLIENT_ID }}
TS_OAUTH_CLIENT_SECRET: ${{ secrets.TS_OAUTH_CLIENT_SECRET }}
run: |
curl -L https://github.com/Adversis/tailsnitch/releases/latest/download/tailsnitch-linux-amd64 -o tailsnitch
chmod +x tailsnitch
./tailsnitch --severity high --json > audit.json
- name: Fail on critical issues
run: |
if ./tailsnitch --severity high --json | jq -e '.summary.critical + .summary.high > 0' > /dev/null; then
echo "Critical or high severity issues found!"
./tailsnitch --severity high
exit 1
fi
With this configuration, security checks will automatically run on PRs for ACL changes, blocking merges if Critical/High issues are found.
Preventing Configuration Mistakes with ACL Tests
While tailsnitch is a detection tool, adding a tests field within your ACLs can help prevent configuration mistakes from occurring in the first place.
{
"acls": [
{
"action": "accept",
"src": ["group:engineering"],
"dst": ["tag:dev:443"]
}
],
"tests": [
{
"src": "group:engineering",
"deny": ["tag:prod:*", "tag:prod-db:5432"]
},
{
"src": "group:devops",
"accept": ["tag:bastion:22"]
}
]
}
If tests fail, ACL changes will be rejected. This helps prevent configuration mistakes before they are detected by tailsnitch.
Common Pitfalls
The Danger of autogroup:member
autogroup:member includes all users participating in the tailnet. Since it also includes external users (Shared Nodes), it can unintentionally grant access rights.
Bad Example:
{
"acls": [
{
"action": "accept",
"src": ["autogroup:member"],
"dst": ["tag:staging:*"]
}
]
}
Good Example:
{
"acls": [
{
"action": "accept",
"src": ["group:engineering"],
"dst": ["tag:staging:443"]
}
]
}
Overreliance on Subnet Routers
While Subnet Routers are convenient, if compromised, they can provide access to a wide range of networks.
Mitigation:
- Enable Stateful Filtering:
tailscale up --advertise-routes=10.0.0.0/24 --stateful-filtering
- Protect the Subnet Router itself with security groups or NACLs.
The Trap of SSH autogroup:nonroot
autogroup:nonroot allows SSH access for all users except root, but it also includes users with sudo privileges.
Bad Example:
{
"ssh": [
{
"action": "accept",
"src": ["group:engineering"],
"dst": ["tag:prod"],
"users": ["autogroup:nonroot"]
}
]
}
Good Example:
{
"ssh": [
{
"action": "accept",
"src": ["group:devops"],
"dst": ["tag:prod"],
"users": ["deploy"]
}
]
}
Regular Audit Operations
Here are operational guidelines for continuously utilizing tailsnitch.
Weekly
- [ ] Run tailsnitch to check for Critical/High issues
- [ ] Review the device approval queue
- [ ] Remove unused authentication keys
Monthly
- [ ] Cross-check group memberships with the employee roster
- [ ] Ensure devices of former employees have been removed
- [ ] Review ACL change history
Quarterly
- [ ] Audit all access rights (who can access what)
- [ ] Review third-party access
- [ ] Reassess Subnet Router configurations
Upon Employee Departure (Immediately)
- [ ] Remove from Tailscale groups
- [ ] Delete user from tailnet
- [ ] Remove created authentication keys
- [ ] Delete devices
- [ ] Audit recent ACL changes
Conclusion
While Tailscale addresses many weaknesses of traditional VPNs at the design level, risks from configuration mistakes still exist. By using tailsnitch, you can visualize "vague anxiety" as concrete issues and prioritize addressing them.
Setup takes just five minutes, and integrating it into your CI/CD pipeline allows for automatic checks with every ACL change. You can also output audit trails for SOC 2 compliance.
Personally, I believe that every organization using Tailscale should run tailsnitch at least once a month. Do not leave Critical/High issues unaddressed until they reach zero, and add ACL tests to prevent recurrence—by thoroughly implementing these two practices, you can significantly reduce the risk of large-scale incidents from VPN breaches.
If you're interested, try running tailsnitch on your own tailnet. You might discover unexpected configuration mistakes.
Top comments (0)