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
{{ message }}
Repository navigation
security(plugin-security): the engine's field guard does not judge a cross-field comparand that names a field the caller may not read, so a comparison against a hidden field is served instead of refused 403 #20932
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 #20917's dev report (5919006124, out_of_scope_findings[1]). ⛔ Filed bare: grading and routing are triage's. ⛔ Not a claim.
⚠️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 keeps the evidence in private scratch space.
What was measured
Measured by #20917's dev through engine.find (the data API's read) with the real SecurityPlugin, as a member whose field-level permissions hide one field. The measurement is private.
A filter whose comparand is a cross-field reference ($field) to the hidden field is served, while the same hidden field as a plain filter member is refused 403 PERMISSION_DENIED. That makes the hidden field's values a comparison oracle.
Mechanism, as the dev read it:plugin-security's predicate guard collects the fields a condition names (collectConditionFields) from its keys, and does not collect a field named inside a $field comparand.
Direction (proposed, triage's to set)
The predicate guard judges a field a $field comparand names exactly as it judges a condition key: one collection, one rule. ⛔ No second guard.
Pins: a hidden field as a $field comparand on engine.find and on the aggregate path answers the same 403 as the hidden field as a key. A readable comparand is the control.
Reader who acts
Triage's first grade. The position is in packages/plugins/plugin-security (domain:services by the lane table).
Dedupe (queries run before filing, closed included)
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 #20917's dev report (5919006124,out_of_scope_findings[1]). ⛔ Filed bare: grading and routing are triage's. ⛔ Not a claim.What was measured
Measured by #20917's dev through
engine.find(the data API's read) with the realSecurityPlugin, as a member whose field-level permissions hide one field. The measurement is private.$field) to the hidden field is served, while the same hidden field as a plain filter member is refused403 PERMISSION_DENIED. That makes the hidden field's values a comparison oracle.service-analytics' read-scope / Cube filter compilers still refuse$field, so a CEL field-to-field RLS rule 400s on those faces #7598), and there the engine serves it.Mechanism, as the dev read it:
plugin-security's predicate guard collects the fields a condition names (collectConditionFields) from its keys, and does not collect a field named inside a$fieldcomparand.Direction (proposed, triage's to set)
$fieldcomparand names exactly as it judges a condition key: one collection, one rule. ⛔ No second guard.$fieldcomparand onengine.findand on the aggregate path answers the same403as the hidden field as a key. A readable comparand is the control.Reader who acts
Triage's first grade. The position is in
packages/plugins/plugin-security(domain:servicesby the lane table).Dedupe (queries run before filing, closed included)
security.explainreports a record visible under a row-levelusingthat compares two fields of different classes, whilefindrefuses the same read withINVALID_FILTER/ 400 #20431, security: the analytics ObjectQL execute face answers a row-level read scope it cannot run withINVALID_FILTER/ 400 whose message echoes the policy's field name and comparands — the disclosure #5367 closed for the native / echo faces #19995, [finding] driver-memory's own reference matcher has no$fieldarm — a cross-field comparand (bare or withaddDays) reaching it is presumably compared as a literal object rather than resolved or refused (grep reading, to be measured) #15104, driver-sql: the #7929 withhold covers the cross-field family only — every other INVALID_FILTER refusal still names the target field, which is admin-authored on a read-scope predicate #8197, [spec] SqlDriver 将$field编译为列对列比较(cross-field comparison push-down) #5222 and [spec]$field跨字段比较:spec 声明 + cel-to-filter 产出,但无任何 SQL 执行层实现 —— enforce-or-remove 裁决位 #5041 (closed) are cross-field compile or disclosure positions. None is the field guard skipping a$fieldcomparand.Dedupe words:
predicate guard $field comparand·cross-field comparison field-level security·collectConditionFields field referenceGenerated by Claude Code