Summary
ModelView.sort_query() uses the attacker-controlled sortBy list-view query parameter without checking it against the configured column_sortable_list allow-list. The value is resolved with getattr(model, ...) and fed into relationship joins and order_by(), so a request can sort by any column of the model — including ones hidden from column_list — and, via a dotted path, by columns of related models. Because row order then reflects the value of an unexposed column, this is an information-exposure ordering oracle.
Root cause
column_sortable_list is consulted only in the list template to decide which header links to render; the server never enforces it, so removing a column from the UI does not prevent sorting by it.
Exploitation
A single request leaks the relative ordering of an unexposed column; the asc↔desc reversal confirms rows are ordered by the secret's actual value. Pairing sortBy with searchable/filterable columns and pagination can narrow the oracle toward specific values, though value recovery is conditional on having a filterable target column.
References
Summary
ModelView.sort_query()uses the attacker-controlledsortBylist-view query parameter without checking it against the configuredcolumn_sortable_listallow-list. The value is resolved withgetattr(model, ...)and fed into relationship joins andorder_by(), so a request can sort by any column of the model — including ones hidden fromcolumn_list— and, via a dotted path, by columns of related models. Because row order then reflects the value of an unexposed column, this is an information-exposure ordering oracle.Root cause
column_sortable_listis consulted only in the list template to decide which header links to render; the server never enforces it, so removing a column from the UI does not prevent sorting by it.Exploitation
A single request leaks the relative ordering of an unexposed column; the
asc↔descreversal confirms rows are ordered by the secret's actual value. PairingsortBywith searchable/filterable columns and pagination can narrow the oracle toward specific values, though value recovery is conditional on having a filterable target column.References