Skip to content

Metrics have no account dimension, so accounts with the same table name share rows, and failed requests record their raw table names #728

Open

Description

@LeeroyHannigan

Problem

The metrics table has no account column on any backend. On SQLite its primary key is (bucket, metric, table_name, index_name, operation) (crates/storage-sqlite/src/schema.rs:317-328); the PostgreSQL table (crates/storage-postgres/migrations/001_schema.sql:235) has the same key, and neither the Cassandra table (crates/storage-cassandra/migrations/catalog/V001__initial_schema.cql:81) nor the MongoDB metrics collection (crates/storage-mongodb/src/management_store.rs) has an account field. The in-memory collector and the flush worker carry no account either, and query_metrics_from_store (crates/server/src/metrics_endpoint.rs) takes none. From the code:

  • Two accounts that each have a table with the same name write to one row, so the counts and latencies the admin sees for that name are the two tables' added together.
  • An IAM user cannot be shown its own account's metrics, which is why fix: serve the console metrics dashboard to admin sessions only #727 makes the console metrics dashboard serve admin sessions only.

The table also records the table name of a request that failed validation. dispatch (crates/engine/src/lib.rs:433) returns the request's sideband metrics whether or not the operation passed validation, and the flush worker writes TableName as it was sent. Measured on SQLite on 31 October 2026: after CreateTable calls that each answered 400, the metrics table held rows whose table_name was x";DROP TABLE tables;--, a followed by U+0000 and b, ééé, and a 256-character string, none of them a table. One account's rejected requests therefore put arbitrary strings, control characters included, into the dimension values every reader of the metrics gets, which after #727 is admins only. The console escapes them when it renders the dashboard.

Expected

  • Each backend's metrics table gains an account column, with a catalog migration for each, and the collector, the flush worker and the store query carry the account from the request.
  • The console dashboard shows an IAM user the metrics of its own account, and an admin either one account or all of them with the account named per row.
  • A request that fails validation adds no row with its TableName, or adds its operation metric without a table name.
  • Tests: two accounts with a table of the same name get separate rows; an IAM user's feed holds only its account's tables; a CreateTable with an invalid name leaves no row with that name.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingsecurity

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions