fix(security): SSRF fixes#4548
Conversation
- Azure TTS SSRF: validate region against /^[a-z][a-z0-9-]{1,30}[a-z0-9]$/
in both the contract (tts.ts) and runtime guard in synthesizeWithAzure,
preventing user-supplied region from redirecting requests to arbitrary hosts
- HubSpot token in logs: remove fullResponse from logger.info call;
log only non-sensitive metadata (hub_id, hub_domain, user_id) instead
of the full introspection response which included the access token
- Wealthbox account takeover: replace hardcoded email with per-user identity
by fetching /v1/users/me; fall back to token-derived stable identifier
so distinct Wealthbox users no longer share the same email address
- Shopify SSRF: apply shopifyShopDomainSchema (.myshopify.com allowlist)
to shopDomain from cookie before using it to build the fetch URL
… identity - Bug 1: Change API endpoint from /v1/users/me to /v1/me (correct Wealthbox API path) - Bug 2: Replace ACCESS_TOKEN header with Authorization: Bearer <token> (standard OAuth 2.0) - Bug 3: Remove generateId() from returned id (was non-deterministic, caused duplicate accounts); use refresh token (stable, long-lived) instead of access token (rotates every ~2 hours) as the hash source for the fallback identity; return null if no token is available
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview Specifically, the Shopify OAuth store route now enforces OAuth provider hardening includes updating Wealthbox Reviewed by Cursor Bugbot for commit c90c3f2. Configure here. |
Greptile SummaryThis PR applies targeted SSRF and credential-exposure fixes across four areas: Azure TTS region validation, Shopify OAuth shop domain enforcement, HubSpot introspection log sanitization, and a full Wealthbox OAuth rewrite with the correct endpoint, auth header, and SHA-256-derived stable identity.
Confidence Score: 4/5The four targeted security fixes are sound and well-structured; an SSML injection issue in the Azure TTS route (flagged in a prior review) remains open. All four fixes close real attack vectors cleanly — the Shopify domain allowlist, the Azure region allowlist with defense-in-depth, the HubSpot log sanitization, and the Wealthbox identity rewrite are each correct and self-consistent. The remaining concern is that voiceId, style, rate, pitch, and text are still interpolated verbatim into the SSML template without XML escaping in the TTS route, a finding carried forward from a prior review that this PR does not address. apps/sim/app/api/tools/tts/unified/route.ts — SSML string construction still embeds user-supplied fields without XML escaping. Important Files Changed
Sequence DiagramsequenceDiagram
participant Client
participant ShopifyRoute as Shopify Store Route
participant AzureTTS as Azure TTS Route
participant WealthboxOAuth as Wealthbox OAuth
participant ExternalAPI as External API
Note over ShopifyRoute: SSRF Fix
Client->>ShopifyRoute: GET shopify/store
ShopifyRoute->>ShopifyRoute: validate cookie schema
ShopifyRoute->>ShopifyRoute: shopifyShopDomainSchema check
alt Domain invalid
ShopifyRoute-->>Client: "redirect error=shopify_invalid_domain"
else Domain valid
ShopifyRoute->>ExternalAPI: fetch shopDomain admin API
ExternalAPI-->>ShopifyRoute: shop data
ShopifyRoute-->>Client: redirect shopify_connected
end
Note over AzureTTS: SSRF Fix with defense-in-depth
Client->>AzureTTS: POST tts/unified
AzureTTS->>AzureTTS: Zod region regex check
AzureTTS->>AzureTTS: Runtime AZURE_REGION_RE check
alt Region invalid
AzureTTS-->>Client: 400 Invalid Azure region
else Region valid
AzureTTS->>ExternalAPI: fetch region.tts.speech.microsoft.com
ExternalAPI-->>AzureTTS: audio buffer
AzureTTS-->>Client: audio response
end
Note over WealthboxOAuth: Auth + Identity Fix
Client->>WealthboxOAuth: OAuth callback
WealthboxOAuth->>ExternalAPI: GET api.crmworkspace.com/v1/me
alt API returns user id
ExternalAPI-->>WealthboxOAuth: user data
WealthboxOAuth-->>Client: identity from API
else API fails
WealthboxOAuth->>WealthboxOAuth: SHA256 refresh token slice
WealthboxOAuth-->>Client: stable fallback identity
end
Reviews (3): Last reviewed commit: "fix(auth): replace stale wealthbox userI..." | Re-trigger Greptile |
…d userId - Replace base64 encoding with SHA-256 hash for fallback token-derived identity so raw token bytes are never stored in the DB - Return null early when Wealthbox API response lacks an id field to prevent all such users colliding on the wealthbox-undefined account
|
@greptile |
|
@cursor review |
There was a problem hiding this comment.
✅ 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 b2e9f57. Configure here.
…l endpoint The dummy URL comment was rendered obsolete when getUserInfo was updated to fetch from api.crmworkspace.com/v1/me. Align userInfoUrl with the real endpoint used in the getUserInfo implementation.
|
@cursor review |
|
@greptile |
There was a problem hiding this comment.
✅ 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 c90c3f2. Configure here.
…ch codebase pattern
All other providers use `${stableId}-${generateId()}` so the account.create.after
hook can strip the UUID suffix, find stale sibling rows, and migrate credential FKs.
Without the suffix the migration logic is skipped and reconnections would hit
duplicate key conflicts instead of gracefully updating credentials.
Summary
Type of Change
Testing
Tested manually. Azure region regex validated against all 33 live Azure Speech Service regions — all pass. Shopify schema validated against Shopify's documented domain format. Wealthbox endpoint and auth header confirmed against dev.wealthbox.com API docs.
Checklist