Secure lightweight broker for browser-based remote shell access.
Status: Active · Go · TypeScript · Noise Protocol · part of TrustSentinel
stk gives a client a shell on a host without exposing SSH — or any inbound port — to the network. A small Go hub brokers the connection; the client and the host-side agent run an end-to-end, mutually-authenticated Noise session on top, so the hub only ever relays ciphertext. The agent dials out to the hub, so there is no shell port to attack.
A runnable MVP builds, is unit-tested, and ships with a Docker Compose end-to-end
demo — see Quick start. There are two clients: a native CLI
(stk-client) and a browser client — the same Go Noise code compiled to
WebAssembly, driving an xterm.js terminal (see web/). The original 2019
browser front end is kept under _legacy/ for reference.
flowchart LR
client["client<br/>(CLI or browser)"]
hub["stk hub<br/>broker · relays ciphertext only"]
agent["agent (host)<br/>PTY shell"]
client -->|WebSocket| hub
agent -->|"dials out, no open port"| hub
client -.->|"end-to-end encrypted (Noise IK, mutual auth)"| agent
Build and unit-test:
go build ./...
go test ./...Run the full end-to-end demo (client gets a brokered, encrypted shell on the agent):
cd deploy/compose
docker compose build
docker compose run --rm e2e # exits 0 on PASS
docker compose down -vTry the browser client (xterm.js + wasm):
make web # build web/stk.wasm
./browser-demo.sh # starts a hub (serving web/) + an agent, prints a URLOpen the printed URL and press Connect. See web/.
On Kubernetes (throwaway kind cluster — build, deploy, run the e2e Job):
deploy/k8s/kind-test.sh # ends with: K8S RESULT: PASSWithout Docker: ./smoke.sh (or make smoke) starts a hub, agent, and client
locally and asserts a command round-trips through the encrypted broker.
cmd/—stk-hub(broker),stk-agent(PTY shell),stk-client(CLI),stk-keygen,stk-wasm(browser client)internal/transport/— message-framed connection (websocket / browser websocket / in-memory pipe)internal/secure/— Noise XX handshake, mutual-auth session (overflynn/noise)internal/shell/— PTY-backed shell (creack/pty)web/— browser client: xterm.js UI + the wasm build gluecrypto/— key handling + secure randomness, a separately-tested moduledeploy/—compose/(full e2e),k8s/(Kubernetes manifests + kind test),test/(crypto tests)_legacy/— the original 2019 GOPATH prototype + browser front end, kept for reference (not built)
- Each device has a persistent identity:
-identity <file>loads it, creating one (mode 0600) on first use. Its public key is what peers pin/authorize. - The client pins the agent it will talk to:
-authorized-agent <agent-pubkey>(required — this is what defeats a malicious hub / MITM). - The agent authorizes clients:
-authorized-clients <file>is an SSH-authorized_keys-style registry (one base64 key per line,#comments), re-read each session so enrolling a client needs no restart.-authorized-client <key>sets a single key inline. Empty ⇒ accept any authenticated client (dev).
Working Go MVP (hub + agent + CLI and browser clients), Noise IK mutual auth (unauthorized clients refused on the first message), persistent device identities + an enrollment registry, unit tests, a runnable Compose e2e, Kubernetes manifests with a kind test, and GitHub Actions CI. Next: hardware attestation to bind identities to a TPM/secure element; richer browser UX (resize, reconnect, login).
Part of TrustSentinel — secure connectivity and network-intelligence tooling by Álvaro López.
- netso — secure-networking platform (SSI + end-to-end encryption)
- stk — browser-based remote shell broker · this repo
- stuk — SSH access gating (port-knock + MFA)
- argos — P2P blockchain network scanning
- eth-rlp — RLP codec for Ethereum discv4
MIT
Originally prototyped at bluebycode/stk (2019); continued under TrustSentinel.

