fix(data-connections): stop listing other accounts' connections on product create - #480
Draft
alukach wants to merge 3 commits into
Draft
fix(data-connections): stop listing other accounts' connections on product create#480alukach wants to merge 3 commits into
alukach wants to merge 3 commits into
Conversation
…oduct create listUsableDataConnections filtered only on UseDataConnection and GetDataConnection, neither of which looks at `owner`. Every account-owned connection in the table therefore reached /products/new and was serialized into the page — bucket names, regions and prefix templates included — for any logged-in user. ProductCreationForm's `!dc.owner || dc.owner === forAccountId` filter runs in the browser, so it only ever hid them from view. Take the accounts the user may create products under and apply the same rule server-side, in the helper rather than at the call site so a future caller can't reintroduce the leak. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
|
Claude finished @alukach's task in 2m 39s —— View job Review of PR #480
✅ No blocking issues — safe to merge.
No correctness, security, or best-practice issues found in the diff itself. |
potentialOwnerAccounts took every membership in state Member, regardless of role or scope. A read-data member, or someone whose membership covers a single product, was offered that account as a product owner — an option createProduct rejects — and, because this list now also scopes which owned data connections are serialized into the page, it handed them that account's bucket names and prefixes. That is the enumeration #462 set out to prevent. Restrict it to account-wide owners and maintainers, which is what createRepository actually requires. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Found while investigating why a BYOB connection wasn't appearing on
/products/new. Not the cause of that — a separate leak on the same path, which #462 did not touch.The problem
listUsableDataConnectionsfilters only onUseDataConnectionandGetDataConnection. Neither looks atowner—getDataConnectionreturnstruefor any non-disabled principal, anduseDataConnectionchecksread_onlyandrequired_flagand nothing else.So
/products/newserialized every account-owned connection in the table into the page for any logged-in user: bucket names, regions, base prefixes and prefix templates.authenticationis stripped, but the rest is not.ProductCreationFormdoes filter on!dc.owner || dc.owner === forAccountId(ProductCreationForm.tsx:90-92) — in the browser. It only ever hid them from view.Demonstrated before fixing: a plain
regular-usersession receivedrival--secretwithbucket: "rival-private-bucket-name".The fix
listUsableDataConnections(session, ownerAccountIds)applies the owner rule server-side. The page passespotentialOwnerAccounts, which it already computes for the owner dropdown, so the set is exactly the accounts the user may create products under.The filter goes in the helper rather than at the call site so a second caller can't reintroduce the leak — the required parameter makes it unskippable.
No behaviour change for legitimate use: system-level (unowned) connections are still offered to everyone, and an account's own connections are still offered to its members.
Scope: this does not close the exposure
GET /api/v1/data-connectionsreturns every connection to any caller, including anonymous ones —getDataConnectionisprincipal?.account?.disabled ? false : true, and for a null principal that expression is falsy, so it returnstrue.sanitizeDataConnectionstrips only secret-bearing auth;details(bucket, region, base prefix) and federated role ARNs are returned deliberately, per that helper's doc comment.So account-owned bucket names remain publicly listable through the API regardless of this PR. This change is still worth making — a page shouldn't ship data its own UI then hides — but it should not be read as closing the hole.
Whether the v1 listing should scope account-owned connections to their owners is a policy question worth deciding separately. The ARN exposure looks intentional (the customer's IAM trust policy is the security boundary); the account-owned bucket names look like a consequence of that decision rather than an intended part of it.
Tests
npx jest: 482 passing. The 5 failures (DropdownSection.integration, 4 analytics card tests) reproduce identically on cleanorigin/main— verified by running those suites detached atorigin/main.tscreports no new errors; the pre-existingAdminBreakdownChartimplicit-any errors are also onmain.Two new tests in
data-connections.test.ts, over the realisAuthorized:🤖 Generated with Claude Code