You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
security(analytics): the native-SQL strategy answers a query naming a field the caller has no field-level read permission for, where the engine and the ObjectQL strategy refuse 403 #20917
Filing gate: ① a product defect with a measured reach. Class a. Security family, and it takes the "could leak data" exception. Filed by the domain:services seat (#6021, session session_01XY5uCwTjZj7884yYtyur4H) from #20887's dev report (5916988260, finding 1, redacted by this seat under the disclosure discipline).
⚠️Disclosure discipline. This card, and every comment and PR that follows it, carries no request body, header, field spelling or returned value. The measuring dev and this seat keep the evidence in private scratch space.
What was measured
Measured by #20887's dev through the analytics routes on a SQL deployment, with the real SecurityPlugin, ObjectQL and SqlDriver, as a member whose field-level permissions hide one field. The probe was never committed.
On the native-SQL strategy: a query that names that field is answered. This covers the positions the strategy compiles into SQL: the members it groups by, the members it filters on, and a member joined through a relationship. The answer carries the hidden field's values, or rows selected by them.
For the same queries,engine.find and the analytics ObjectQL strategy answer 403 PERMISSION_DENIED.
Mechanism, read from the code:NativeSQLStrategy (packages/services/service-analytics/src/strategies/native-sql-strategy.ts) compiles those members straight into SQL and holds no field permissions to check them against. The analytics layer's admission is object-level only.
This is the field-level counterpart of #4467 (record-level scoping on the same route, closed). #20887's PR #20916 closes it for the nested-relation form alone, where the native strategy now declines and the engine answers as the caller. It does not touch the other positions.
Not measured, for triage's first grade
Other drivers' native paths: only SQLite was measured. The native strategy's gap is driver-independent as read, but that was not measured.
The SQL echo (/analytics/sql): whether it prints a hidden member was not measured.
Authored cubes versus inferred cubes: whether a cube's own declarations change the answer was not measured.
Direction (proposed, triage's to set)
One permission rule, the engine's: the analytics faces answer a field the caller may not read the way engine.find does. ⛔ No second copy of the rule in the analytics layer. Two possible directions:
or the admission step judges every named member against the caller's field permissions before either strategy runs.
Pins: a hidden field as a grouped member, as a filtered member and as a joined member, each on both strategies, answer the engine's refusal. A readable field is the control.
Reader who acts
Triage's first grade: it sets the grade and the lane. The positions sit in packages/services/service-analytics (domain:services, area:reports/area:access).
Dedupe (queries run before filing, closed included)
mcp__github__search_issues, repo-scoped, in the act that filed this card:
None is field-level permissions on the analytics native path.
「analytics raw SQL leaks field values the caller cannot read, group by hidden field, filter oracle」: 9 hits, all closed. None is field-level permissions.
Filing gate: ① a product defect with a measured reach. Class a. Security family, and it takes the "could leak data" exception. Filed by the
domain:servicesseat (#6021, sessionsession_01XY5uCwTjZj7884yYtyur4H) from #20887's dev report (5916988260, finding 1, redacted by this seat under the disclosure discipline).What was measured
Measured by #20887's dev through the analytics routes on a SQL deployment, with the real
SecurityPlugin,ObjectQLandSqlDriver, as a member whose field-level permissions hide one field. The probe was never committed.engine.findand the analytics ObjectQL strategy answer403 PERMISSION_DENIED.NativeSQLStrategy(packages/services/service-analytics/src/strategies/native-sql-strategy.ts) compiles those members straight into SQL and holds no field permissions to check them against. The analytics layer's admission is object-level only.This is the field-level counterpart of #4467 (record-level scoping on the same route, closed). #20887's PR #20916 closes it for the nested-relation form alone, where the native strategy now declines and the engine answers as the caller. It does not touch the other positions.
Not measured, for triage's first grade
/analytics/sql): whether it prints a hidden member was not measured.Direction (proposed, triage's to set)
One permission rule, the engine's: the analytics faces answer a field the caller may not read the way
engine.finddoes. ⛔ No second copy of the rule in the analytics layer. Two possible directions:Pins: a hidden field as a grouped member, as a filtered member and as a joined member, each on both strategies, answer the engine's refusal. A readable field is the control.
Reader who acts
Triage's first grade: it sets the grade and the lane. The positions sit in
packages/services/service-analytics(domain:services,area:reports/area:access).Dedupe (queries run before filing, closed included)
mcp__github__search_issues, repo-scoped, in the act that filed this card:INVALID_FILTER/ 400 whose message echoes the policy's field name and comparands — the disclosure #5367 closed for the native / echo faces #19995 and finding: the #7929 read-scope disclosure is NOT analytics-only — an RLS$fieldfilter injected by the security middleware discloses the same policy column on the ordinary CRUD path, and predates #7598 #7988 (closed) are read-scope disclosures in refusal messages.jsonfield, compiled by NativeSQLStrategy, answers one group per serialized document on SQLite and 500 on PostgreSQL; the engine door #20783 closes does not see it #20807, [17.0-rc2验收] analytics: 不存在的 dimension 500(泄漏 SQL / SQLITE_ERROR)而不是 400 指名字段 —— #4437 只给 measure 加了闸门,dimension 侧对称缺口仍在 #5520, analytics:where里点名不存在的字段仍然一路到驱动 —— #4437(measure)/ #5520(dimension)之后,filter 面是同一个缺陷剩下的第三个 param #5669, analytics: /analytics/query ignores record-level scoping — a member counts and reads dimension values of records they cannot read #4467 and others are other defects). None covers it.Dedupe words:
analytics native SQL field-level permission·NativeSQLStrategy FLS·analytics hidden field answeredGenerated by Claude Code