Skip to content

Changelog

Version v1.1.0 — security hardening

v1.1.0 is a security-hardening release. Three critical and five high-severity CVEs patched, SSH command composition hardened against injection, global rate limiting added, Slack webhook validation tightened. All backwards-compatible for self-hosters — pull, restart, migrations run, done.

⚠️ Behavior change to be aware of

Global rate limiting is now active. 100 requests per minute per client IP, across all routes except /health and /api/client-config. If you have programmatic integrations that poll aggressively, they may start getting HTTP 429 responses with a retryAfterSeconds field. Adjust client polling or loosen the limit via custom config if needed.

Security fixes

Patched CVEs

  • fast-jwt 5.0.6 → 6.2.2 (via @fastify/jwt 9 → 10 — PR #69) closes:
    • Critical — Cache confusion via cacheKeyBuilder collisions returning claims from a different token
    • Critical — Incomplete fix for CVE-2023-48223 (JWT algorithm confusion via whitespace-prefixed RSA keys)
    • Highfast-jwt accepts unknown crit header extensions (RFC 7515 violation)
    • Moderate — Stateful RegExp non-deterministic allowed-claim validation (logical DoS)
    • Moderate — ReDoS in allowed* claim validation during token verification
  • Numerous additional CVEs patched via grouped dependency updates (backend, frontend, CLI, agent, Docker).

Code-level hardening

  • Slack webhook URL validation (#63) — replaced a substring check (.includes('hooks.slack.com')) with proper new URL(url).hostname === 'hooks.slack.com'. URLs like https://evil.com/?x=hooks.slack.com are now correctly rejected.
  • SSH command injection surface (#67, #68) — introduced shellEscape() in src/lib/ssh.ts and applied it at every call site where a user-configured value (paths, container names, etc.) is interpolated into a shell command string. Covers deploy, database-backup, database-query-executor, config-files, agent-deploy, and service log streaming. Double-quoting alone was insufficient — $, backticks, and $() were still interpreted.
  • Global rate limiting (#64) — @fastify/rate-limit registered globally, 100 req/min/IP, /health and /api/client-config allow-listed so external monitors don’t get throttled.

Dependencies

Significant bumps:

  • @fastify/jwt 9.1.0 → 10.0.0 (security)
  • @fastify/multipart 9.4.0 → 10.0.0
  • @fastify/cors 10.x → 11.x (bundled in grouped backend security update)
  • zod 3.x → 4.x (backend — with forward-compatible code changes in #62)
  • fast-jwt 5.0.6 → 6.2.2 (transitive via @fastify/jwt)
  • @types/node 22.x → 25.x
  • Docker base image golang:1.22-alpine1.26-alpine
  • CLI Go toolchain 1.22 → 1.25
  • Plus grouped backend-security, frontend-security, cli-minor-and-patch, agent-minor-and-patch, actions-version groups.

Developer experience

  • shellEscape() helper exported from src/lib/ssh.ts — wrap any value interpolated into a command string.
  • New convention documented in CLAUDE.md (Backend Patterns) and docs/development/testing-guide.md (Unit test rule 7 on keeping vi.mock factories in sync with module exports).
  • Dependabot grouping (#50) — security updates and minor+patch bumps now land as one PR per ecosystem per week, instead of dozens of individual PRs.

Upgrading

Terminal window
docker pull ghcr.io/bridgeinpt/bridgeport:latest
docker stop bridgeport && docker rm bridgeport && docker run -d ... # same args as before

Migrations apply automatically on first start. No manual steps.

Full changelog

https://github.com/bridgeinpt/bridgeport/compare/v1.0.0…v1.1.0