Security & Cryptography
Deep dive into Explita Tunnel's inner session encryption, ECDH key agreement, and threat model
Security in Explita Tunnel is designed around a zero-trust model with two clear boundaries:
- Outer Public Transport Layer: Public internet traffic (from web browsers, webhooks, or third-party APIs) connects to the edge gateway over standard TLS 1.3. The gateway terminates public TLS to perform virtual host routing, apply rate limits, and sanitize headers.
- Inner Tunnel Cryptographic Envelope: Authenticated encryption (ECDH P-256 + HKDF + AES-256-GCM) secures all HTTP request frames, streaming chunks, and WebSocket payloads across the tunnel connection between the edge gateway and your local workstation (dev PC).
[!NOTE] Understanding the Encryption Scope: Explita Tunnel's cryptographic envelope secures the inner tunnel session between the Edge Gateway and your local developer machine, rather than directly from the visitor's web browser to your PC. Because public browsers connect via standard HTTPS (
https://myapp.tunnel.explita.ng), the edge gateway terminates public TLS to inspect theHostheader for subdomain routing. Payloads are strictly processed in volatile memory under a zero-log policy, immediately re-encrypted into the inner tunnel envelope, and streamed across the WebSocket to your workstation.
🔐 The Cryptographic Protocol
Client CLI (eta) Gateway Server
│ │
│ 1. WebSocket Connect (TLS 1.3) │
├──────────────────────────────────────────────────────────────►│
│ │
│ 2. Hello Frame: Client Ephemeral ECDH Public Key (P-256) │
├──────────────────────────────────────────────────────────────►│
│ │
│ 3. Ready Frame: Server Ephemeral ECDH Public Key (P-256) │
│◄──────────────────────────────────────────────────────────────┤
│ │
│ 4. Local HKDF-SHA256 Derivation │ 4. Local HKDF-SHA256 Derivation
│ -> Symmetric 256-bit AES Key │ -> Symmetric 256-bit AES Key
│ -> Print SHA-256 Fingerprint │ -> Print SHA-256 Fingerprint
│ │
│ 5. Bidirectional Stream: AES-256-GCM Encrypted Frames │
│◄═════════════════════════════════════════════════════════════►│1. Ephemeral Key Exchange (ECDH P-256)
When the eta CLI connects to the gateway:
- The client generates a fresh, ephemeral Elliptic Curve Diffie-Hellman keypair using the NIST P-256 curve (
prime256v1). - The client transmits its public key in uncompressed DER/X9.62 format inside the initial
hellohandshake frame. - The gateway server generates its own ephemeral P-256 keypair, records the client's public key, and returns its public key in the
readyresponse frame.
Because both keypairs are generated in-memory and discarded upon session termination, the protocol delivers Perfect Forward Secrecy (PFS). Compromising a future key does not expose past tunnel sessions.
2. Key Derivation (HKDF-SHA256)
Both client and server compute the identical raw ECDH shared secret point on the elliptic curve. To ensure high cryptographic entropy, the raw secret is processed through HMAC-based Extract-and-Expand Key Derivation (HKDF-SHA256):
- Hash Function: SHA-256
- Derived Key Length: 32 bytes (256 bits)
- Info String:
"explita-tunnel-v1-session"
3. Authenticated Encryption (AES-256-GCM)
All HTTP request bodies, streamed chunks, headers, and WebSocket frame payloads are enveloped in Galois/Counter Mode (AES-256-GCM):
- Key: 256-bit derived symmetric key
- Initialization Vector (IV): 12-byte random cryptographic nonce generated per frame
- Authentication Tag: 16-byte GCM authentication tag appended to each payload
[!IMPORTANT] AES-256-GCM provides both confidentiality and data integrity. If any intermediary tampers with a single byte in transit, GCM tag verification immediately fails and the frame is rejected before parsing.
🪪 Cryptographic Fingerprint Verification
To detect Man-in-the-Middle (MITM) attacks during the initial key exchange, both the client and server compute a cryptographic fingerprint of the agreed session key:
Fingerprint = SHA256(Derived_AES_Key).slice(0, 16).toHex()When a tunnel session initializes, the terminal logs the computed fingerprint:
[Server] Tunnel connected: https://acme.tunnel.explita.ng (AES-256-GCM, fingerprint: SHA256:7f:a9:3c:...)
[Client] Connected! Session Fingerprint: SHA256:7f:a9:3c:...By comparing fingerprints, engineers can verify key agreement across untrusted networks.
🛡️ Edge Security & Threat Model
In addition to payload encryption, the Explita Tunnel gateway incorporates strict production guardrails:
1. Untrusted Header Sanitization
Clients calling public tunnel endpoints may attempt header spoofing attacks. Explita Tunnel eliminates this vector:
- All incoming headers prefixed with
x-explita-*are strictly stripped at the gateway. - Gateway-generated metadata (such as
x-explita-tunnel-id,x-explita-tenant, andx-explita-client-ip) is injected into the request only after sanitization. - The
Hostheader is checked andx-forwarded-hostis bound to the verified public domain.
2. IP & CIDR Firewall Allowlisting
You can restrict access to authorized IP addresses or webhook CIDR blocks directly at the CLI:
# Allow only GitHub webhook IP ranges and your developer IP
eta 3000 -s webhooks -i "192.30.252.0/22, 185.199.108.0/22, 203.0.113.42/32"When an unauthorized IP calls the tunnel:
- The gateway immediately terminates the request with HTTP 403 Forbidden.
- If a WebSocket upgrade is attempted, the socket closes with code
1008 (Policy Violation). - No request packets or connection attempts are forwarded to your local development machine.
3. Gateway Client Authentication (Token Verification)
To prevent unauthorized agents from opening tunnels on your self-hosted gateway, Explita Tunnel enforces token authentication before any cryptographic handshake begins:
- Pre-Shared Static Tokens (
AUTH_TOKENS): Gateway operators configure a comma-separated list of approved tokens in.env(AUTH_TOKENS="tok_1,tok_2"). This requires zero databases and automatically locks down the server. - Dynamic Multi-User Auth (
@explita/tunnel-server-plugin): For multi-tenant organizations, the plugin validates revocable developer tokens against Redis cache and PostgreSQL. - Immediate Rejection: Any agent connecting without a valid token is immediately terminated with WebSocket close code
1008 ("Invalid token")before any tunnel state or routing is registered.
4. HTTP Basic Authentication with Constant-Time Comparison
Protect staging or client preview tunnels with HTTP Basic Authentication:
eta 3000 -s client-demo -a "designer:SecretPass2026!"To eliminate timing attacks, credential verification uses Node.js timingSafeEqual:
const credsBuf = Buffer.from(decoded);
const expectedBuf = Buffer.from(expectedAuth);
if (credsBuf.length !== expectedBuf.length) return false;
return timingSafeEqual(credsBuf, expectedBuf);4. Rate Limiting & Resource Quotas
To prevent local resource exhaustion from denial-of-service attempts:
- Sliding Window Rate Limit: 100 requests per second per tunnel. Excess requests receive HTTP
429 Too Many Requestswith aRetry-After: 1header. - Maximum Request Body: 25 MB. Larger uploads trigger HTTP
413 Payload Too Large. - Session Duration Limit: 24-hour maximum continuous socket lifetime, enforcing regular cryptographic key rotation.