Skip to content

sec(api): analytics queries with a scoped user's raw external id are provider-unconstrained and can return another provider's unregistered rows #624

Closed

Description

@cristim

Found in the review of PR #622 (#520 slice). Analytics (handler_analytics.go, validateAnalyticsAccountScope and the history/breakdown/trends queries) calls QueryHistory, QueryBreakdown and the trends queries directly with a provider-unconstrained filter {"": {externalID}} (postgres_analytics.go ~70-72: account_id = ANY, no provider). For a scoped user whose unique registered raw external id is requested, the query can therefore also return rows of ANOTHER provider's UNREGISTERED account that shares the same external id (e.g. an AWS 12-digit account id and a GCP project number). Registered accounts cannot collide (uniqueness is enforced). Dashboard, inventory and history are not exposed: intersectAccountFilterScope / intersectDualColumnScope re-group the empty-provider bucket under the allowed provider.

Acceptance: for a scoped session with a unique raw id, resolve the filter to {match.Provider: {id}} (or intersect the filter as the other paths do); handle legacy rows with an empty provider deliberately (document the decision); regression test through HandleRequest with an unregistered other-provider row sharing the id (rows must not be returned), plus unchanged behavior for UUID requests and unrestricted users. Related: #520, #622, #593, #433 (name matching, out of scope).

Activity

  1. IAmJSD commented on Oct 19, 2026

    @IAmJSD
    Collaborator

    Claiming: working on this

  2. self-assigned this
    on Oct 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions