Skip to content

fix(security): validate cloud region/project inputs and bind vertex credentials to the executing workspace - #6167

Merged
waleedlatif1 merged 3 commits into
stagingfrom
fix/vertex-location-ssrf-and-credential-binding
Aug 2, 2026
Merged

fix(security): validate cloud region/project inputs and bind vertex credentials to the executing workspace#6167
waleedlatif1 merged 3 commits into
stagingfrom
fix/vertex-location-ssrf-and-credential-binding

Conversation

@waleedlatif1

@waleedlatif1 waleedlatif1 commented Aug 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Validate vertexLocation before it reaches @google/genai. The SDK builds its base URL as `https://${location}-aiplatform.googleapis.com/` — a literal interpolation into the hostname — so attacker.tld/x terminates the authority and the auth client still attaches Authorization: Bearer <workspace GCP token> to the attacker's host. Runtime-confirmed against production via POST /api/guardrails/validate, which needs only a session cookie.
  • Same treatment for the two siblings in the same bug class: vertexProject (interpolated into the URL path) and the Bedrock region (interpolated into the endpoint hostname, now using the pre-existing validateAwsRegion). azureEndpoint was already routed through the DNS-pinning SSRF guard and needed no change.
  • Bind Vertex credential resolution to the executing workspace. resolveVertexCredential enforced only the user↔credential predicate; authorizeCredentialUse also enforces workflow-workspace↔credential. A credential held in workspace B could be pasted into a workflow in workspace A and consumed by A's principals — including on deployed runs, where enforceCredentialAccess is false and ctx.userId is the workflow owner rather than the trigger caller. Service-account credentials mint a cloud-platform-scoped token, so this handed A the use of B's GCP identity.

Details

Chokepoint. Two new validators (validateGoogleCloudLocation, validateGoogleCloudProject) live next to the existing validateAwsRegion in the shared input-validation module and are applied in each provider's executeRequest. There is exactly one vertexai: true construction site in the repo, so every path — agent/router/evaluator/translate blocks, /api/providers, /api/guardrails/validate — goes through them. Nothing containing /, :, @, ?, #, or whitespace can pass.

Credential binding. getCredentialActorContext resolves the workspace from the credential row itself, so it structurally cannot express the workflow-workspace predicate. resolveVertexCredential now takes the executing workspaceId (params object, since the arg list grew) and rejects a mismatch with the same message credential-access.ts uses. All four call sites pass ctx.workspaceId, already in scope at each. Routing through authorizeCredentialUse directly was the other option but it needs a NextRequest the executor does not have.

Regression audit

  • ExecutionContext.workspaceId is optional in the type, so the binding check is conditional — but execution-core.ts:356 throws when execution metadata lacks a workspace, so it is always present on real runs. No bypass by omission.
  • credential.workspaceId is NOT NULL, so there is no personal/unscoped credential the new check could wrongly reject.
  • Custom-block children deliberately run under the source workspace (childWorkspaceId = childWorkflow.workspaceId) with childUserId = loadUserId; the new check follows that boundary rather than fighting it. Regular child workflows already go through assertChildWorkflowInWorkspace.
  • Mixed-case locations like US-Central1 work today (DNS is case-insensitive), so the provider lowercases before validating instead of rejecting input that currently succeeds. Second commit.
  • Neither providers/vertex nor providers/bedrock is imported from any client module, so pulling in the validation module adds nothing to a client bundle. check:client-boundary passes.
  • Legacy domain-scoped project ids (google.com:my-project) would be rejected by the project validator. They cannot be created anymore and none are expected here.

Type of Change

  • Bug fix

Testing

  • providers/vertex/index.test.ts (new) — malicious locations and projects throw and never construct the client; valid values pass through; mixed case normalizes; the us-central1 default still applies.
  • executor/utils/vertex-credential.test.ts (new) — cross-workspace credential rejected before any token is minted; same-workspace still resolves; the user↔credential check still fires.
  • lib/core/security/input-validation.test.ts — table-driven cases for both validators covering every authority-terminating character class.
  • Each fix was reverted and the suites re-run to confirm they go red (7 failures) rather than passing vacuously.
  • tsc -p apps/sim --noEmit clean, bun run lint clean, bun run check:api-validation passes, check:client-boundary passes. The one failing test in a wider run (executor/handlers/pi/cloud-review-tools.test.ts) fails identically on origin/staging and is unrelated.
  • Not live-tested against a real Vertex deployment — verification is unit-level plus source trace.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel

vercel Bot commented Aug 1, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Aug 2, 2026 12:03am

Request Review

@cursor

cursor Bot commented Aug 1, 2026

Copy link
Copy Markdown

PR Summary

High Risk
Changes authentication-adjacent credential resolution and blocks URL injection that could exfiltrate GCP/AWS tokens; scope is security-critical but narrowly gated with tests at provider and resolver boundaries.

Overview
This PR closes credential theft / SSRF-style redirect paths in Vertex AI and Bedrock by validating inputs before SDKs build URLs, and stops cross-workspace Vertex credential reuse during workflow execution.

Vertex and Bedrock providers now reject malicious vertexLocation, vertexProject, and bedrockRegion values (slashes, @, :, hostnames, path injection) via validateGoogleCloudLocation, validateGoogleCloudProject, and extended validateAwsRegion (including eusc-de-east-1). The Vertex provider lowcases location before validation so mixed-case regions still work. Invalid values throw before GoogleGenAI or Bedrock clients are created.

