- C# 75.6%
- JavaScript 12.1%
- CSS 7.6%
- HTML 4.3%
- Dockerfile 0.4%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
CORTEX_CLIENT_TOKEN, CORTEX_OPERATOR_KEY, CORTEX_TRUSTED_PROXIES and CORTEX_ALLOWED_HOSTS now work as plain environment variables, matching .env and compose.yaml. The Cortex__ names still win when both are set. Bump to 0.4.0. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> |
||
| .impeccable | ||
| docs | ||
| src | ||
| tests/Cortex.Tests | ||
| .dockerignore | ||
| .env.example | ||
| .gitattributes | ||
| .gitignore | ||
| AGENTS.md | ||
| compose.yaml | ||
| Cortex.slnx | ||
| DESIGN.md | ||
| Dockerfile | ||
| PRODUCT.md | ||
| README.de.md | ||
| README.md | ||
Cortex
English | Deutsch
Rescue shell access for machines where RDP, SSH and the usual remote tools no longer work.
A small client runs on the broken machine and dials out to your server. An operator opens the server's web console in a browser, picks the machine and runs shell commands on it. Because the client connects outbound, it works behind NAT and firewalls, and it is built to keep running and reconnecting no matter what.
Operator's browser ──HTTPS──▶ Reverse proxy ──▶ Server ◀──── outbound WebSocket ──── Client (on the broken machine)
(web console, login) (TLS, VPN/firewall) (SignalR hub, REST API) (Windows or Linux, runs as a service)
Features
Client (Windows and Linux, native AOT, one small self-contained binary)
- Runs as a Windows service or systemd service (
install/uninstall), starts at boot, restarts after a failure. - Reconnects forever with backoff; output produced while offline is queued and delivered later.
- Persistent shell:
cmd.exeon Windows,bash(orsh) on Linux. Working directory and environment survive between commands. - PowerShell on demand (
Send-PS): the script is passed without any quoting or escaping. On Linux this needspwsh. - Shell fallback: if
cmd.exeis broken or missing, commands run through one-shotpowershell.exeand the console says so. - Abort, Reset and a command timeout (default 15 min) kill the whole process tree, so a hung command never blocks the machine's access.
- Correct text encoding (OEM code page on Windows, UTF-8 on Linux), separate stdout/stderr, real exit codes.
- Reports its health: version, user, whether it is elevated/SYSTEM/root, active shell, busy/idle with queue length, last seen.
- Stable client ID per machine (machine name plus machine id), so a rebooted machine reappears as the same client.
Server (ASP.NET Core + SignalR, also native AOT)
- Web console and REST API; several operators can watch the same client at once.
- Per-client history (bounded, in memory) replayed when you reload the page or switch clients.
- Live online/offline status and command visibility for every open console.
- Client token: only clients that know the shared secret can register or send output.
- Operator login: a 32-byte key protects the console, REST API and live output, with lockout after repeated failures.
- Built for a TLS reverse proxy (forwarded headers, keep-alive tuning, nginx/Caddy examples).
- Runs as a Windows or systemd service too, with hardening on Linux.
Quick start (try it locally)
Requirements: .NET 10 SDK.
# 1. Start the server (open mode, only for local testing)
dotnet run --project src/Server
# 2. In another terminal, start a client that connects to it
dotnet run --project src/Client -- run --server http://localhost:5254/hub
# 3. Open the console
# http://localhost:5254/
Select the client in the console, type a command (for example dir or ls) and press Enter.
Without secrets configured, both sides warn that they are open. Do not expose that setup to a network.
Deployment
1. Build the binaries
dotnet publish src/Server -c Release -r win-x64 # or linux-x64
dotnet publish src/Client -c Release -r win-x64 # or linux-x64
Native AOT cannot cross-compile: build for Linux on Linux and for Windows on Windows. Windows needs the Visual Studio
C++ build tools (and vswhere.exe on PATH), Linux needs clang and zlib1g-dev. The results run without installing .NET.
2. Create the secrets (once)
cortex-server genkey # prints a new operator key: 32 random bytes as 64 hex characters
Choose a long random client token as well. They are two different secrets: the operator key logs people in to the console, the client token lets machines register. Keep both in a password manager.
3. Install the server
Run from an elevated prompt (Windows) or with sudo (Linux, needs systemd):
cortex-server install --urls http://127.0.0.1:5254 --token <ClientToken> --operator-key <OperatorKey> --trusted-proxies 127.0.0.1
Put a TLS-terminating reverse proxy in front of it (nginx and Caddy configs are in docs/DEPLOYMENT.md).
The proxy must allow WebSocket upgrades on /hub and use long timeouts. Restrict access with a firewall or VPN as well.
To run the server in Docker instead, see the Docker section in docs/DEPLOYMENT.md
(cp .env.example .env, then docker compose up -d --build).
4. Install the client on each machine
cortex-client install --server https://rescue.example.com/hub --token <ClientToken>
The service starts immediately, at every boot, and after failures. Remove it with cortex-client uninstall / cortex-server uninstall.
Secrets are stored in the service environment (Windows registry value, or a root-only 0600 file on Linux), never on the command line.
Client options: --name <id> (override the client ID), --command-timeout <minutes>, --token <secret> (or the
CORTEX_TOKEN environment variable).
More detail, including where secrets live and Linux notes: docs/DEPLOYMENT.md.
Usage
Web console
- Open the server URL and log in with the operator key (the session lasts 12 hours).
- Clients is a searchable table with state, name, system, user, activity and last seen; filter by All / Online / Attention / Offline, sort by a column header, and open a machine with a click or Enter. In the console, the client switcher in the top bar (or Ctrl+K) jumps to another machine by name.
- The console shows the machine's health (state, activity, last seen, user, rights, shell, version, uptime) next to a dark output window. On narrow screens the health collapses to a one-line summary.
- Choose cmd (or sh) or PowerShell, type a command and press Enter or Send. Up and Down recall earlier commands of that machine.
- Abort stops the running command. Reset restarts the shell and drops queued commands, so it asks for a second press to confirm. The eraser clears only your view; the wrap button toggles line wrapping.
- The theme button cycles automatic, light and dark. The layout adapts from phone to wide monitor.
A client shown as "Not responding" is connected but has not sent a heartbeat for 90 seconds; try Abort, then Reset. Shortcuts: Ctrl+K client switcher, / search on the Clients page.
REST API (for scripts)
Every request under /clients needs the operator key as a bearer token (or the session cookie from POST /auth/login).
KEY=<OperatorKey>
curl -H "Authorization: Bearer $KEY" https://rescue.example.com/clients # connected clients
curl -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"commandText":"whoami"}' https://rescue.example.com/clients/<clientId>/command # run a command
curl -H "Authorization: Bearer $KEY" https://rescue.example.com/clients/<clientId>/history # output so far
curl -H "Authorization: Bearer $KEY" -X POST https://rescue.example.com/clients/<clientId>/abort
Use "shell":"powershell" in the command body for PowerShell. Output is read from /history; each command ends with one
entry carrying isFinal: true and its exitCode.
| Endpoint | Purpose |
|---|---|
GET /clients |
Connected clients with health information |
GET /clients/{id}/history |
Commands and output for a client |
POST /clients/{id}/command |
Run a command (commandText, optional shell: cmd or powershell) |
POST /clients/{id}/reset, /abort |
Restart the shell / stop the running command |
POST /auth/login, /auth/logout, GET /auth/session |
Operator session (no login needed for these) |
Security model
- Network: put the server behind TLS and a firewall or VPN. The console page itself is public but contains no data.
- Clients authenticate with the shared client token (
Cortex:ClientToken). Without a valid token a connection cannot register, send output or impersonate a client. - Operators authenticate with the operator key (
Cortex:OperatorKey). It is compared in constant time, sessions are signed and stateless, and five wrong keys lock an address out for 15 minutes. - With no secrets configured, the server is open and logs a warning on startup.
- Anyone with the operator key can run commands as the client's service account (SYSTEM / root). There are no per-user accounts and no audit of who ran what; rotate the key if it may have leaked.
Platform support and limitations
| Windows | Linux | |
|---|---|---|
| Client / Server | yes | yes (systemd for services) |
| Shell | cmd.exe, PowerShell fallback |
bash or sh, pwsh optional |
- Commands are line based: programs that wait for interactive input (
pause,ssh, editors) can only be recovered with Abort/Reset or the timeout. - Abort, Reset and timeouts restart the shell, so the working directory and environment variables are lost.
- History lives in server memory (20,000 entries) and is cleared when the server restarts.
- The client is not packaged for macOS, and no self-update exists yet.
- The Windows service
installpath has not yet been verified on a real elevated system. The Linux path has been tested on Ubuntu with systemd.
Project layout
Code is organized in vertical slices, the same names in each project (details in AGENTS.md).
src/Shared wire contracts, one JSON context, service installer
src/Server hub, REST API, history, security, hosting, console page (wwwroot/ui.html)
src/Client connection, shell execution, health, startup
tests MSTest project that mirrors the slices
docs DEPLOYMENT.md (proxy, services, Docker, secrets), REVIEW.md (findings and what was fixed)
Development
dotnet build Cortex.slnx
dotnet test Cortex.slnx # Windows runs the cmd.exe tests, Linux runs the bash tests; the rest is skipped
The tests start real shells and an in-memory server, so they take a few seconds and need the platform's shell.
AGENTS.md describes conventions for contributors and coding agents.
Documentation
- docs/DEPLOYMENT.md: reverse proxy, services on Windows and Linux, secrets, operator login
- docs/REVIEW.md: design review, fixed issues and open items
- AGENTS.md: architecture overview and rules for contributing