anthropics / anthropics/anthropic-sdk-typescript
Managed Agents egress gateway omits SNI on upstream TLS to Cloudflare R2 (503 HANDSHAKE_FAILURE_ON_CLIENT_HELLO)
- Lenguaje dominante
- TypeScript
- Estrellas
- 2.1k
- Forks
- 403
- Merge medio
- 1 d 21 h
- PR fusionados (30 d)
- 8
Descripción
> Heads-up: this is almost certainly a **Managed Agents egress-gateway / infrastructure** issue rather than a defect in the TypeScript SDK itself. Filing here since it's the closest public channel — please route to the managed-agents/egress team as appropriate.
## Summary
When code running inside a Managed Agents sandbox makes an outbound HTTPS request to a Cloudflare R2 S3 endpoint (`https://.r2.cloudflarestorage.com/...`), the egress gateway's **upstream** TLS connection to R2 fails. The gateway surfaces it as:
```
503 Service Unavailable — HANDSHAKE_FAILURE_ON_CLIENT_HELLO
```
The inbound leg (sandbox → gateway, terminated with an Anthropic egress cert) is fine; the failure is on the gateway → R2 leg.
## Root cause (reproduced)
**Cloudflare R2 requires SNI in the ClientHello. The egress gateway appears to open the upstream TLS connection without an SNI extension**, so Cloudflare rejects the handshake with a fatal `handshake_failure` alert — which the gateway reports as the 503 above.
Reproduced outside the sandbox by varying only the SNI on a raw TLS handshake to the R2 endpoint's IP:
| ClientHello SNI | Result |
|---|---|
| `.r2.cloudflarestorage.com` (correct host) | ✅ handshake OK (TLS 1.3) |
| `r2.cloudflarestorage.com` (base domain) | ✅ handshake OK |
| **no SNI** | ❌ `SSLV3_ALERT_HANDSHAKE_FAILURE` |
The no-SNI failure matches the gateway's `HANDSHAKE_FAILURE_ON_CLIENT_HELLO` exactly. With *any* SNI present the handshake succeeds, so the destination and cert are fine — only the missing SNI breaks it.
Minimal repro (any machine, no SDK involved):
```python
import ssl, socket
host = ".r2.cloudflarestorage.com"
ip = socket.gethostbyname(host)
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ctx.check_hostname = False; ctx.verify_mode = ssl.CERT_NONE
# no server_hostname => no SNI => fatal handshake_failure from Cloudflare
ctx.wrap_socket(socket.create_connection((ip, 443))) # SSLV3_ALERT_HANDSHAKE_FAILURE
```
## Expected
The egress gateway should forward an SNI matching the destination hostname on the upstream TLS handshake, so requests to `*.r2.cloudflarestorage.com` (and any other SNI-required origin) succeed.
## Impact
Any Managed Agents workload that uploads/downloads to Cloudflare R2 via the S3-compatible API fails at the network layer, regardless of credentials or request correctness. Credentials and the R2 endpoint are verified healthy — an identical signed `PutObject`/`GetObject`/`DeleteObject` round-trip from a normal network (which sends SNI) succeeds.
## Environment
- `@anthropic-ai/sdk` `0.112.3`
- Managed Agents beta (`managed-agents-2026-04-01`), `agent_toolset_20260401` built-in toolset
- Sandbox environment: `config: { type: "cloud", networking: { type: "unrestricted" } }`
- Destination: `https://.r2.cloudflarestorage.com` (Cloudflare R2, S3-compatible API)
## Workaround
Have the agent emit the generated artifact back through the session stream and perform the R2 upload from outside the sandbox (where SNI is sent normally). Not viable for workloads that must egress from within the sandbox.
Guía de contribución
Evaluación
Este issue todavía no se ha evaluado.