Releases: shellhub-io/shellhub
v0.25.1
What's Changed
- fix(api): stop persisting unused pty-req modelist by @gustavosbarreto in #6436
- fix(api): enforce unique namespace names in postgres by @otavio in #6439
- fix(api): widen device pretty_name column to 256 chars by @gustavosbarreto in #6443
- chore: bump shellhub version to v0.25.1-rc.1 by @gustavosbarreto in #6444
- fix(ssh): fall back to base domain for web endpoint host header by @luizhf42 in #6445
- refactor: consolidate web endpoints domain fallback into shared pkg by @luizhf42 in #6447
- feat(ui): auto-lock secure vault after inactivity by @luizhf42 in #6448
- feat(ui-react): rework the command palette for quick device connect by @luizhf42 in #6409
- ssh: bump golang.org/x/crypto from 0.52.0 to 0.53.0 in /ssh by @dependabot[bot] in #6449
- agent: bump golang.org/x/sys from 0.45.0 to 0.46.0 in /agent by @dependabot[bot] in #6451
- ui: bump the tiptap group in /ui with 6 updates by @dependabot[bot] in #6453
- ui: bump typescript-eslint from 8.60.1 to 8.61.0 in /ui by @dependabot[bot] in #6454
- ui: bump axios from 1.16.1 to 1.17.0 in /ui by @dependabot[bot] in #6455
- ui: bump @types/react from 18.3.30 to 18.3.31 in /ui by @dependabot[bot] in #6456
- ui: bump vite from 7.3.3 to 7.3.5 in /ui by @dependabot[bot] in #6457
- agent: bump golang.org/x/crypto from 0.52.0 to 0.53.0 in /agent by @dependabot[bot] in #6450
- api: bump golang.org/x/crypto from 0.52.0 to 0.53.0 in /api by @dependabot[bot] in #6452
- fix(ssh): close dead device connections to stop log spam and CPU spin by @gustavosbarreto in #6460
- chore: bump shellhub version to v0.25.1-rc.2 by @gustavosbarreto in #6461
- fix(api): upsert active_sessions to prevent duplicate key error on session update by @geovannewashington in #6463
- chore: bump shellhub version to v0.25.1-rc.3 by @gustavosbarreto in #6464
- fix(api): renumber colliding 004 migration and guard against duplicates by @gustavosbarreto in #6465
- fix(api): return 400 instead of 500 on a malformed filter by @otavio in #6466
- fix(install): install shellhub-agent host wrapper for docker and podman installs by @geovannewashington in #6462
- chore: bump shellhub version to v0.25.1 by @gustavosbarreto in #6470
Full Changelog: v0.25.0...v0.25.1
v0.25.0
ShellHub v0.25.0 finishes two long-running migrations and opens the door to AI tooling. The backend now runs on a single Postgres datastore, the console is React-only, and there is a built-in MCP server so assistants like Claude Code and Cursor can drive ShellHub directly.
Postgres is now the only datastore
The MongoDB store has been removed and Postgres is the sole storage implementation (#6429). This is the end of the migration started in earlier releases: less surface area, one query layer, one set of migrations to reason about.
Upgrading from a MongoDB-backed install? Complete the Mongo to Postgres migration before moving to v0.25.0. There is no in-place path back once you are on a Mongo-less build. Check
/api/migration/statusand follow the migration guide first.
One console, built on React
The deprecated Vue frontend is gone (#6401) and the React frontend has been promoted from ui-react to ui as the only served console (#6423). Everything now ships from a single, actively developed UI.
Manage ShellHub from your AI assistant
ShellHub now embeds an MCP (Model Context Protocol) server inside the api service (#6266). AI assistants (Claude Code, Claude Desktop, Cursor) can list and manage devices, sessions and namespaces without any extra binary or sidecar.
It authenticates with a namespace API key sent as X-API-Key, validated through the same nginx auth_request path as the REST API. Tools run through the API middleware in-process, so authorization is enforced by exactly the same layer that guards /api (#6400).
{
"mcpServers": {
"shellhub": {
"url": "https://<shellhub-host>/mcp",
"headers": { "X-API-Key": "<your-api-key>" }
}
}
}Device custom fields
Attach arbitrary metadata to devices and manage it through per-key endpoints (#6248, #6286).
Valkey replaces Redis
The cache and pubsub backend moved from Redis to Valkey, a drop-in Redis fork (#6402). If you point ShellHub at an external Redis, switch it to Valkey.
Also in this release
Features
- Namespace device auto-accept setting (#6264)
- Billing & subscription management in the console (#6232)
- Chatwoot live-chat support widget (#6249) and user-facing announcement modal (#6265)
- Cloud free-tier device chooser (#6279)
- Web endpoints:
tls.domainas Host override even without TLS (#6321), and a Domain without enabling TLS (#6323) - Customer-facing API documentation build (#6392)
Fixes
- Block API keys on account-level routes (#6397) and return clean 404s for malformed tenant/namespace IDs (#6405, #6408)
- Public key tag sync (#6340), percent-encoded fingerprint paths (#6336), and search across all pages (#6384)
- Restore TLS-to-backend in the web endpoint proxy (#6320)
- CLI: fatal on config parse error (#6326), namespace inspect device counts (#6325) and member list (#6324)
- Console: validate add-member email (#6315); UTF-8 base64 list filters (#6388); Setup, Sign In, app bar and namespace selector polish (#6344, #6343, #6403, #6399)
Performance
- Scope session event aggregation to the listed page (#6433)
Enterprise
- Enterprise-only license banner in the console (#6342)
- Use the
api-enterpriseimage in the enterprise compose (#6291) and pass web endpoint envs to it (#6394) - Map
SHELLHUB_-prefixed SAML env vars on the api service (#6410)
Under the hood
- Reusable agent core extracted into the importable
agentdpackage (#6431) - docker-compose wrapper rework with profiles and bats tests (#6337, #6339, #6348)
- Shared-component and OpenAPI refactors across the UI
- Dependency updates across all services (Go 1.25.11, Alpine, nginx, assorted Go/npm modules) via Dependabot
New Contributors
- @danielgatis made their first contribution in #6248
- @kekius-maximus45 made their first contribution in #6315
Full Changelog: v0.24.2...v0.25.0
v0.24.2
What's Changed
- chore(deps): bump go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp from 1.41.0 to 1.43.0 in /tests by @dependabot[bot] in #6146
- feat(ui-react): implement announcements admin panel by @luizhf42 in #6133
- feat(ui-react): add admin sessions list and detail pages by @luannmoreira in #6107
- ci: remove private registry dependency from CI workflows by @gustavosbarreto in #6150
- fix(infra): ensure postgres container restarts after host reboot by @geovannewashington in #6152
- refactor(ui-react): unify main and admin sidebar behavior by @luizhf42 in #6151
- chore(deps): bump axios from 1.13.6 to 1.15.0 in /ui-react by @dependabot[bot] in #6157
- ui: bump axios from 1.14.0 to 1.15.0 in /ui by @dependabot[bot] in #6156
- fix(cli): ensure first user created via CLI is admin by @geovannewashington in #6155
- fix(gateway): raise WebSocket timeouts and enable TCP keepalive by @gustavosbarreto in #6158
- chore(ci): remove verify-fix workflow by @gustavosbarreto in #6161
- feat(agent): default transport to yamux (v2) by @gustavosbarreto in #6163
- fix(ui-react): fix sidebar behavior when terminal is open by @luizhf42 in #6166
- refactor(ui-react): add reusable
DataTablecomponent by @luizhf42 in #6164 - refactor(api): remove RSA signature gate from initial setup flow by @geovannewashington in #6162
- fix(ui-react): fix License page upload input on Chromium by @luizhf42 in #6189
- docker: api: bump golang from 1.25.8-alpine3.22 to 1.25.9-alpine3.22 in /api by @dependabot[bot] in #6186
- docker: cli: bump golang from 1.25.8-alpine3.22 to 1.25.9-alpine3.22 in /cli by @dependabot[bot] in #6185
- docker: agent: bump golang from 1.25.8-alpine3.22 to 1.25.9-alpine3.22 in /agent by @dependabot[bot] in #6184
- docker: ssh: bump golang from 1.25.8-alpine3.22 to 1.25.9-alpine3.22 in /ssh by @dependabot[bot] in #6183
- docker: gateway: bump golang from 1.25.8-alpine3.22 to 1.25.9-alpine3.22 in /gateway by @dependabot[bot] in #6182
- docker: ui: bump nginx from 1.29.7-alpine to 1.29.8-alpine in /ui by @dependabot[bot] in #6181
- ui: bump typescript-eslint from 8.58.0 to 8.58.2 in /ui by @dependabot[bot] in #6180
- refactor(ui-react): split useCopy hook into its own file by @luizhf42 in #6167
- chore: update gliderlabs/ssh fork to fix golang.org/x/crypto v0.50.0 compatibility by @gustavosbarreto in #6193
- ui: bump eslint-plugin-jest from 29.15.1 to 29.15.2 in /ui by @dependabot[bot] in #6171
- ssh: bump golang.org/x/net from 0.52.0 to 0.53.0 in /ssh by @dependabot[bot] in #6170
- api: bump github.com/getkin/kin-openapi from 0.134.0 to 0.135.0 in /api by @dependabot[bot] in #6177
- api: bump golang.org/x/crypto from 0.49.0 to 0.50.0 in /api by @dependabot[bot] in #6178
- ui: bump follow-redirects from 1.15.11 to 1.16.0 in /ui by @dependabot[bot] in #6192
- agent: bump github.com/mattn/go-shellwords from 1.0.12 to 1.0.13 in /agent by @dependabot[bot] in #6172
- api: bump github.com/testcontainers/testcontainers-go/modules/postgres from 0.41.0 to 0.42.0 in /api by @dependabot[bot] in #6179
- api: bump github.com/getsentry/sentry-go from 0.44.1 to 0.45.1 in /api by @dependabot[bot] in #6175
- chore(deps): bump actions/github-script from 8 to 9 by @dependabot[bot] in #6188
- chore(deps): bump softprops/action-gh-release from 2 to 3 by @dependabot[bot] in #6187
- fix(ui-react): clear query cache on logout to drop stale user data by @luizhf42 in #6194
- fix(ui-react): surface swallowed errors in ConfirmDialog delete flows by @luizhf42 in #6168
- chore(deps): migrate dependabot from ui to ui-react by @luizhf42 in #6198
- feat(cli): add type column to namespace list output by @geovannewashington in #6197
- docker: ui-react: bump node from 24.13.0-alpine3.22 to 24.15.0-alpine3.22 in /ui-react by @dependabot[bot] in #6207
- ui-react: bump @types/node from 25.5.0 to 25.6.0 in /ui-react by @dependabot[bot] in #6209
- ui-react: bump @hey-api/openapi-ts from 0.94.3 to 0.94.5 in /ui-react by @dependabot[bot] in #6210
- ui-react: bump typescript-eslint from 8.57.0 to 8.58.2 in /ui-react by @dependabot[bot] in #6211
- ui-react: bump vitest from 4.1.0 to 4.1.4 in /ui-react by @dependabot[bot] in #6208
- ssh: bump github.com/pires/go-proxyproto from 0.11.0 to 0.12.0 in /ssh by @dependabot[bot] in #6206
- ui-react: bump @tiptap/markdown from 3.22.2 to 3.22.3 in /ui-react by @dependabot[bot] in #6205
- api: bump github.com/testcontainers/testcontainers-go/modules/mongodb from 0.41.0 to 0.42.0 in /api by @dependabot[bot] in #6204
- docker: ssh: bump alpine from 3.23.3 to 3.23.4 in /ssh by @dependabot[bot] in #6203
- docker: gateway: bump alpine from 3.23.3 to 3.23.4 in /gateway by @dependabot[bot] in #6200
- docker: api: bump alpine from 3.23.3 to 3.23.4 in /api by @dependabot[bot] in #6202
- docker: ui-react: bump nginx from 1.29.4-alpine to 1.29.8-alpine in /ui-react by @dependabot[bot] in #6201
- docker: cli: bump alpine from 3.23.3 to 3.23.4 in /cli by @dependabot[bot] in #6199
- chore(ui-react): remove deprecated
baseUrlfrom ui-react'stsconfig.jsonby @luizhf42 in #6212 - refactor(ui-react): use
@import alias by @luizhf42 in #6213 - fix(openapi): align tag name pattern with backend validation by @luizhf42 in #6216
- ui-react: bump postcss from 8.5.8 to 8.5.10 in /ui-react by @dependabot[bot] in #6225
- ui-react: bump axios from 1.15.0 to 1.15.1 in /ui-react by @dependabot[bot] in #6224
- ui-react: bump @tiptap/react from 3.22.2 to 3.22.4 in /ui-react by @dependabot[bot] in #6221
- ui-react: bump autoprefixer from 10.4.27 to 10.5.0 in /ui-react by @dependabot[bot] in #6223
- chore(deps): bump actions/setup-node from 6.3.0 to 6.4.0 by @dependabot[bot] in #6220
- api: bump github.com/labstack/gommon from 0.4.2 to 0.5.0 in /api by @dependabot[bot] in #6219
- api: bump github.com/jackc/pgx/v5 from 5.9.1 to 5.9.2 in /api by @dependabot[bot] in #6217
- fix(api): expose internal namespace lookup for SSH service by @gustavosbarreto in #6228
- fix(api): let admin panel through RequiresTenant guard by @gustavosbarreto in #6229
- feat(ui-react): add Containers page and components by @luizhf42 in #6214
- feat(ui-react): add team invitations feature by @luizhf42 in #6191
- ui-react: bump typescript-eslint from 8.58.2 to 8.59.0 in /ui-react by @dependabot[bot] in #6222
- fix(ui-react): fix lint error in
ContainerTagsPopovertest by @luizhf42 in #6231 - api: bump github.com/moby/moby/api from 1.54.1 to 1.54.2 in /api by @dependabot[bot] in #6218
- docs(api): remove status field from namespace member schema by @geovannewashington in #6230
- feat(ui): add SAML SSO login and admin authentication settings by @luannmoreira in #6196
- test: optimize healthchecks and force image rebuild by @gustavosbarreto in #6234
- fix(ui-react): make sidebar p...
v0.21.7
Security
Fixes four cross-tenant and input-validation advisories:
- GHSA-vwx9-7qcf-gg7f — cross-tenant IDOR on namespace endpoints reachable via API Key and JWT callers, allowing a caller to read, edit, delete or toggle session recording of a namespace they are not scoped to, and to enumerate namespaces across tenants on the list endpoint. (initially fixed in v0.21.6)
- GHSA-j72x-xfwg-783f —
GET /api/devices/:uidreturned the full device object for any authenticated caller, allowing cross-tenant disclosure of device metadata (hostname, MAC, OS, public key, remote address, last-seen). - GHSA-9w9c-9w8m-w89q —
GET /api/sessions/:uidreturned the full session object for any authenticated caller, allowing cross-tenant disclosure of SSH session data (username, device UID, remote IP, authentication state, timestamps). - GHSA-47r2-v3x6-wff9 — filter and sort query parameters on the device list accepted attacker-controlled identifiers as BSON keys, enabling HTTP 500 crash-DoS and blind regex extraction via
$regexvalues.
Full Changelog: v0.21.6...v0.21.7
v0.21.6
Security
Fixes GHSA-vwx9-7qcf-gg7f — cross-tenant IDOR on namespace endpoints reachable via API Key and JWT callers, allowing a caller to read, edit, delete or toggle session recording of a namespace they are not scoped to, and to enumerate namespaces across tenants on the list endpoint. Reported by @Edu0x01.
What's Changed
- fix(api): prevent cross-tenant access via API Key and JWT by @gustavosbarreto
Full Changelog: v0.21.5...v0.21.6
v0.24.1
What's Changed
- feat(ui-react): add admin user management pages by @luizhf42 in #6086
- feat(ui): add admin namespace management by @luizhf42 in #6105
- feat(ui-react): handle token query param on Login page for admin login-as-user by @luizhf42 in #6110
- fix(ui-react): fix connection announcement overflow in admin namespace details by @luizhf42 in #6109
- feat(ui-react): add admin device list and detail pages by @luizhf42 in #6113
- ui: bump defu from 6.1.4 to 6.1.6 in /ui by @dependabot[bot] in #6115
- ui: bump lodash from 4.17.23 to 4.18.1 in /ui by @dependabot[bot] in #6111
- fix(ci): temporarily pin
claude-code-actionto 1.0.88 by @luizhf42 in #6125 - feat(ui-react): add admin firewall rules list and detail pages by @luizhf42 in #6116
- ci: add SBOM generation to release workflows by @otavio in #6112
- fix(ui-react): resolve prettier and eslint formatting conflicts by @luizhf42 in #6126
- ui: bump turndown from 7.2.2 to 7.2.4 in /ui by @dependabot[bot] in #6122
- ui: bump vuetify from 3.12.3 to 3.12.5 in /ui by @dependabot[bot] in #6121
- ui: bump sass from 1.98.0 to 1.99.0 in /ui by @dependabot[bot] in #6120
- api: bump github.com/lib/pq from 1.12.1 to 1.12.3 in /api by @dependabot[bot] in #6119
- ui: bump @vue/runtime-dom from 3.5.31 to 3.5.32 in /ui by @dependabot[bot] in #6118
- chore(deps-dev): bump vite from 7.3.1 to 7.3.2 in /ui-react by @dependabot[bot] in #6117
- ui: bump qrcode.vue from 3.8.0 to 3.8.1 in /ui by @dependabot[bot] in #6123
- fix(api): add id tiebreaker to paginated queries by @gustavosbarreto in #6127
- fix(ui-react): use server-side filtering for device search by @luizhf42 in #6129
- fix(ui-react): use plain strings for public key filter tags by @luannmoreira in #6128
- fix(api): qualify column names in device queries with JOINs by @gustavosbarreto in #6130
- fix(api): place AND operator before connector filter in device list by @gustavosbarreto in #6131
- fix(api): compute device online status in session queries by @luizhf42 in #6137
- fix(store): add missing "lt" operator to PG filter parser by @gustavosbarreto in #6140
- feat(cli): add namespace enumeration capabilites by @geovannewashington in #6132
- chore: bump shellhub version to v0.24.1 by @gustavosbarreto in #6141
Full Changelog: v0.24.0...v0.24.1
v0.24.0
PostgreSQL as Default Database
PostgreSQL is now the default and only supported database backend. MongoDB is no longer required.
If upgrading from v0.22.x or earlier, upgrade to v0.23.0 first to run the automatic migration pipeline, then upgrade to v0.24.0. See the migration guide for details.
v0.23.0
Database Migration (MongoDB to PostgreSQL)
This release introduces the automatic migration pipeline from MongoDB to PostgreSQL. On startup, ShellHub reads all data from MongoDB, writes it to PostgreSQL, and runs a deep field-by-field validation to ensure data integrity.
Set SHELLHUB_DATABASE=migrate in your .env to enable the migration. The migration status is exposed via GET /api/migration/status and shown in the UI.
The next release (v0.24.0) will switch the default database to PostgreSQL, completing the transition.
New React UI
The new admin interface built with React is now available alongside the existing Vue UI:
- Generated API SDK with TanStack Query, replacing the Axios/Zustand layer
- Role-based permission system
- Admin panel with dashboard and license management
- Session recording playback
- Password recovery, sign-up, and account confirmation flows
- Two-factor authentication (TOTP)
- Connect-via-terminal UX improvements
CLI
- New
user listcommand - TTY allocation is now disabled when stdout is not a terminal
Infrastructure
- Go 1.25.8
- golangci-lint v2.11.3
- Decoupled enterprise entry point from community module
- SAML types removed from core models
v0.22.0
ShellHub v0.22.0
The React Release
v0.22.0 is the biggest frontend change in ShellHub's history. The entire UI has been rebuilt from scratch in React with TypeScript, replacing the Vue-based frontend that served the project for years. This release also lays the groundwork for the upcoming PostgreSQL migration.
For the full story behind these changes, see Inside ShellHub #1.
New React UI
The new frontend ships as the default at /. The legacy Vue UI remains accessible at /v1 during the transition period.
Highlights compared to the previous frontend:
- No more Vuetify lock-in. The new UI uses Tailwind CSS with a custom design system, giving full control over styling without fighting a component library.
- Multi-session terminal. The old terminal opened one SSH session in a modal. The new one supports multiple concurrent sessions with a taskbar — minimize, restore, and fullscreen.
- Secure Vault. Store encrypted SSH private keys in the browser for password-protected key authentication directly from the web terminal.
- Welcome wizard. A guided onboarding flow for new users after account creation.
- Better error handling. Connection failures, expired sessions, and network drops show inline banners with clear messages instead of silently failing.
Unified Open-Core Architecture
The Cloud/Enterprise layer has been merged into the API binary. Instead of running a separate service, enterprise features are now compiled into the same binary and activated by configuration. This simplifies deployment, eliminates inter-service calls, and makes transactions across community and enterprise code truly atomic.
Agent Improvements
- Yamux multiplexing. The agent now uses multistream and yamux instead of an HTTP server for device communication, improving reliability and reducing overhead.
- Native static binary. Replaced the standalone runc dependency with a native static binary, simplifying agent distribution.
- PTY deadlock fix. Resolved a window-change deadlock that could freeze terminal sessions under load.
- ARMv6 support fix. Corrected architecture targeting for ARMv6 devices.
Infrastructure
- ACME-DNS support for web endpoint wildcard certificates — an alternative to DigitalOcean and Cloudflare DNS providers.
- MongoDB → PostgreSQL migration tooling is included in this release as groundwork for the v0.23.0 transition. Not yet active by default.
- Generic store test suite that validates both MongoDB and PostgreSQL implementations against the same test cases.
Bug Fixes
- Fixed namespace device counter cache discrepancies
- Fixed license device limit enforcement
- Fixed recovery email conflict check against empty strings
- Fixed trailing comma in agent config.json env array
- Improved web terminal error handling and reconnection
Updated Stack
- Go 1.24.13
- Node.js 24 (LTS)
- Alpine 3.22
New Contributors
- @geovannewashington made their first contribution in #5954
Full Changelog: v0.21.5...v0.22.0
v0.21.5
What's Changed
- ui: bump typescript-eslint from 8.50.1 to 8.51.0 in /ui by @dependabot[bot] in #5686
- agent: bump github.com/labstack/echo/v4 from 4.14.0 to 4.15.0 in /agent by @dependabot[bot] in #5683
- api: bump github.com/labstack/echo/v4 from 4.14.0 to 4.15.0 in /api by @dependabot[bot] in #5682
- ssh: bump github.com/labstack/echo/v4 from 4.14.0 to 4.15.0 in /ssh by @dependabot[bot] in #5681
- ui: bump vuetify from 3.11.5 to 3.11.6 in /ui by @dependabot[bot] in #5685
- ui: bump eslint-plugin-jest from 29.11.1 to 29.12.1 in /ui by @dependabot[bot] in #5684
- feat: simplify issue templates to reduce friction by @gustavosbarreto in #5689
- chore: remove documentation and security links from issue templates by @gustavosbarreto in #5691
- test(ui): improve main UI's store modules' tests by @luizhf42 in #5657
- feat: allow immediate device slot reuse after deletion by @gustavosbarreto in #5688
- test(ui): enhance main UI's store module tests by @luizhf42 in #5692
- test(ui): improve Admin's store modules' tests by @luizhf42 in #5693
- test(ui): improve
useTablePreferencescomposable tests by @luizhf42 in #5694 - fix: exclude removed devices from DeviceConflicts checks by @gustavosbarreto in #5695
Full Changelog: v0.21.4...v0.21.5