resolveVertexCredential takes an options object and requires the credential’s workspaceId to match the executing workflow’s ctx.workspaceId; agent, evaluator, and router handlers pass that context. Cross-workspace credentials fail before token minting.

New unit tests cover validators, provider chokepoints, and workspace binding.

Reviewed by Cursor Bugbot for commit 270ecbd. Configure here.

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit f266e00. Configure here.

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

Comment thread apps/sim/providers/bedrock/index.ts
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@greptile-apps

greptile-apps Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR hardens cloud-provider execution by validating Vertex and Bedrock endpoint inputs before SDK construction and binding Vertex credentials to the executing workflow workspace.

  • Adds Google Cloud location and project validators and applies them at the Vertex provider boundary.
  • Applies the existing AWS region validator before constructing Bedrock requests.
  • Passes execution workspace identity into Vertex credential resolution and rejects cross-workspace credentials before token minting.
  • Adds regression tests for malicious endpoint inputs, normalization, defaults, credential authorization, and workspace isolation.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains in the eligible follow-up review scope.

Important Files Changed

Filename Overview
apps/sim/executor/utils/vertex-credential.ts Adds executing-workspace ownership enforcement before a Vertex credential can mint or refresh an access token.
apps/sim/lib/core/security/input-validation.ts Adds constrained Google Cloud location and project validators and expands the AWS region validator for European Sovereign Cloud.
apps/sim/providers/vertex/index.ts Normalizes and validates Vertex location and project inputs before constructing the authenticated Google SDK client.
apps/sim/providers/bedrock/index.ts Validates the configured AWS region before deriving the Bedrock endpoint and inference profile.
apps/sim/executor/handlers/agent/agent-handler.ts Supplies the executing workspace when resolving Vertex credentials for agent blocks.
apps/sim/executor/handlers/evaluator/evaluator-handler.ts Supplies the executing workspace when resolving Vertex credentials for evaluator blocks.
apps/sim/executor/handlers/router/router-handler.ts Supplies the executing workspace in both Vertex credential-resolution paths used by router blocks.

Sequence Diagram

sequenceDiagram
  participant Exec as Workflow Executor
  participant Cred as Vertex Credential Resolver
  participant Validate as Cloud Input Validators
  participant SDK as Cloud Provider SDK

  Exec->>Cred: credentialId, userId, workspaceId
  Cred->>Cred: Check user access and workspace ownership
  Cred-->>Exec: Access token
  Exec->>Validate: Project, location, or region
  Validate-->>Exec: Validated input
  Exec->>SDK: Construct authenticated provider client
  SDK-->>Exec: Provider response
Loading

Reviews (2): Last reviewed commit: "fix(security): accept AWS European Sover..." | Re-trigger Greptile

…redentials to the executing workspace

Two credential-exposure bugs on the Vertex AI path.

1. `vertexLocation` reached `new GoogleGenAI({ location })` unvalidated. The
   SDK interpolates that value straight into the API hostname
   (`https://${location}-aiplatform.googleapis.com/`), so a value like
   `attacker.tld/x` terminates the authority component and relocates the
   request — with the workspace's GCP bearer token attached by the auth
   client — to an arbitrary host. Reachable from agent/router/evaluator
   blocks and from `POST /api/guardrails/validate` with only a session
   cookie. `vertexProject` (interpolated into the URL path) and the Bedrock
   region (interpolated into the endpoint hostname) had the same shape of
   problem.

   Adds `validateGoogleCloudLocation` / `validateGoogleCloudProject` to the
   shared input-validation module and applies them, plus the existing
   `validateAwsRegion`, at the provider chokepoints. Every path to the SDK
   goes through `executeRequest`, so no caller can bypass them.
   `azureEndpoint` already routes through the DNS-pinning SSRF guard.

2. `resolveVertexCredential` enforced only the user↔credential predicate and
   never the workflow-workspace↔credential predicate that
   `authorizeCredentialUse` applies on the HTTP path. A credential held in
   workspace B could be pasted into a workflow in workspace A and consumed
   by workspace-A principals with no access to B — including on deployed
   runs, where `enforceCredentialAccess` is false and `ctx.userId` is the
   workflow owner rather than the trigger caller. Service-account
   credentials mint a `cloud-platform`-scoped token, so this handed
   workspace A the use of workspace B's GCP identity.

   The resolver now takes the executing `workspaceId` and rejects a
   credential belonging to a different workspace, mirroring
   `credential-access.ts`. All four executor call sites pass
   `ctx.workspaceId`.
Hostnames are case-insensitive, so a mixed-case location like US-Central1
reaches Google today. Lowercase it before the region check rather than
rejecting an input that currently works.
…eAwsRegion

eusc-de-east-1 is a real Bedrock-enabled region that the existing pattern
did not cover, so applying the validator to bedrockRegion would have
rejected a config that worked before. Adds the eusc-<country> partition.
@waleedlatif1
waleedlatif1 force-pushed the fix/vertex-location-ssrf-and-credential-binding branch from f266e00 to 270ecbd Compare August 2, 2026 00:03
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 270ecbd. Configure here.

@waleedlatif1
waleedlatif1 merged commit be8a93d into staging Aug 2, 2026
27 checks passed
@waleedlatif1
waleedlatif1 deleted the fix/vertex-location-ssrf-and-credential-binding branch August 2, 2026 00:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant