Automated Threat Modeling

Spring Cloud Config CVE-2026-40981: Brief Summary of Cross Project Secret Exposure via GCP Secret Manager Backend

A brief summary of CVE-2026-40981, a high-severity authorization bypass in Spring Cloud Config's Google Secret Manager backend that lets unauthenticated clients retrieve secrets from unintended GCP projects. Includes patch analysis and affected version details.

CVE Analysis

8 min read

ZeroPath CVE Analysis
ZeroPath CVE Analysis

2026-05-06

Spring Cloud Config CVE-2026-40981: Brief Summary of Cross Project Secret Exposure via GCP Secret Manager Backend
Experimental AI-Generated Content

This CVE analysis is an experimental publication that is completely AI-generated. The content may contain errors or inaccuracies and is subject to change as more information becomes available. We are continuously refining our process.

If you have feedback, questions, or notice any errors, please reach out to us.

[email protected]

Introduction

A crafted HTTP request to a Spring Cloud Config Server backed by Google Secrets Manager can silently return secrets from GCP projects the caller was never meant to access. For any organization that relies on Spring Cloud Config to distribute application secrets across microservices, CVE-2026-40981 is a direct path from an unauthenticated network position to credentials stored in arbitrary GCP projects. The only limit is how broad the Config Server's own service account permissions are.

Spring Cloud Config is a central component in the Spring ecosystem for externalized configuration management. It is widely deployed in Java enterprise environments and cloud-native architectures, where it serves configuration properties, including secrets, to distributed applications at scale.

Technical Information

Root Cause: Unvalidated Client-Controlled Project ID

The vulnerability is in the GoogleSecretManagerV1AccessStrategy class, which retrieves secrets from GCP Secret Manager on behalf of Config Server clients. Before the fix, when a Config Client sent an X-Project-ID HTTP header to the Config Server, the getProjectId() method accepted the header value without any validation or authorization check:

// OLD (vulnerable) — blindly accepted header result = configProvider.getValue(HttpHeaderGoogleConfigProvider.PROJECT_ID_HEADER, true);

This is a textbook instance of CWE-639: Authorization Bypass Through User Controlled Key. Nothing in the authorization path stopped one client from reaching another project's secrets by simply changing the key value (the project ID) in the request, and nothing verified whether the requesting client was entitled to that project's secrets.

CVSS Breakdown

The CVSS v3.1 vector is AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N, which scores 7.5 (High):

  • Attack Vector: Network and Privileges Required: None mean any unauthenticated network client can attempt exploitation.
  • Attack Complexity: Low means no special conditions or race windows are needed.
  • Confidentiality Impact: High reflects the direct exposure of sensitive secrets.
  • Integrity and Availability: None, since the flaw is read only.

Attack Flow

An attacker exploiting this vulnerability would follow these steps:

  1. Identify a Spring Cloud Config Server instance that uses Google Secrets Manager as its backend. An attacker can sometimes infer this from error messages, response patterns, or knowledge of the target's infrastructure.
  2. Send the Config Server an HTTP request with an X-Project-ID header set to the ID of a different GCP project. The attacker needs to know or guess valid GCP project IDs, but these are often predictable (e.g., company-production, company-staging).
  3. If the Config Server's service account has IAM permissions on the targeted GCP project (common in organizations that share service accounts or grant broad cross-project access), the server retrieves and returns secrets from that unintended project.
  4. The attacker receives secrets they were never authorized to access, potentially including database credentials, API keys, encryption keys, and other sensitive configuration data.

The blast radius is bounded by the IAM permissions of the Config Server's service account. In organizations with permissive cross-project IAM policies, a single Config Server could expose secrets across dozens of GCP projects.

Patch Information

The Spring team fixed CVE-2026-40981 in commit 4e93ce5, authored by Ryan Baxter on April 21, 2026, and merged into both the v5.0.3 and v4.3.3 releases on May 6, 2026. The commit is titled "Add allowed-project-ids property" and makes 391 additions and 35 deletions across seven files.

What the Patch Changes

The fix introduces a new class, GcpProjectResolutionSupport, which encapsulates and secures all project ID resolution logic. It replaces the old inline resolution code in GoogleSecretManagerV1AccessStrategy.

