1. Host-header injection (sso_initiate / sso_complete): replace
request.host_url with dify_config.CONSOLE_API_URL via a
_trusted_origin() helper that fails closed when unset. An
attacker-controlled Host header on sso-initiate would otherwise
be sealed into the signed state envelope, causing the IdP to
redirect the victim's EE-signed SSO assertion to evil.com.
2. Unvalidated JWS claim payloads: add ExtSubjectAssertionClaims
and ApprovalGrantClaimsPayload pydantic models and route every
verified payload through model_validate. A signed-but-malformed
blob now returns BadRequest('invalid_sso_assertion') or
VerifyError('claim shape invalid') instead of crashing the
handler with KeyError / 500. ApprovalGrantClaimsPayload is
imported lazily inside verify_approval_grant to break the
libs -> controllers cycle.
3. Timing-unsafe CSRF compare in approve_external: replace plain
!= with secrets.compare_digest.
4. Bearer rate-limit bypass on revoked tokens: move
enforce_bearer_rate_limit to fire after sha256_hex but before
resolver.resolve, so revoked-token replay is now bounded. Also
collapse the two distinct error messages (unknown token prefix
vs token unknown or revoked) into a single generic
'invalid_bearer' to remove the prefix-validity oracle.
Tests: 4 new unit-test files cover each finding plus one updated
test for the new bearer error string. 744 tests pass.
- docker-compose.yaml: revert api/web from build: back to image tags
(1.14.1); fix api_websocket/worker/worker_beat downgraded to 1.14.0
- Remove verbose internal design comments from openapi controllers
- web/next.config.ts: trim anti-framing comment to one line
- cli/tsconfig.json: drop lib:ES2015 override (broke Error.cause typing)
- eslint.config.mjs: ignore cli/context/** and cli/docs/** (local caches)
- pnpm-lock.yaml: regenerate after fresh install