Skip to content

Product documentation

Pre-production security posture + dependency audit

A pre-production security pass over oathy: pinned-dependency CVE review and the security-relevant deployment/config invariants, with an honest OK / GAP / UNKNOWN verdict per area and links to the tracking tickets.

Pre-production security posture + dependency audit

This is the pre-production security pass called for as oathy approaches its production cutover. It covers two things: a CVE review of the pinned dependency versions, and the security-relevant deployment and configuration invariants the platform will ship with.

It is a findings report, not a set of fixes — every genuine gap is tracked by a linked ticket rather than patched here, because a security change deserves its own reviewed PR.

Validation boundary

Read this as a static review — source, chart, workflow, and Git branch-protection inspection, plus a live CVE lookup against public advisory databases as of the audit date. It is not a penetration test and not a running-system scan. In particular:

  • Dependency CVE claims name the CVE, the affected range, and the pinned version. They are grounded in public advisories retrieved on the audit date. The assistant's own training cut-off is January 2026, so the 2026 advisory detail here comes from live lookups; anything disclosed after the audit date is unknown and needs a fresh scan.
  • Resolved transitive versions (for example, the exact Spring Security version Spring Boot pulls) were read from the managed BOM and the project's own documentation, not from a live mvn dependency:tree. Confirm them with a real resolve before acting.
  • Branch-protection state was read from the GitHub API on the audit date; it is a mutable setting, so re-check it at cutover.
  • Nothing here observes the live cluster. Runtime posture (actual ingress TLS, actual NetworkPolicy enforcement by the cluster CNI, actuator reachability from the public internet) needs a live probe or a pentest to confirm.

Verdict

Prod-security-readiness: conditional-pass, with governance and config gaps to close first.

The dependency posture is genuinely strong. Every pin reviewed sits at or above the fix line for the 2026 CVE waves — Spring Boot 4.0.6 is one patch above the range CVE-2026-40976 (critical) hits, Jackson 2.22.1 is a fixed version for the June-2026 Jackson RCE batch, and Bouncy Castle 1.85 clears its known advisories. No unpatched known-critical dependency was found at the pinned versions as of the audit date. That is a clean result stated with evidence, not an absence of looking.

A subsequent live resolve (SSO-2224) went beyond the explicit pins to the full Boot-managed transitive closure — the "confirm with a real resolve" caveat above — and did surface a Critical/High backlog there that the pin review did not cover: tomcat-embed, the postgresql JDBC driver, and ONGRES scram (all now remediated in bom/pom.xml), plus a Bouncy Castle version skew — bcpkix/bcutil-jdk18on arriving transitively at 1.77 beside the pinned bcprov 1.85, now all pinned to 1.85. After these, a fresh full-reactor mvn dependency:tree cross-checked against the OSV.dev API shows the only remaining Critical/High is a test-scope-only protobuf-java (CVE-2024-7254), tracked under SSO-2225; the rest of the residual is MODERATE/LOW — now also cleared, with SSO-2239 pinning OpenTelemetry to 1.62.0 and Logback to 1.5.34 (see Part A).

The material items are governance and configuration, not vulnerable code:

  1. Spring Security 7.0.5 (via Spring Boot 4.0.6) is fixed for the critical Dynamic Client Registration CVE, but trails the June-2026 7.0.6 batch that patched a SAML-processing CVE — and the platform ships a SAML federation member (SSO-2160).
  2. Several security-relevant CI guards run on every PR but are not in branch-protection's required checks, so they do not actually block a merge — including the SSRF guard (SSO-2162).
  3. CVE scanning was advisory-only — nothing blocked a PR on a vulnerable dependency (SSO-1620 / SSO-742). Since this audit, SSO-742 wired both scanners into real gates that run per-PR and fail visibly (OWASP DC failBuildOnCVSS=7; osv-scanner fails on Critical/High — its invocation was also silently broken, see below). They are deliberately kept non-required in branch protection until a known transitive-HIGH backlog is remediated (SSO-2195), so they surface the gap without blocking merges.