Resolution now follows a strict waterfall:

  1. X-Project-ID header: If the client supplies this header and token-mandatory is true (the new default), the server accepts the value, because the downstream checkRemotePermissions() IAM check still gates access. If token-mandatory is false, the server checks the header value against a new allowed-project-ids allow list. If that list is empty, every client-supplied project ID is rejected.
  2. GCE Metadata endpoint: If no header is present, the server queries the metadata server. The allow list does not apply here, since the client cannot steer this path.
  3. project-id property fallback: A new config property that only the server admin sets is the last resort (e.g., for local development). The allow list does not apply to it either.
  4. If nothing resolves: getSecrets() returns an empty list and checkRemotePermissions() returns false, so the request gets no property sources backed by Secret Manager.

The main code change in GoogleSecretManagerV1AccessStrategy:

// NEW (fixed) — delegates to allow-list-aware resolver if (projectResolutionSupport != null) { String project = projectResolutionSupport.resolve(configProvider, rest); if (project != null) { return project; } } return null; // no GSM data for this request

This is how GcpProjectResolutionSupport.resolve() enforces the allow list when token-mandatory=false:

private boolean isProjectAllowed(String projectId) { List<String> allowed = properties.getAllowedProjectIds(); if (allowed == null || allowed.isEmpty()) { return false; // empty list = reject all client-supplied IDs } for (String candidate : allowed) { if (candidate != null && projectId.equals(candidate.trim())) { return true; } } return false; }

New Configuration Properties

The patch adds two properties to GoogleSecretManagerEnvironmentProperties:

  • allowed-project-ids (List<String>, default empty): The explicit allow list for client-supplied X-Project-ID values when token-mandatory=false.
  • project-id (String): A server-side fallback project for when the metadata server is unreachable.

The old constructors of GoogleSecretManagerV1AccessStrategy that did not accept GcpProjectResolutionSupport are now marked @Deprecated(forRemoval = true), and the factory class GoogleSecretManagerAccessStrategyFactory now injects GcpProjectResolutionSupport into every strategy it creates.

The commit includes unit tests in GcpProjectResolutionSupportTests covering five scenarios: header denied when the allow list is empty, header allowed when in the list, header allowed when token-mandatory=true regardless of list, metadata fallback, configured project-id fallback, and null when no resolution is possible.

Immediate Containment

If you cannot upgrade immediately, set the following property to require client token verification, which blocks unauthorized cross-project access:

spring.cloud.config.server.gcp-secret-manager.token-mandatory=true

Fixed Releases (Published May 6, 2026)

BranchFixed VersionAvailability
5.0.x5.0.3OSS
4.3.x4.3.3OSS
4.2.x4.2.7Enterprise Support Only
4.1.x4.1.10Enterprise Support Only
3.1.x3.1.14Enterprise Support Only

Older unsupported versions are also affected. Organizations on older branches must either buy enterprise support or migrate to a supported open-source branch.

Affected Systems and Versions

This vulnerability affects Spring Cloud Config Server instances that use Google Secrets Manager as a backend. These version ranges are confirmed affected:

  • Spring Cloud Config 3.1.x: versions 3.1.0 through 3.1.13 (inclusive)
  • Spring Cloud Config 4.1.x: versions 4.1.0 through 4.1.9 (inclusive)
  • Spring Cloud Config 4.2.x: versions 4.2.0 through 4.2.6 (inclusive)
  • Spring Cloud Config 4.3.x: versions 4.3.0 through 4.3.2 (inclusive)
  • Spring Cloud Config 5.0.x: versions 5.0.0 through 5.0.2 (inclusive)

The vulnerable configuration requires:

  • Spring Cloud Config Server deployed with Google Secrets Manager as the configuration backend
  • The Config Server's GCP service account having IAM access to more than one GCP project
  • Network access to the Config Server endpoint

Older, unsupported versions of Spring Cloud Config are also affected but will not receive patches.

References

Detect & fix
what others miss

Works with
  • GitHub
  • GitLab
  • Bitbucket
  • Azure DevOps Services
  • Gerrit
  • CVS
  • Jira
  • Linear
  • Slack
  • Security Compass
Explore integrations
Security magnifying glass visualization