Skip to content

fix(account): honour the integrationServices list in findFullSocialIdBySocialKey - #11008

Closed
clayrisser wants to merge 1 commit into
hcengineering:developfrom
clayrisser:fix/account-social-key-integration-services
Closed

fix(account): honour the integrationServices list in findFullSocialIdBySocialKey#11008
clayrisser wants to merge 1 commit into
hcengineering:developfrom
clayrisser:fix/account-social-key-integration-services

Conversation

@clayrisser

Copy link
Copy Markdown

Problem

findFullSocialIdBySocialKey (server/account/src/serviceOperations.ts:932-935) gates its callers on a frozen literal instead of the shared integrationServices list:

const { extra } = decodeTokenVerbose(ctx, token)
verifyAllowedServices(['telegram-bot', 'gmail', 'tool', 'workspace', 'google-calendar'], extra)

integrationServices (server/account/src/utils.ts:2024-2035) is:

['github', 'telegram-bot', 'hulygram', 'mailbox', 'caldav', 'gmail', 'google-calendar', 'huly-mail', 'ai-assistant', 'tool']

So the literal omits six names that are already trusted elsewhere in this very file: github, hulygram, mailbox, caldav, huly-mail, ai-assistant.

Those six are trusted by every neighbouring endpoint — getIntegrationSecret (:895), listIntegrationsSecrets (:921), listIntegrations (:726), findExistingIntegration (utils.ts:2049) — all of which gate on integrationServices directly. A service that is allowed to create and read its own integrations, including their secrets, is refused when it tries to resolve a social key.

This needs no configuration to reproduce: it happens on a stock checkout with no environment variables set.

Reproduction

  1. Mint a service token with extra.service = 'github'.
  2. createIntegration — succeeds (gated on integrationServices, which contains github).
  3. findFullSocialIdBySocialKey with the same token — Forbidden.

The practical consequence is that a deployment wanting any of those six services to resolve a social key has to run it under the tool service name instead, which is a far broader identity than the service needs — tool is the admin/migration name that dev/tool and the model migrations use.

Fix

Union the endpoint's own names with integrationServices:

-  verifyAllowedServices(['telegram-bot', 'gmail', 'tool', 'workspace', 'google-calendar'], extra)
+  verifyAllowedServices(
+    ['telegram-bot', 'gmail', 'tool', 'workspace', 'google-calendar', ...integrationServices],
+    extra
+  )

This is the shape findPersonBySocialKey already uses seventy lines below, at :1002:

verifyAllowedServices(['tool', 'workspace', 'aibot', ...integrationServices], extra)

Union rather than replace, deliberately. workspace appears in this endpoint's literal but is not in integrationServices, so replacing the literal outright would revoke access that works today. Spreading keeps every existing caller working and only adds the six that the adjacent endpoints already trust.

Scope and residual risk

  • Nothing is removed. The five names in the literal keep working, workspace included.
  • The six names added are exactly the six already permitted by the sibling calls in the same file, so this widens findFullSocialIdBySocialKey to the set the rest of the integration surface already uses — it does not invent a new trust boundary.
  • No behaviour change for any caller that works today.

Verification

Change is one call. git apply is clean against develop @ 1be6047c8, and the reachability claim above was checked by reading integrationServices and each verifyAllowedServices call site in serviceOperations.ts on that commit.

No tests are added: verifyAllowedServices is a pure allow-list check and the change is to its argument, so a test would restate the list rather than pin behaviour. Happy to add one if you'd like the allow-list itself pinned.

Related, not included

integrationServices is a hardcoded array with a maintainer comment asking // Move to config?. Making it extensible from the environment would let a deployment add its own integration service without patching, and would compose with this change — but that is a configuration-surface decision rather than a bug fix, so I have left it out of this PR. Happy to open it separately if it is wanted.

Provenance

Found while running a first-party integration service against a self-hosted deployment under its own service name, which worked for every integration call and then failed on social-key resolution.

…ialKey

getIntegrationSecret, listIntegrationsSecrets and findExistingIntegration
all gate on the shared `integrationServices` list.
findFullSocialIdBySocialKey instead repeats a frozen literal
['telegram-bot', 'gmail', 'tool', 'workspace', 'google-calendar'], which
omits six of the shared list's names (github, hulygram, mailbox, caldav,
huly-mail, ai-assistant). A service that may create and read its own
integrations is therefore still refused when it resolves a social key,
forcing deployments to run it under the 'tool' service name, which is far
broader.

Union the endpoint's own names with `integrationServices` — the shape
findPersonBySocialKey already uses a few lines below. Union rather than
replace: 'workspace' is in the literal but not in `integrationServices`,
so replacing would revoke it.

Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Clay Risser <clayrisser@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@clayrisser
clayrisser force-pushed the fix/account-social-key-integration-services branch from 6cf9120 to 7cc6ead Compare August 13, 2026 06:47
@clayrisser

Copy link
Copy Markdown
Author

Closing — this was opened by an automated agent without my intent. Apologies for the noise.

@clayrisser clayrisser closed this Aug 14, 2026
@clayrisser
clayrisser deleted the fix/account-social-key-integration-services branch August 14, 2026 20:43
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