Release 1.26.0 - Egress Auth & Security Hardening
July 2026
Upgrading from 1.25.0
This section covers everything you need to know to upgrade from 1.25.0 to 1.26.0.
Breaking Changes
This release adds a preflight validator to build_and_run.sh that refuses to start the stack when secrets are left at known-weak defaults. This affects LOCAL Docker Compose deployments only (e.g. a local box, EC2, or macOS running build_and_run.sh). Managed deployments are NOT affected - AWS ECS/DocumentDB and EKS/Helm supply their own secrets and do not run this preflight.
If you are a local Docker Compose user upgrading an existing deployment, build_and_run.sh will now fail with:
ERROR: DOCUMENTDB_PASSWORD is set to the known-weak default 'admin'.
ERROR: OPENBAO_TOKEN is set to the known-weak default 'dev-root-token'.
You must set strong values in .env. The two secrets are handled differently:
- OpenBao token (
OPENBAO_TOKEN) - the dev OpenBao container runs in-memory and is recreated on every restart, so there is no stored data to preserve. Just set a strong value (openssl rand -hex 32) in.env. Any previously vaulted egress credentials are re-established by reconnecting accounts after startup. - MongoDB password (
DOCUMENTDB_PASSWORD) - your existingmongodb-datavolume already holds a user created with the OLD password. MongoDB only creates that user on first boot, so changing.envalone does NOT update the stored user and will lock the app out of your existing data (registered servers/agents). You must rotate the stored user's password in place first, then set the same value in.env.
Full step-by-step instructions (including macOS sed variants, verification, and troubleshooting) are in the new FAQ:
If you do not need to preserve local data, you can instead recreate the MongoDB volume - see How do I migrate an existing local MongoDB to authenticated mode?.
Related hardening in this release that local Docker Compose users should be aware of:
- MongoDB now runs with authentication by default in
docker-compose.yml(--auth+ a keyfile-init helper). Fresh installs create the root user fromDOCUMENTDB_USERNAME/DOCUMENTDB_PASSWORDon first boot;build_and_run.shauto-generates a strongDOCUMENTDB_PASSWORDwhen it is unset (#1386). - Non-front-door Compose ports are now loopback-bound (
127.0.0.1) by default; only the nginx front door (80/443) is published on all interfaces. Override withHOST_BIND_IP=0.0.0.0if you deliberately need LAN access (#1376). - Keycloak realm setup uses
sslRequired=external(notnone). The orphaneddisable-ssl.shwas removed and the setup guides were corrected (#1380, #1384).
Breaking changes for Helm / EKS
The weak-secret preflight does not run on EKS, but there are two required upgrade actions:
- New
openbaosubchart dependency. The stack chart (charts/mcp-gateway-registry-stack/Chart.yaml) now declares anopenbaodependency (condition: openbao.enabled) for the per-user egress credential vault. You must runhelm dependency build/helm dependency updatebeforehelm upgrade(see Upgrade Instructions), or the packaged subcharts will be stale. Many other subchart templates/values also changed this release, so this is required regardless. - New required value
egressAuth.markerSecretfor standalone deployments. The chart now rendersAUTH_SERVER_NGINX_MARKER_SECRETvia{{ required ... }}, so a standalone install/upgrade fails to render unlessegressAuth.markerSecretis set to a strong random value (identical across auth-server and registry). It guards all mcp-proxy token minting and is not egress-specific. Set it in your values before upgrading.
Breaking changes for Terraform / ECS
No mandatory new variables: the egress credential vault is off by default (egress_auth_enabled = false) and every new variable (cors_allowed_origins, mcp_proxy_timeout, the egress_* family) has a default. Two things to know:
- If you enable the egress vault (
egress_auth_enabled = true), ECS uses AWS Secrets Manager as the backend and the registry task role is granted scopedsecretsmanager+ KMS access underegress_secrets_manager_path_prefix. Set theegress_*variables accordingly (seeterraform/aws-ecs/terraform.tfvars.example). egress_nginx_marker_secretis auto-generated into Secrets Manager when left empty; set it only to pin a specific value. (ECS supplies this automatically, unlike the Helm standalone path which requires it explicitly.)
New Environment Variables
| Variable | Default | Description |
|---|---|---|
EGRESS_AUTH_ENABLED |
false |
Enable the per-user egress credential vault (third-party OBO). |
SECRET_STORE_BACKEND |
openbao |
Secret store for per-user egress tokens: secrets-manager or openbao. |
OPENBAO_ADDR |
http://openbao:8200 |
OpenBao backend address. |
OPENBAO_TOKEN |
(required, no default) | OpenBao token. The preflight rejects the old dev-root-token. |
OPENBAO_NAMESPACE |
(empty) | OpenBao namespace (enterprise/HCP). |
OPENBAO_KV_MOUNT |
secret |
KV v2 mount path. |
OPENBAO_AUTH_METHOD |
token |
OpenBao auth method (token for Compose; kubernetes for EKS). |
OPENBAO_ROLE |
(empty) | OpenBao role for kubernetes auth. |
EGRESS_OAUTH_CALLBACK_BASE_URL |
(empty) | Base URL for the egress OAuth callback. |
EGRESS_TOKEN_REFRESH_SKEW_SECONDS |
300 |
Refresh egress tokens this many seconds before expiry. |
EGRESS_STATE_TTL_SECONDS |
600 |
TTL for the egress OAuth state parameter. |
SECRETS_MANAGER_PATH_PREFIX |
mcp/egress |
Path prefix for the AWS Secrets Manager backend. |
SECRETS_MANAGER_KMS_KEY_ID |
(empty) | Optional KMS key for the Secrets Manager backend. |
AWS_SECRETS_REGION |
(empty) | Region for the Secrets Manager backend (falls back to AWS_REGION). |
CORS_ALLOWED_ORIGINS |
(empty) | Exact allowlist of browser origins for credentialed CORS (fail-closed). |
MCP_PROXY_TIMEOUT |
30 |
Upstream read timeout (seconds) for the MCP proxy hop; supports long-running tool calls. |
AUTH_SERVER_NGINX_MARKER_SECRET |
(auto-generated) | Shared marker secret guarding mcp-proxy token minting; build_and_run.sh generates it if empty. |
DOCUMENTDB_PASSWORD |
(required, no default) | MongoDB/DocumentDB password. The preflight rejects admin; build_and_run.sh generates a strong value when unset. |
SECRET_KEY |
(auto-generated) | Session-signing key; enforced minimum length. build_and_run.sh generates it if empty. |
PF_ADMIN_PASS |
(placeholder) | PingFederate admin password; the shipped placeholder is rejected. |
Upgrade Instructions
Docker Compose
cd mcp-gateway-registry
git pull origin main
git checkout 1.26.0
# REQUIRED (local Docker Compose upgrades): set strong secrets before starting.
# OpenBao is in-memory (no data to preserve): set a strong OPENBAO_TOKEN in .env.
# MongoDB: rotate the stored password IN PLACE, then set it in .env -- otherwise
# you lose access to your existing data. Full steps:
# docs/faq/rotate-mongodb-and-openbao-secrets.md
# Review new env vars in .env.example and update your .env, then:
./build_and_run.shKubernetes / Helm (EKS)
cd mcp-gateway-registry
git pull origin main
git checkout 1.26.0
# REQUIRED: chart files changed in this release, so rebuild packaged subcharts.
cd charts/mcp-gateway-registry-stack
helm dependency build
helm dependency update
# Update values.yaml (new egress-vault / OpenBao settings) then upgrade:
helm upgrade mcp-gateway . -f your-values.yamlThe weak-secret preflight is a build_and_run.sh check and does not run on EKS. Helm/EKS deployments supply DOCUMENTDB_PASSWORD and the OpenBao/vault configuration through their own values/secrets.
Terraform / ECS
cd mcp-gateway-registry
git pull origin main
git checkout 1.26.0
# Update your .tfvars with any new variables (egress vault / Secrets Manager)
cd terraform/aws-ecs
terraform plan
terraform applyECS uses AWS DocumentDB (authenticated + TLS by the managed service) and AWS Secrets Manager, so the local weak-secret preflight and MongoDB password rotation do not apply.
Pre-built Images (Amazon ECR Public)
The three gateway service images are published to Amazon ECR Public and pulled by the prebuilt Compose path (./build_and_run.sh --prebuilt). Override the namespace with ECR_REGISTRY if you mirror them elsewhere.
docker pull public.ecr.aws/p3v1o3c6/registry:1.26.0
docker pull public.ecr.aws/p3v1o3c6/auth-server:1.26.0
docker pull public.ecr.aws/p3v1o3c6/mcpgw:1.26.0The example MCP servers (currenttime, realserverfaketools) and the metrics service are built locally by build_and_run.sh and are not published as release images.
Major Features
Per-user egress credential vault (third-party OBO)
The gateway can now broker per-user, third-party credentials for egress to external MCP servers, so an authenticated user's connection to a downstream SaaS (e.g. Slack, Atlassian, GitHub) uses that user's own OAuth token rather than a shared credential. Tokens are held in a secret store - OpenBao (a dev-mode container ships with Docker Compose; a sealed, file-backed standalone OpenBao ships with Helm) or AWS Secrets Manager - and refreshed ahead of expiry. Off by default (EGRESS_AUTH_ENABLED=false).
Configurable MCP proxy timeout
The MCP proxy hop's upstream timeout was hardcoded to 30s, causing long-running tool calls to fail with 504. It is now a first-class parameter, MCP_PROXY_TIMEOUT, wired across all deployment surfaces (Compose, Helm, Terraform) and derived into nginx's proxy_read_timeout.
LLM tool-execution confirmation and A2A agent authentication
Agent tool execution is now gated behind an explicit confirmation step, and agent-to-agent (A2A) calls authenticate the calling agent, closing an unauthenticated-execution path.
What's New
Security Hardening
This release is a broad security-hardening pass across the auth, proxy, and data layers:
- Enable MongoDB authentication by default in Docker Compose; drop the committed weak
adminpassword (#1386) - Loopback-bind all non-front-door Compose ports by default (#1376)
- Remove the orphaned
disable-ssl.shthat weakened Keycloak TLS; keepsslRequired=external(#1380) - Remove weak default Keycloak credentials and stop forcing non-temporary passwords (#1381)
- Remove the anonymous
/.well-known/mcp-serversdiscovery endpoint (#1374) - Drop unused
python-joseto remove CVE-bearing transitive dependencies (#1387) - Add access control to
GET /servers/{path}/versionsso it no longer leaks backend URLs (#1388) - Make peer federation tokens write-only in responses (#1389)
- Separate internal service tokens from user tokens (#1359); MCP session-id hardening (#1357)
- SSRF URL validation on registration and OAuth token calls (#1363, #1396)
- CORS allowlist made fail-closed and credential-aware (#1364)
- ID-token signature verification and secret-key length hardening (#1366, #1367)
- Authorization/ownership checks tightened across management routes (#1365)
- Enforce CSRF validation on IAM management and federation endpoints (#1390)
- Stop relaying caller credentials to untrusted MCP/A2A upstreams (#1391); treat client auth headers as ingress-only and strip on egress (#1369)
- Block script-scheme (
javascript:/data:) URLs in dynamic frontend links (#1394) - MCP proxy body-integrity: re-authorize the exact forwarded body, fail closed on an uninspectable body (#1393)
- Require a per-deployment secret for metrics API-key hashing and close a rate-limit oracle (#1399)
- Restrict read-only info disclosure on management/search responses (#1397)
- Harden Docker Compose stacks against insecure defaults, incl. a weak-secret denylist and preflight (#1400, #1368)
- Raise dependency floors above known CVE fixes (incl. aiohttp), refresh all
uv.lockfiles, and extend the python-jose guard to the root and all sub-project manifests/locks (#1401) - Federation credential hardening: validate peer
endpointURLs through the SSRF guard on create/update/sync and harden peer credential handling (#1398) - Log redaction and secret hygiene: redact secrets/tokens from logs across auth-server, providers, and CLI/discovery clients; keep freshly minted M2M secrets off stdout; write secret files with
0600perms (#1405)
Deployment
- Add an OpenBao dev-mode container to the Docker Compose stacks (#1349)
- Pull prebuilt images from Amazon ECR Public instead of Docker Hub (#1352)
Documentation
- New FAQ: rotate MongoDB password + OpenBao token for local Docker Compose (#1402)
- Remove DockerHub publish steps from the release-notes skill (the project no longer publishes to DockerHub) (#1404)
- Stop instructing
sslRequired=nonein the setup guides;externalis correct (#1384) - Fix mermaid rendering in the auth and egress-vault docs (#1382, #1383, #1373, #1375)
- Add a self-service lifecycle workflow demo video link
Bug Fixes
- Repair the fresh-deploy path in
docker-compose.podman.yml: mongo-init credentials, OAuth discovery env wiring, and realm-setup documentation (#1395) - Make the MCP proxy upstream timeout configurable to fix 504s on long-running tool calls (#1356)
- Update
TemplateResponsecalls to the current Starlette signature (#1360) - Reduce authorization lookups and extend nginx header stripping (#1342)
- Remove the invalid "file" storage backend from the terraform-setup skill docs (#1353)
- Recurse into the FastAPI 0.138 included-router wrapper in the internal-route meta-test (#1347)
Closed Issues
| Issue | Title | Closed By |
|---|---|---|
| #1379 | docker-compose.podman.yml: mongodb-init default credentials don't match the no-auth mongodb-ce service | #1395 |
| #1378 | docker-compose.podman.yml: KEYCLOAK_EXTERNAL_URL/MCP_HTTPS_REQUIRED not passed to containers; Keycloak has no host port mapping | #1395 |
| #1377 | docker-compose.podman.yml: Keycloak realm import is silently broken | #1395 |
| #1320 | MCP proxy hop upstream timeout is hardcoded to 30s (long-running tool calls fail with 504) | #1356 |
| #1266 | Egress: ingress-token relay fix (relay-ingress + none) | #1369 |
Pull Requests Included
| PR | Title |
|---|---|
| #1405 | log redaction |
| #1404 | docs(skill): remove DockerHub publish steps from release-notes skill |
| #1402 | docs(faq): rotate MongoDB password + OpenBao token for local Docker Compose (EC2/macOS) |
| #1401 | update dependencies (raise floors above CVE fixes; extend python-jose guard) |
| #1398 | federation credential hardening |
| #1400 | harden compose: case-insensitive weak-secret denylist; blank PF_ADMIN_PASS placeholder |
| #1399 | fix(metrics-service): require per-deployment secret for API-key hashing; close rate-limit oracle |
| #1397 | readonly info restriction |
| #1396 | fix(egress): route OAuth token calls through the SSRF guard and escape callback HTML |
| #1395 | fix(podman): repair fresh-deploy path in docker-compose.podman.yml |
| #1394 | frontend xss hrefs |
| #1393 | mcp proxy integrity |
| #1392 | feat: gate LLM tool execution behind confirmation and authenticate A2A agents |
| #1391 | fix: stop relaying caller credentials to untrusted MCP/A2A upstreams |
| #1390 | fix: enforce CSRF validation on IAM management and federation endpoints |
| #1389 | fix(security): make peer federation_token write-only in responses |
| #1388 | fix(security): add access control to GET /servers/{path}/versions |
| #1387 | fix(security): drop unused python-jose (removes CVE-bearing deps) |
| #1386 | fix(security): enable MongoDB auth by default; drop weak admin password |
| #1384 | docs: stop instructing sslRequired=none; external is correct |
| #1383 | docs(egress-vault): fix mermaid render of placeholders |
| #1382 | docs(auth): fix mermaid render of token placeholder |
| #1381 | fix(security): remove weak Keycloak default credentials |
| #1380 | fix(security): remove orphaned disable-ssl.sh that weakened Keycloak TLS |
| #1376 | fix(security): loopback-bind non-front-door compose ports |
| #1375 | docs(egress): make mermaid notes/messages parseable |
| #1374 | security: remove /.well-known/mcp-servers anonymous discovery endpoint |
| #1373 | docs(egress): fix mermaid render error from angle-bracket token placeholders |
| #1369 | fix(egress): treat client auth headers as ingress-only, strip on egress |
| #1368 | remove hardcoded placeholder secrets |
| #1367 | secret key hardening |
| #1366 | idtoken signature |
| #1365 | authz and ownership |
| #1364 | cors and cookies |
| #1363 | ssrf url validation |
| #1361 | feat(nginx): derive mcp-proxy proxy_read_timeout from MCP_PROXY_TIMEOUT |
| #1360 | fix: update TemplateResponse calls to current Starlette signature |
| #1359 | fix(security): separate internal service tokens from user tokens |
| #1358 | feat(config): wire MCP_PROXY_TIMEOUT as a first-class param across all surfaces |
| #1357 | (fix) mcp session id hardening |
| #1356 | fix: make MCP proxy upstream timeout configurable |
| #1353 | fix(terraform-setup): remove invalid "file" storage backend from skill docs |
| #1352 | fix(compose): pull prebuilt images from ECR Public instead of Docker Hub |
| #1351 | update python-jose dependency |
| #1350 | docs(slides): update presentation PDF |
| #1349 | feat(compose): add OpenBao dev-mode container to Docker Compose stacks |
| #1347 | test(auth): recurse into FastAPI 0.138 included-router wrapper |
| #1344 | build(deps): bump actions/checkout |
| #1342 | fix: reduce authz lookups, extend nginx header stripping, reuse constants |
| #1312 | Feat/egress auth |
| #1305 | feat(helm): standalone OpenBao for per-user egress credential vault |
Contributors
Thank you to all contributors for this release:
Support
Full Changelog: 1.25.0...1.26.0
What's Changed
- chore: update image tags to 1.25.0 by @github-actions[bot] in #1338
- build(deps): bump actions/checkout from 6.0.3 to 7.0.0 in /.github/workflows in the actions group by @dependabot[bot] in #1344
- test(auth): fix authserver test for FastAPI 0.138 by @omrishiv in #1347
- chore(deps): weekly lockfile update (2026-06-29) by @github-actions[bot] in #1346
- feat(helm): standalone OpenBao for per-user egress credential vault by @omrishiv in #1305
- feat(compose): add OpenBao dev-mode container to Docker Compose stacks by @aarora79 in #1349
- docs(slides): update presentation PDF by @aarora79 in #1350
- fix(compose): pull prebuilt images from ECR Public instead of Docker Hub by @aarora79 in #1352
- fix(terraform-setup): remove invalid "file" storage backend from skill docs by @aarora79 in #1353
- Feat/egress auth by @omrishiv in #1312
- (chore) update python-jose dependency by @omrishiv in #1351
- (fix) mcp session id hardening by @omrishiv in #1357
- fix: make MCP proxy upstream timeout configurable (#1320) by @zsxh1990 in #1356
- feat(config): wire MCP_PROXY_TIMEOUT as a first-class param across all surfaces by @aarora79 in #1358
- Separate internal service tokens from user tokens by @aarora79 in #1359
- Fix TemplateResponse calls for current Starlette signature by @aarora79 in #1360
- Derive mcp-proxy nginx proxy_read_timeout from MCP_PROXY_TIMEOUT by @aarora79 in #1361
- fix: reduce authz lookups, extend nginx header stripping, reuse constants by @omrishiv in #1342
- ssrf url validation by @omrishiv in #1363
- authz and ownership by @omrishiv in #1365
- cors and cookies by @omrishiv in #1364
- idtoken signature by @omrishiv in #1366
- secret key hardening by @omrishiv in #1367
- remove hardcoded placeholder secrets by @omrishiv in #1368
- reuse uv.lock for precommit tests by @omrishiv in #1371
- (fix): checkov skip placement by @omrishiv in #1372
- fix(egress): treat client auth headers as ingress-only, strip on egress (#1266) by @aarora79 in #1369
- docs(egress): fix mermaid render error in egress-auth-design by @aarora79 in #1373
- docs(egress): fix mermaid render (notes/messages with arrow syntax) by @aarora79 in #1375
- security: remove anonymous /.well-known/mcp-servers discovery endpoint by @aarora79 in #1374
- fix(security): loopback-bind non-front-door compose ports (SA-5) by @aarora79 in #1376
- fix(security): remove orphaned disable-ssl.sh that weakened Keycloak TLS (SA-8) by @aarora79 in #1380
- fix(security): remove weak Keycloak default credentials (SA-9) by @aarora79 in #1381
- docs: stop instructing sslRequired=none; external is correct by @aarora79 in #1384
- fix(security): enable MongoDB auth by default; drop weak admin password (SA-11) by @aarora79 in #1386
- fix(security): drop unused python-jose to remove CVE-bearing deps (SA-13) by @aarora79 in #1387
- fix(security): add access control to GET /servers/{path}/versions (SA-19) by @aarora79 in #1388
- fix(security): make peer federation_token write-only in responses (SA-24) by @aarora79 in #1389
- csrf protection by @omrishiv in #1390
- close potential credential leak by @omrishiv in #1391
- docs(egress-vault): fix mermaid render of placeholders by @zsxh1990 in #1383
- docs(auth): fix mermaid render of token placeholder by @zsxh1990 in #1382
- a2a example llm tool safety by @omrishiv in #1392
- mcp proxy integrity by @omrishiv in #1393
- frontend xss hrefs by @omrishiv in #1394
- fix(podman): repair fresh-deploy path (realm setup, OAuth discovery, mongo-init) (#1377, #1378, #1379) by @aarora79 in #1395
- route OAuth token calls through the SSRF guard by @omrishiv in #1396
- readonly info restriction by @omrishiv in #1397
- metrics key hardening by @omrishiv in #1399
- compose hardening by @omrishiv in #1400
- docs(faq): rotate MongoDB password + OpenBao token for local Docker Compose (EC2/macOS) by @aarora79 in #1402
- update dependencies by @omrishiv in #1401
- docs(skill): remove DockerHub publish steps from release-notes skill by @aarora79 in #1404
- federation credential hardening by @omrishiv in #1398
- chore: update image tags to 1.26.0 by @github-actions[bot] in #1403
- log redaction by @omrishiv in #1405
New Contributors
Full Changelog: 1.25.0...1.26.0