None of these is a shipped exploit path today; all three should be closed before the prod cutover. The CI security guards that are required (29 contexts) cover the highest-value token, crypto, cookie, host-header, and Kubernetes-hardening invariants — see CI security guards.

Findings summary

Severity is the assistant's assessment for the pre-prod context; re-rate where a ticket calls for triage. Status is OK (invariant holds, evidenced), GAP (a real shortfall), or UNKNOWN (needs a live scan or pentest to settle).

Part A — dependencies / CVEs

AreaSeverityStatusEvidenceTicket
Jackson 2.x default-typing postureOKjackson.version = 2.22.1, a fixed version for the June-2026 Jackson batch (CVE-2026-54513 RCE, CVE-2026-54512 CVSS 9.2); check-no-default-typing is a required gate.
Jackson pin comment driftLowGAPbom/pom.xml comment + CLAUDE.md still describe a 2.21.3 pin, which is below the 2.21.4 fix line — a reversion trap.SSO-2161 (new)
Spring Boot 4.0.6OKCVE-2026-40976 (critical, auth bypass) affects 4.0.0 through 4.0.5; 4.0.6 is the fix.
Spring Security 7.0.x (DCR CVE)OKCVE-2026-22752 (CVSS 9.6, Authorization Server DCR) is fixed in 7.0.5, which Boot 4.0.6 pulls; the hub does enable DCR.
Spring Security 7.0.5 trails 7.0.6MediumGAP7.0.6 (2026-06-09) fixed 7 further CVEs incl. SAML processing; saml-member uses spring-security-saml2-service-provider.SSO-2160 (new)
Bouncy Castle — bcprov 1.85, but bcpkix/bcutil skewed to 1.77MediumREMEDIATEDThe bom pinned only bcprov-jdk18on1.85; bcpkix/bcutil-jdk18on leaked in transitively at 1.77 (saml-member: opensaml → cryptacular) — a BC version skew carrying CVE-2025-8916 + CVE-2026-5588 (both MODERATE). SSO-2224 pins all three to 1.85, clearing both. bcprov 1.85 already cleared CVE-2025-8885 (≤ 1.77) + CVE-2026-0636 (1.741.83).SSO-2224
Nimbus JOSE+JWT 10.9.1OKCVE-2024-21235 algorithm-confusion is structurally mitigated by the required jwt-decoder-algorithm-check (ES256 allow-list).
CVE scan as a merge gateMediumGAP (partially closed)Was: OWASP DC weekly/push failBuildOnCVSS=11 (never fails), no NVD_API_KEY; osv-scanner weekly, issue-only. SSO-742 since wired both as real per-PR gates (DC failBuildOnCVSS=7; osv fail-on-Critical/High) and fixed osv-scanner's silently-broken v1 invocation. Kept non-required pending transitive-HIGH remediation.SSO-1620 / SSO-742 (done) → SSO-2195 (remediate + promote to required)
Boot-managed / transitive CVEs (live resolve)HighREMEDIATEDA live mvn dependency:tree + osv-scanner v2.3.8 resolve (the caveat in the Validation boundary) surfaced Critical/High advisories in Boot-4.0.6-managed / transitive artifacts the explicit-pin review did not reach: tomcat-embed 11.0.21 (3 CRITICAL + 3 HIGH, CVE-2026-43515 / -43512 / -41293 / -42498 / -43513 / -41284), postgresql JDBC 42.7.10 (2 HIGH, CVE-2026-54291 / -42198), ONGRES scram 3.2 (1 HIGH, CVE-2026-53712). Pinned in bom/pom.xml11.0.24 / 42.7.13 / 3.4. A follow-up resolve also caught a Bouncy Castle skew (bcpkix/bcutil-jdk18on 1.77 beside bcprov 1.85), now pinned to 1.85 (see the Bouncy Castle row). After these, a fresh full-reactor resolve shows no remaining Critical/High except test-scope protobuf-java 4.26.1 (via grpc, CVE-2024-7254, HIGH) — tracked under SSO-2225; residual MODERATE/LOW (opentelemetry 1.55.0, logback 1.5.32) since remediated under SSO-2239 (see the OpenTelemetry + Logback row).SSO-2224, SSO-2225, SSO-2239
OpenTelemetry + Logback residual (MODERATE/LOW)Moderate / LowREMEDIATEDThe residual below the Critical/High bar the SSO-2224 resolve left: io.opentelemetry:* 1.55.0 (MODERATE, CVE-2026-45292 / GHSA-rcgg-9c38-7xpx — unbounded W3C-baggage-propagation memory + CPU allocation, fixed 1.62.0) and logback-classic/logback-core 1.5.32 (LOW — CVE-2026-10532 fixed 1.5.34, CVE-2026-9828 fixed 1.5.33; HardenedObjectInputStream object-injection, only when the hardened receiver is explicitly enabled). SSO-2239 pins the otel family via an opentelemetry-bom 1.62.0 import and logback via explicit logback-classic/-core 1.5.34 dependencyManagement entries, both before the spring-boot-dependencies import; a fresh full-reactor dependency:tree confirms otel 1.62.0 + logback 1.5.34 with no other managed version regressed.SSO-2239
Dependabot coverageOK.github/dependabot.yml covers Maven + GitHub Actions weekly, grouped Spring/Kotlin/shared-libs, labelled security.
Remaining pinned librariesUNKNOWNokhttp 5.4.0, pdfbox 3.0.8, bucket4j 8.10.1, twilio 12.1.1, tink 1.23.0, geoip2 5.2.0, pact 4.7.3 (test): no known high/critical at the pinned versions as of the audit date, but all post-date the training cut-off — confirm with a live scan.

