Skip to content

All versions since v3.0.2

v3.0.2

What’s new

A drop-in patch — no migrations, no config changes. It fixes over-aggressive rate limiting that could surface a normal dashboard load as a 500, makes the frontend self-heal stale chunks after an upgrade, refreshes the app icons, and — the headline — launches the public documentation site at bridgeport.bridgein.com.


Fixes

Rate limiting no longer trips on normal page loads (#312)

The global limiter (100 req/min per IP) was applied to every route, including static-asset serving and the SPA shell — so a single dashboard load (HTML + a dozen hashed JS/CSS chunks + 30s polling) could exhaust the budget for one legitimate user. The rejection on the static route was then mis-classified as a 500 and captured to error monitoring.

  • Static/SPA GET/HEAD requests are now exempt from the limiter; /api/* and /mcp stay throttled — the limiter protects the programmatic surface, not local file serving.
  • Genuine rate-limit responses now return a correct 429 Too Many Requests with Retry-After instead of a 500, and no longer spam error monitoring.

If you front BridgePort with a reverse proxy or CDN, that’s the right layer to DoS-protect static serving.

Frontend self-heals stale chunks after a deploy (#312)

A vite:preloadError handler now does a one-shot, cooldown-guarded reload when a lazy-loaded route chunk fails to fetch — typically right after an upgrade swaps the hashed assets. “Failed to fetch dynamically imported module” errors recover transparently instead of dead-ending the page.


Improvements

Refreshed app icons (#310)

New favicon and PWA/app-tile icons in the brand aesthetic — the red crane mark on dark #0a0e14 tiles, with a transparent favicon that adapts to light and dark browser tab strips.


Security

  • CVE-2026-12143 / GHSA-hmw2-7cc7-3qxx — CRLF injection in form-data (< 4.0.6), high severity, pinned to ≥ 4.0.6. This dependency lives only in the docs-site build toolchain (website/) and never reaches the app runtime or the Docker image, so the running app was never exposed — closed for hygiene. (#309)

Documentation

Public documentation site launched (#307, #308, #311, #313)

BridgePort now has a full docs site at bridgeport.bridgein.com, built with Astro Starlight from the repo’s docs/ — a single source, so the site and GitHub never drift. Highlights:

  • Full-text search, dark/light, branded to match the app UI
  • API reference auto-generated from the OpenAPI spec
  • Architecture & flow diagrams rendered from Mermaid
  • A changelog sourced from these GitHub Releases (so this release will appear there automatically)
  • Real product screenshots (dashboard, monitoring, services)
  • An llms.txt endpoint so AI agents can consume the docs
  • Auto-deploys via Cloudflare on every docs change and on each published release

API changes

None. (Rate-limit responses now return 429 instead of an erroneous 500 — a fix, not a surface change; see Fixes.) -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgEyiv4hf6iBgr34ICjN6HnEP/vs Yr31eNU5HhdkQaYd4AAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQLoiwVIhyZuzlKhDAlmko0bhVpoKrbuRyBug03RBdL0BFftf7YkHAREPYq7n9qD4Hh r2jduikwYktaNiQCaXrQI= -----END SSH SIGNATURE-----

v3.1.0 Latest

What’s new

This is a security-hardening release. It closes an unauthenticated deploy-trigger path in the incoming webhook endpoints, escapes every user-influenced value that reaches a shell command (closing command-injection paths, including one on the control-plane host), fixes a cross-environment access-control gap on the database monitoring routes, and adds SSRF guards to the registry and outgoing-webhook clients. It also ships dashboard-topology rendering fixes and expanded documentation. No database migrations.

If you use the incoming webhook endpoints (/api/webhooks/*), read “Action required” below before upgrading — they now fail closed.


Action required before upgrading

Skip this section if you don’t use the incoming CI/CD webhook endpoints.

Incoming webhooks now fail closed

The /api/webhooks/deploy, /api/webhooks/deploy-image, and /api/webhooks/github endpoints now require a configured secret and a valid signature. Previously the signature was verified only when a secret happened to be set (and the GitHub endpoint could be bypassed entirely by omitting the signature header). If the relevant secret is not set, the endpoint is now disabled and returns 401.

Before upgrading, make sure the secret is configured on your BridgePort instance:

Terminal window
# Generate a strong secret and set it in your environment / compose:
openssl rand -base64 32
# WEBHOOK_SECRET=... (for /api/webhooks/deploy and /deploy-image)
# GITHUB_WEBHOOK_SECRET=... (for /api/webhooks/github)

Your CI must sign the exact request body bytes it sends (HMAC-SHA256, hex; the GitHub endpoint uses the sha256= prefix). See docs/guides/webhooks.md. If you don’t use these endpoints, no action is needed. (#351)


Security

This release resolves findings from an internal security review. The webhook issue is the only one reachable without authentication; the command-injection and SSRF paths require an authenticated operator (BridgePort’s role gate already blocks read-only “viewer” accounts from the operations that reach them), and the IDOR affects environment-scoped API tokens.

  • Unauthenticated webhook deploy-trigger / signature bypass — the GitHub webhook verified its signature only when the header was present, so omitting it skipped verification even with a secret configured; the other webhook endpoints verified only when a secret was set. All three now fail closed (secret + valid signature required), HMAC is computed over the raw request bytes, and the comparison is length-safe. Malformed payloads and image tags containing shell metacharacters are rejected. (#351)
  • Command-injection hardening in shell exec paths — every user-influenced value interpolated into a shell command (container name, image reference, health-check URL, database-backup connection fields, SSH monitoring placeholders) is now shell-escaped, and config/compose files are written over SFTP instead of shell heredocs. (#351)
  • Cross-environment access control (IDOR) — the database metrics, test-connection, and monitoring sub-routes now verify the database belongs to the environment in the request path, so an environment-scoped token can no longer reach databases in other environments. (#351)
  • SSRF guards — the container-registry client and the admin outgoing-webhook delivery path now block private/loopback/link-local/cloud-metadata addresses and no longer follow redirects; registryUrl must be a valid URL. (#351)
  • Defense-in-depth — baseline security response headers (X-Content-Type-Options, X-Frame-Options, Referrer-Policy), an explicit secret-scrub on outbound Sentry events, and a startup warning when JWT_SECRET is weak. (#351)

Tracked as follow-ups (not in this release): hashing agent tokens at rest, explicit per-route role gates on the service/registry routes, and per-account login throttling.


Fixes

Dashboard topology rendering (#335, #336, #337)

  • Services with deployments on multiple servers now render under every server they run on in the dashboard topology diagram, instead of only one. (#335, #336)
  • Saved server-box sizes are clamped to their children’s footprint, so a manually-resized server box no longer clips the services inside it. (#337)

Documentation

  • “What’s Next” roadmap page — the docs site now has a /roadmap/ page generated at build time from the GitHub milestones and epics, plus a discoverable manual redeploy workflow for refreshing it. (#349)
  • Maintainer runbook — a new docs/development/maintainer-runbook.md consolidating release, CI, tracker, and naming conventions. (#350)
  • Docs-site build & deploy documentation and general discoverability improvements. (#315, #334)

Under the hood

  • Release → docs refreshrelease.yml now pings the Cloudflare Pages deploy hook after cutting a release, so the docs changelog refreshes without waiting for the next push to master. (#314)
  • Dependency-group bumps: #331, #332, #333. -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgEyiv4hf6iBgr34ICjN6HnEP/vs Yr31eNU5HhdkQaYd4AAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQNdqD+8jBq0JCSd88RMP81EGZNPSM0s0KvG5Xa0UWCVsx0Ii8D8rfvQ1qr//f4IH52 Dk1u7+dyoKVwWppZ27vg8= -----END SSH SIGNATURE-----