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
Reported by #7738's dev as out_of_scope_findings (report §4), deliberately not fixed there — plugin-security was outside that card's cleared lane. Filed unassigned.
#7738 / PR #7833 withholds DriverOptions.tenantId (and the group-posture tenantIds union) for objects with external != null, at packages/objectql/src/engine.ts:2528. Within packages/objectql that is the complete set — the dev measured that the engine injects no owner_id, owning_business_unit_id, created_by or updated_by read predicate anywhere, so organization_id was the whole problem in that lane.
Two sibling injectors live on a different layer and are untouched.
The two siblings
injector
column
site
RLS compiler — resolves current_user.organization_id from executionContext.tenantId and folds it into the query AST
A compiled wildcard tenant_isolation rule would add a second, independent org predicate to a federated read — one that #7833's engine-level fix does not reach, because it is applied at a different layer.
⚠️ Unmeasured, and here is exactly why neither fired on the one capture we have
This is a hypothesis with a named place to check it, not an observed defect. #7738's QA capture did not show either predicate, for two identifiable reasons that are properties of that fixture rather than of the code:
the capture showed exactly one predicate with one binding, so no wildcard RLS rule had been compiled for that object on that boot;
showcase_ext_customer carries the ADR-0090 D1 grandfather stamp sharingModel: 'public_read_write', and the run recorded __readScope: 'org'. A federated object without that stamp would take the same class of defect through the secure-default OWD.
Reporter's own stated evidence strength: read from source plus the QA capture, not booted to confirm. Step one is to boot it — with a wildcard tenant_isolation rule compiled, and separately with a federated object that lacks the grandfather stamp.
The failure is fail-open, and that is what makes it worse than an error. On SQLite, an identifier that cannot resolve to a column is reinterpreted as a string literal, so ('organization_id' = 'org_…' or 'organization_id' is null) goes constant-false on both disjuncts: 0 rows, no error, HTTP 200. Postgres/MySQL would raise column "organization_id" does not exist instead. The symptom is dialect-dependent; the defect is not. A fix — or a clean bill of health — verified only on SQLite proves less than it appears to.
If the measurement comes back clean — no wildcard rule ever reaches a federated object, no non-grandfathered federated object exists — "latent, no change needed" is a valid outcome, provided it is recorded with the measurement rather than assumed.
Also noted by the same report, same family, different lane
SqlDriver.computeTenantField (sql-driver.ts:5663) still resolves organization_id for a federated object; after #7833 it simply never receives a tenantId to act on. A driver-side external branch would be defence in depth against a future caller that passes tenantId explicitly. That is the driver lane — mentioned so it is not lost, not folded in here.
Reported by #7738's dev as
out_of_scope_findings(report §4), deliberately not fixed there —plugin-securitywas outside that card's cleared lane. Filed unassigned.Context: what #7738 did and did not close
#7738 / PR #7833 withholds
DriverOptions.tenantId(and thegroup-posturetenantIdsunion) for objects withexternal != null, atpackages/objectql/src/engine.ts:2528. Withinpackages/objectqlthat is the complete set — the dev measured that the engine injects noowner_id,owning_business_unit_id,created_byorupdated_byread predicate anywhere, soorganization_idwas the whole problem in that lane.Two sibling injectors live on a different layer and are untouched.
The two siblings
current_user.organization_idfromexecutionContext.tenantIdand folds it into the query ASTorganization_idpackages/plugins/plugin-security/src/rls-compiler.ts:119__readScopeown/unit)owner_id-shapedA compiled wildcard
tenant_isolationrule would add a second, independent org predicate to a federated read — one that #7833's engine-level fix does not reach, because it is applied at a different layer.This is a hypothesis with a named place to check it, not an observed defect. #7738's QA capture did not show either predicate, for two identifiable reasons that are properties of that fixture rather than of the code:
showcase_ext_customercarries the ADR-0090 D1 grandfather stampsharingModel: 'public_read_write', and the run recorded__readScope: 'org'. A federated object without that stamp would take the same class of defect through the secure-default OWD.Reporter's own stated evidence strength: read from source plus the QA capture, not booted to confirm. Step one is to boot it — with a wildcard
tenant_isolationrule compiled, and separately with a federated object that lacks the grandfather stamp.Why it matters as much as #7738 did
The failure is fail-open, and that is what makes it worse than an error. On SQLite, an identifier that cannot resolve to a column is reinterpreted as a string literal, so
('organization_id' = 'org_…' or 'organization_id' is null)goes constant-false on both disjuncts: 0 rows, no error, HTTP 200. Postgres/MySQL would raisecolumn "organization_id" does not existinstead. The symptom is dialect-dependent; the defect is not. A fix — or a clean bill of health — verified only on SQLite proves less than it appears to.⛔ Fences
Also noted by the same report, same family, different lane
SqlDriver.computeTenantField(sql-driver.ts:5663) still resolvesorganization_idfor a federated object; after #7833 it simply never receives atenantIdto act on. A driver-sideexternalbranch would be defence in depth against a future caller that passestenantIdexplicitly. That is the driver lane — mentioned so it is not lost, not folded in here.Related