Part B — security posture (config / invariants)

AreaSeverityStatusEvidenceTicket
Ingress TLSOKingress-tls-annotations-check is a required gate; SSL-bundle references use the #{null} SpEL default across hub / product-api / api-gateway / synthetic-monitor.
Staging TLS certHighGAPStaging hub wildcard cert expired (cert-manager ACME challenge stuck).SSO-2119 (tracked)
Default-deny NetworkPolicy (ingress)OKNamespace-wide default-deny-ingress renders and is enabled in values-staging.yaml (networkPolicy.enabled: true).
Default-deny NetworkPolicy (egress)MediumGAPnetworkPolicy.egressEnabled: false in staging and enabled: false by default in values.yaml; no prod values file yet. Hub keeps its own per-service egress policy as SSRF defence-in-depth.SSO-1797 (tracked)
Operator-set / seed secretsOK (tracked follow-ups)Seed client secrets moved {noop}{bcrypt} (SSO-741); per-service AES key backup and Vault-at-deploy design are tracked.SSO-2101 / SSO-2137 / SSO-2129 / SSO-2139 (tracked)
CI security guards as hard gatesHighGAP29 required contexts on main; 6 security-relevant guards run on every PR but are not required, so they do not block merge — incl. outbound-url-guard-check (SSRF).SSO-2162 (new)
trustTestIssuers defaultOKTrustedTenantIssuers defaults trustTestIssuers = false; code comments confirm the live/prod state is false.
SSRF outbound-URL guardOK (gating gap folded into SSO-2162)OutboundUrlGuard + check-outbound-url-guard.sh (SSO-2095) + SecurityBoundaryArchTest exist; the discovery-doc re-validation gap was closed (SSO-2117).SSO-2095 / SSO-2117 (tracked)
Cross-tenant response = 404 not 403OKDocumented privacy invariant; backed by check-no-tenant-in-customer-plane-path (whose gating gap is part of SSO-2162).
Actuator exposureOKHub exposes only health, info, prometheus with show-details: never and gates /actuator/prometheus behind SCOPE_admin; product-api / identity expose health, info, prometheus (mgmt port kept internal, show-details: when-authorized); no env / heapdump / threaddump / shutdown / configprops anywhere.
api-gateway gateway actuator endpointLowUNKNOWNapi-gateway exposes the gateway endpoint (route topology) on the app port with no explicit /actuator matcher found in its security config — confirm it is not reachable from the public internet at runtime.

