cloudflare / cloudflare/cloudflared

access tcp/ssh: service token ignored, browser auth attempted per-connection, TCP banner not delivered (2026.6.0 regression from 2026.5.1)

Open
#1,674 0 comments 3 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
15.6k
Forks
1.4k
PR merge metrics
No merged PRs in 30d

Description

### Summary

`cloudflared access tcp` (and `access ssh`) in 2026.6.0 ignores all headless auth credentials (service-token-id/secret flags, `$TUNNEL_SERVICE_TOKEN_ID`/`SECRET` env vars, `-H` header injection) and falls through to interactive browser auth on every new TCP connection. SSH banner never reaches the client; connection times out.

This is a regression from 2026.5.1, which honored service tokens correctly and never attempted browser auth when credentials were provided.

### Environment

- cloudflared client: `2026.6.0 (built 2026-06-08T18:16:09Z)` on macOS arm64 (Apple Silicon)
- cloudflared daemon: `2026.5.1` (remote tunnel daemon, working)
- Tunnel mode: dashboard-managed (remote config), single hostname route `.example.com → ssh://localhost:2222`
- Access app: self-hosted, free tier, policy includes Emails + Service Auth

### Steps to reproduce

1. Create a CF Access Service Token + add to Access app policy as `Include: Service Auth`.
2. Add hostname route in tunnel: `.example.com → ssh://localhost:2222`.
3. On client (where 2026.6.0 is running):
```
export TUNNEL_SERVICE_TOKEN_ID=".access"
export TUNNEL_SERVICE_TOKEN_SECRET=""
cloudflared access tcp \
--hostname .example.com \
--url 127.0.0.1:2229 \
--service-token-id "$TUNNEL_SERVICE_TOKEN_ID" \
--service-token-secret "$TUNNEL_SERVICE_TOKEN_SECRET"
```
4. From another shell: `ssh -p 2229 user@127.0.0.1`

### Expected behavior (2026.5.1)

- cloudflared authenticates against CF Access using the service token credentials
- WebSocket established to CF edge, no browser prompt
- TCP bytes (SSH banner, kex, payload) flow bidirectionally
- SSH login succeeds

### Actual behavior (2026.6.0)

- cloudflared starts: `INF Start Websocket listener host=127.0.0.1:2229` (looks fine)
- On the first SSH connection attempt, cloudflared logs:
```
A browser window should have opened at the following URL:
https://.example.com/cdn-cgi/access/cli?...
```
- SSH client never receives a banner. `Connection timed out during banner exchange`.
- Verified the service-token flag values DID reach cloudflared (`--help` shows them as defaults when env vars set).
- Verified service token works for HTTP auth (`curl -H "CF-Access-Client-Id:..." -H "CF-Access-Client-Secret:..." https://.example.com/` returns HTTP 200 with a `CF_Authorization` cookie set).
- Header injection via `-H` flag also attaches at WebSocket upgrade (cloudflared debug log shows `Cf-Access-Client-Id` + `Cf-Access-Client-Secret` headers in the WebSocket GET — and the WebSocket upgrades to HTTP 101 Switching Protocols), but per-connection auth still kicks off browser flow.
- Cycle repeats on every TCP connection attempt.

### Workaround

Downgrade to cloudflared 2026.5.1. No client-side workaround in 2026.6.0 has been found.

### Repro environment context

- macOS LaunchAgent (background process, cannot complete browser flow) calling cloudflared per-connection: broken.
- Interactive foreground SSH: also broken (same per-connection retry on browser flow).
- HTTP curl with service-token headers to same hostname: works (HTTP 200).

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.