Fix GCP Service Agent Token Theft vulnerability in connection testing - #1623
Fix GCP Service Agent Token Theft vulnerability in connection testing#1623akkaur wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Code Review
This pull request updates GCPUtils.loadServiceAccountCredentials to load credentials using ServiceAccountCredentials.fromStream instead of GoogleCredentials.fromStream and adds corresponding unit tests. The feedback suggests enhancing the positive test case by asserting that the returned credentials are an instance of ServiceAccountCredentials to ensure the security fix is explicitly verified.
04bc968 to
354a90a
Compare
|
/gemini review |
1 similar comment
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request updates the loadServiceAccountCredentials method in GCPUtils to return ServiceAccountCredentials instead of GoogleCredentials, preventing the loading of non-service-account credentials. A new test class GCPUtilsTest has been added to validate this behavior with both positive and negative test cases. I have no feedback to provide.
|
The changes in this pull request correctly address the identified security vulnerability by restricting credential parsing to |
There was a problem hiding this comment.
Code Review
This pull request updates GCPUtils to load credentials specifically as ServiceAccountCredentials instead of the generic GoogleCredentials to mitigate potential external account payload attacks, and introduces unit tests to verify this behavior. The review feedback suggests programmatically generating a dummy RSA keypair at runtime in the test instead of hardcoding a static private key string, which prevents triggering automated credential scanners in CI/CD pipelines.
… and plugin validation Modified GCPUtils.loadServiceAccountCredentials to use ServiceAccountCredentials.fromStream() instead of GoogleCredentials.fromStream(). Previously, GoogleCredentials.fromStream() would implicitly parse various credential types. This allowed a malicious user to supply an external_account payload with a crafted credential_source (pointing to the GCP metadata server) and an external token_url, triggering an unintended Workload Identity Federation exchange and exfiltrating the Data Fusion Service Agent's token. By explicitly restricting the parser to ServiceAccountCredentials, external and non-service-account configurations now instantly throw an IOException prior to any external token fetches and effectively blocks the Privilege Escalation attack. Also added GCPUtilsTest.java to explicitly test that only service_account credential types can be loaded, securing regression coverage against external account injections. Fixes: b/501546932, b/501543027
354a90a to
e1c02fe
Compare
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request updates GCPUtils.loadServiceAccountCredentials to load credentials using ServiceAccountCredentials.fromStream instead of the generic GoogleCredentials.fromStream to prevent loading arbitrary external account credentials. Additionally, a new test class GCPUtilsTest has been added to verify both positive and negative scenarios for loading service account credentials. No review comments were provided, so there is no feedback to address.
| throws IOException { | ||
| try (InputStream inputStream = openServiceAccount(serviceAccount, isServiceAccountFilePath)) { | ||
| return GoogleCredentials.fromStream(inputStream); | ||
| return ServiceAccountCredentials.fromStream(inputStream); |
There was a problem hiding this comment.
Changing from GoogleCredentials.fromStream() to ServiceAccountCredentials.fromStream() restricts your application to accepting only traditional, long-lived service account key JSON files.
The primary impacts across your application include:
- Breaks Workload Identity Federation (
external_account): Workloads authenticating from AWS, Azure, GitHub Actions, or on-premises environments via keyless federation will crash with anIOExceptionorIllegalArgumentExceptionbecause anexternal_accountJSON cannot be parsed byServiceAccountCredentials. - Breaks Local Developer Workflows (
authorized_user): Developers using credential files generated bygcloud auth application-default loginor user OAuth flows will no longer be able to supply those files to your code. - Blocks Impersonated Account Files (
impersonated_service_account): Configuration files designed to dynamically impersonate a service account without possessing its private key will fail to load. - Enforces Security Anti-Patterns: It forces consumers of your application or plugin to create, download, store, and rotate static service account private keys (
"type": "service_account"), increasing the risk of leaked credentials. - API Incompatibility / Code Changes: Any calling code expecting the base
GoogleCredentialstype may need adjustments if it relies on polymorphic credential handling, thoughServiceAccountCredentialsis assignable toGoogleCredentials. - Gains Direct Access to Service Account Methods: On the positive side, you gain compile-time access to service account-specific methods on the returned object without casting—such as
.createDelegated(userEmail)for Google Workspace Domain-Wide Delegation,.getClientEmail(), and.getPrivateKey().
Would it be fine?
There was a problem hiding this comment.
To remediate you may consider implementing stricter input validation for Google Cloud connector configurations.
Example:
- Implement Stricter Input Validation: Add validation checks in the backend handlers (such as
ConnectionHandler.javain CDAP and individual plugin connectors likeGCSConnector.java) for theserviceAccountJSONpayload. - Restrict Credential Type Properties: Do not allow the
credential_sourceURL to point to the local metadata server (http://metadata.google.internal/computeMetadata/v1/...) or internal loopback IP addresses when testing connections with external accounts. - Validate Token URLs: Allowlist or validate the
token_urldomain to ensure it points to legitimate identity providers, rather than arbitrary attacker-controlled destinations. - Audit All Google Connectors: Ensure the validation applies systemically across all Google Cloud connectors (BigQuery, GCS, Spanner, Bigtable, Pub/Sub, etc.) as the vulnerability may be present in multiple plugin configurations.
Modifies GCPUtils.loadServiceAccountCredentials to use ServiceAccountCredentials.fromStream() instead of GoogleCredentials.fromStream(). Previously, GoogleCredentials.fromStream() would implicitly parse various credential types. This allowed a malicious user to supply an external_account payload with a crafted credential_source (pointing to the GCP metadata server) and an external token_url, triggering an unintended Workload Identity Federation exchange and exfiltrating the Data Fusion Service Agent's token. By explicitly restricting the parser to ServiceAccountCredentials, external and non-service-account configurations now instantly throw an IOException prior to any external token fetches and effectively blocks the Privilege Escalation attack.
Also adds GCPUtilsTest.java to explicitly test that only service_account credential types can be loaded, securing regression coverage against external account injections.