Part A — dependency detail

Jackson — pinned safe, but the comment is a trap

bom/pom.xml pins jackson.version = 2.22.1 and imports jackson-bom before spring-boot-dependencies so the pin wins for every transitive Jackson 2 artifact. On 2026-06-22 a batch of Jackson vulnerabilities was disclosed, including CVE-2026-54513 (RCE via a BasicPolymorphicTypeValidator allow-list bypass, affecting 2.10.02.18.7, 2.19.02.21.3, 3.0.03.1.3) and CVE-2026-54512 (CVSS 9.2). 2.22.1 is one of the listed fixed versions, so the current pin is safe.

The problem is documentation drift: the jackson.version comment block and the CLAUDE.md "Jackson default-typing" pitfall both still describe the policy as pin to the 2.21.x LTS line, 2.21.3 latest. 2.21.3 is below the 2.21.4 fix line and is therefore vulnerable to the RCE. A maintainer who "corrects" the version to match the stale comment would silently reintroduce a critical RCE. The defence-in-depth check-no-default-typing guard (a required gate) still bans the gadget-enabling API, but the version pin is the real fix and its description must be reconciled — tracked as SSO-2161.

Spring Boot 4.0.6 and Spring Security 7.0.5

Spring Boot 4.0.6 (released 2026-04-23) is one patch above the range CVE-2026-40976 hits (4.0.0 through 4.0.5) — a critical default-web-security authorization bypass — so the platform carries that fix.

Spring Boot 4.0.6 resolves Spring Security 7.0.5. That matters because the hub runs the Spring Authorization Server with Dynamic Client Registration enabled (RFC 7591 / 7592 filter chain), which is the exact precondition for CVE-2026-22752 (CVSS 9.6, malicious client registration leading to stored XSS / privilege escalation / SSRF). CVE-2026-22752 is fixed in 7.0.5, so the hub is covered.

However, Spring Security 7.0.6 (2026-06-09) fixed seven further CVEs — including SAML processing, XSS, open-redirect, and X.509 handling — and 7.0.5 predates that batch. The platform ships saml-member, which consumes spring-security-saml2-service-provider, so the SAML-processing CVE is a live surface. The recommendation is to evaluate bumping to the Spring Boot patch that pulls Spring Security 7.0.6 or later (or overriding the managed version), after triaging which of the seven June CVEs affect used surfaces — tracked as SSO-2160.

Bouncy Castle, Nimbus, and the long tail

Bouncy Castle bcprov-jdk18on 1.85 clears CVE-2025-8885 (ASN.1 DoS, affects ≤ 1.77) and CVE-2026-0636 (LDAP injection, affects 1.74 through 1.83). The bom originally pinned only bcprov, so a live resolve found bcpkix-jdk18on / bcutil-jdk18on still arriving transitively at 1.77 (saml-member: opensaml-security-api 5.1.6cryptacular 1.2.6) — a version skew against the 1.85 provider that also carried CVE-2025-8916 (MODERATE, fixed 1.79) and CVE-2026-5588 (MODERATE, fixed 1.84). SSO-2224 pins bcpkix + bcutil to the same ${bouncycastle.version} = 1.85, so all three -jdk18on artifacts resolve consistently and both advisories clear.

Nimbus JOSE+JWT 10.9.1 carries the historical CVE-2024-21235 algorithm-confusion class, which is structurally mitigated by the required jwt-decoder-algorithm-check — every decoder must pin an ES256 allow-list, so a JWKS advertising a weaker or none algorithm is rejected.

The remaining pins (okhttp 5.4.0, pdfbox 3.0.8, bucket4j 8.10.1, twilio 12.1.1, tink 1.23.0, geoip2 5.2.0, pact 4.7.3 in test scope) showed no known high or critical CVE at the pinned versions on the audit date. They post-date the training cut-off, so this is a knowledge-based clearance and a live osv-scanner / OWASP Dependency-Check run should confirm it.

OpenTelemetry and Logback — the MODERATE/LOW residual (SSO-2239)

The same post-SSO-2224 full-reactor resolve that cleared the Critical/High backlog also surfaced two advisories below that bar. They were deferred from SSO-2224 — each needs a coordinated multi-artifact bump ahead of a Boot-managed BOM — and are remediated under SSO-2239:

  • OpenTelemetry. Spring Boot 4.0.6 manages the whole io.opentelemetry:* family (api / context / sdk-* / exporter-*, 14 artifacts) at 1.55.0, which carries CVE-2026-45292 (MODERATE, GHSA-rcgg-9c38-7xpx): unbounded memory allocation and CPU consumption in W3C baggage propagation, fixed 1.62.0. Pinned by importing io.opentelemetry:opentelemetry-bom 1.62.0 before spring-boot-dependencies — the same first-declared-wins mechanism as netty-bom / protobuf-bom. The separate io.opentelemetry.semconv:* line (1.37.0, a different groupId not managed by that BOM) is outside the advisory and left untouched.
  • Logback. Boot 4.0.6 manages logback-classic / logback-core 1.5.32, carrying CVE-2026-10532 (LOW, fixed 1.5.34) and CVE-2026-9828 (LOW, fixed 1.5.33) — object-injection / deserialization via HardenedObjectInputStream, reachable only when the receiver-side hardened stream is explicitly enabled (not the default). Bumped to 1.5.34. Logback publishes no BOM, and — as the tomcat / postgresql / scram overrides already record — a <logback.version> property alone cannot reach the imported Boot BOM, so both artifacts are pinned via explicit dependencyManagement entries (referencing a logback.version property) before the spring-boot-dependencies import.

A fresh full-reactor mvn dependency:tree confirms io.opentelemetry:* resolves to 1.62.0 and logback-classic / logback-core to 1.5.34, with no other managed version regressed. These are the last of the dependency-CVE residuals the SSO-2224 resolve surfaced; the only remaining flagged finding is the test-scope protobuf-java under SSO-2225.

The scanning gate itself

Three scanners exist but none blocks a PR:

  • OWASP Dependency-Check (security-scan.yml) runs weekly and on push to main with failBuildOnCVSS=11 — so it never fails on a finding — and with no NVD_API_KEY, so the keyless NVD sync is rate-limited and the scan is explicitly advisory.
  • osv-scanner (security-scan-deps.yml) runs weekly and opens a GitHub issue on critical/high findings; it never fails CI. This workflow exists precisely because a public RCE (CVE-2025-55182) reached the team via a researcher email rather than internal detection.
  • SpotBugs / FindSecBugs runs weekly and on push, wrapped so it never fails.

For a platform entering production, a vulnerable dependency can merge and ship, surfacing only at the next weekly run. Adding an NVD_API_KEY, lowering failBuildOnCVSS, and/or running osv-scanner per-PR blocking on critical is the fix — already tracked as SSO-1620 and SSO-742.

Update (2026-07-24, SSO-742). The gate is now wired. OWASP Dependency-Check drops to failBuildOnCVSS=7 (root pom + security-scan.yml) with a suppression file for reviewed exceptions; osv-scanner (security-scan-deps.yml) now fails the job on Critical/High. Both gained a pull_request trigger. Two findings emerged while wiring this:

  1. osv-scanner had been a silent no-op. Its step used osv-scanner v1 syntax (--recursive --skip-git --json) against the pinned v2.3.8 binary, which rejects those flags (flag provided but not defined: -skip-git, exit 127); || true swallowed the error, so every weekly run reported "0 findings" without scanning. Corrected to scan source -r --include-git-root --format json.
  2. The dependency set is not clean once osv-scanner actually runs. It surfaces real Spring-Boot-4.0.6-managed transitive HIGHs the NVD-focused pass above did not cover: io.netty 4.2.12.Final (up to CVSS 8.7; fixed in 4.2.15/16) and Jackson 3 tools.jackson.core:jackson-core 3.1.2 (CVSS 8.7; fixed in 3.1.4). The audit's Jackson row cleared com.fasterxml.jackson 2.x but did not review the tools.jackson (Jackson 3) surface Spring Boot 4 actually ships.

Because a threshold-7 gate trips on that backlog today, both scanners are kept non-required in branch protection (they are not in the 29 required contexts) — they fail visibly on a PR but do not block merge-on-required-green. Remediation of the transitive HIGHs and promotion to required checks is tracked as SSO-2195 (relates SSO-2162).

Part B — posture detail

The required-check gap is the load-bearing posture finding

Architecture and security invariants are enforced by a family of scripts/check-*.sh guards wired into ci.yml (see CI security guards). The GitHub API shows main requires 29 status-check contexts (strict: true, no rulesets). The required set covers the highest-value invariants — the reactive-.block(), JWT-algorithm, custom-error-shape, MDC, raw-cookie, default-typing, host-header, pod-security-context, SA-token, ingress-TLS, and literal-secret guards are all required.

But several security-relevant guards run on every PR (confirmed: no event if: gate) yet are absent from the required set, so a merge on required-green does not block on their failure:

  • outbound-url-guard-check — the SSRF outbound-URL guard coverage (SSO-2095). This is the standout: the SSRF boundary recurred four times (SSO-790 / 791 / 795 / 796) and SSO-2117 only just closed a discovery-doc re-validation gap. A change that drops an OutboundUrlGuard call could merge on green.
  • no-tenant-in-customer-plane-path-check — tenant-isolation, no tenant id in a URL path (SSO-1937). See tenant isolation.
  • audit-internal-k8s-enabled-check — the internal audit endpoint must require Kubernetes ServiceAccount-JWT auth rather than permitAll (SSO-1337).
  • no-noop-secret-in-migration-check — bans a cleartext {noop} client secret in a migration (SSO-741).
  • no-unbounded-varchar-check and encryption-key-secrets-backed-up-check — data-safety and DR.

The compensating control is the pr-merger running scripts/local-ci/pr-check.sh (which runs all guards), but that path is unenforced. Because these jobs already report on every PR, promoting them into required_status_checks will not deadlock open PRs — tracked as SSO-2162.

TLS

SSL-bundle references default via #{null} across the Spring services, so an unset bundle env-var yields a plaintext client rather than a boot-time NoSuchSslBundleException. Ingress TLS annotations are enforced by the required ingress-tls-annotations-check. The one open TLS item is the expired staging hub wildcard certificate, already tracked at High as SSO-2119 — referenced here, not re-filed.

NetworkPolicy

The namespace-wide baseline (network-policy-default-deny.yaml) has two halves behind one kill-switch. The ingress half is enabled in staging (networkPolicy.enabled: true), so default-deny-ingress plus per-destination allows are in force. The egress half is gated separately by networkPolicy.egressEnabled, which is false in staging and false by default in values.yaml; there is no prod values file yet, so a prod deploy that does not set it inherits no namespace-wide egress default-deny. This is the deliberate outcome of SSO-1797, which removed a per-service egress policy that was causing audit-emission failures — so egress default-deny is intentionally deferred, not forgotten. The hub still carries its own per-service egress NetworkPolicy (a CVE-2025-55182 follow-up, enabled in staging) that restricts hub egress and denies the cluster-internal private ranges, which is the SSRF-relevant defence-in-depth layer. The prod-values decision on the namespace-wide egress baseline should be made explicitly at cutover; it belongs under SSO-1481 and references SSO-1797.

Secrets

The operator-set-secret posture (per-service AES key backup and DR set, Vault-at-deploy for prod client secrets) is already captured across SSO-2129 (done), SSO-2101, SSO-2137, and SSO-2139 — referenced here, not duplicated. The historically git-known seed client-secret gap was closed by moving the seed family to {bcrypt} (SSO-741); the residual is that the guard preventing a {noop} regression is not yet a required check, which is folded into SSO-2162.

Actuator

Actuator exposure is tight, not wide-open. The hub exposes only health, info, prometheus, sets show-details: never, and gates /actuator/prometheus behind SCOPE_admin; /actuator/health and /actuator/info are the only permitAll actuator paths. product-api and identity-service expose health, info, prometheus with the management surface kept internal behind the gateway and show-details: when-authorized. No service exposes env, heapdump, threaddump, shutdown, configprops, or beans. The one item to confirm at runtime is that the api-gateway's gateway actuator endpoint (route topology) is not reachable from the public internet — an UNKNOWN that a live probe settles.

Tickets — newly filed vs. already tracked

Newly filed (all linked to the prod-readiness epic SSO-1481):

  • SSO-2160 (Medium) — bump Spring Security past 7.0.5 to pick up the 7.0.6 June-2026 CVE batch; SAML surface is live.
  • SSO-2161 (Low) — reconcile the jackson.version comment drift so no one reverts to the CVE-vulnerable 2.21.3.
  • SSO-2162 (High) — promote the SSRF / tenant-isolation / audit-auth / secret guards into required_status_checks so they actually gate merges.
  • SSO-2195 (High, filed 2026-07-24 via SSO-742) — remediate the Spring-Boot-4-managed transitive HIGHs (netty, Jackson 3) surfaced once osv-scanner actually runs, then promote the now-wired CVE-scan jobs into required_status_checks.

Referenced, not re-filed (already tracked):

  • SSO-2119 — expired staging hub wildcard TLS cert (High).
  • SSO-1797 — the egress-NetworkPolicy relaxation that leaves egress default-deny off.
  • SSO-2101 / SSO-2137 / SSO-2129 / SSO-2139 — operator-set / seed secret posture.
  • SSO-2095 / SSO-2117 — SSRF outbound-URL guard and its discovery-doc fix.
  • SSO-1620 / SSO-742NVD_API_KEY and turning the CVE scan into a real gate.

What still needs a live scan or pentest

  • A live mvn dependency:tree to confirm the resolved Spring Security version and to catch any other transitive drift the managed BOM introduces.
  • A keyed osv-scanner / OWASP Dependency-Check run to confirm the long-tail clearance above and to catch anything disclosed after the audit date.
  • A runtime probe of the deployed cluster: actual ingress TLS, actual CNI NetworkPolicy enforcement, and whether any actuator endpoint (notably the api-gateway gateway endpoint) is reachable from the public internet.
  • A full penetration test of the auth flows — this static pass does not exercise the OAuth, DCR, SAML, or token-revocation paths against a running system.

Source: bom/pom.xml; .github/workflows/ci.yml, security-scan.yml, security-scan-deps.yml; .github/dependabot.yml; deploy/helm/thoryn/templates/network-policy-default-deny.yaml and values*.yaml; servers/authorization-hub/src/main/resources/application.yaml; servers/authorization-hub/.../config/ResourceServerConfig.kt; core/lib/common/.../security/TrustedTenantIssuers.kt; GitHub branch-protection API; public CVE advisories retrieved on the audit date.