{"schema":"threatline.record/2","record":{"id":"GHSA-2qh9-qcxq-f8qc","aliases":["GHSA-2qh9-qcxq-f8qc"],"summary":"Scope chains are ignored by findByKey() and exists(key=)","details":"### Impact\nWheels 4.0 added chainable model scopes (`model(\"Book\").published().findAll()`). Two chain terminals ignore the scope's conditions:\n\n- `findByKey(key)` replaces the merged WHERE clause with the primary-key condition, so `model(\"Book\").published().findByKey(id)` returns the record even when it is outside the scope.\n- `exists(key=...)` on a scope chain or the query builder does the same; in production (error information off) it returns true for an out-of-scope key instead of throwing.\n\nApplications that use scopes for authorization or multi-tenancy (for example a `currentTenant` or `ownedBy(user)` scope chained into finders, as the multi-tenancy guide recommends) can therefore load, and then update or delete, records belonging to another user or tenant when the record key comes from the request.\n\n`findAll`, `findOne`, `findFirst`, `count` and other aggregates, `updateAll`, `deleteAll`, `findEach` and `findInBatches` respect the scope and are not affected.\n\n### Patches\nFixed in 4.2.0. `findByKey()`, `exists(key=...)`, `updateByKey()` and `deleteByKey()` now combine the key condition with an incoming scope chain, query builder or `where` argument (AND) instead of replacing it, so a key outside the scope matches nothing. Lookups with no `where` are unchanged.\n\n### Workarounds\nUse `findOne(where=\"id = #key#\")` or `findAll(where=...)` on the scope chain instead of `findByKey`, or check ownership explicitly after loading the record.\n","categories":["Unclassified"],"product":"wheels","vendor":"","ecosystem":null,"affected_ranges":[{"source":"GitHub Advisory Database","source_url":"https://github.com/wheels-dev/wheels/security/advisories/GHSA-2qh9-qcxq-f8qc","source_modified_at":"2026-10-12T00:02:29Z","fetched_at":"2026-10-28T20:58:01.013507Z","package":{"ecosystem":"other","name":"wheels"},"range":">= 4.0.0, <= 4.1.2"}],"fixed_versions":[{"source":"GitHub Advisory Database","source_url":"https://github.com/wheels-dev/wheels/security/advisories/GHSA-2qh9-qcxq-f8qc","source_modified_at":"2026-10-12T00:02:29Z","fetched_at":"2026-10-28T20:58:01.013507Z","package":{"ecosystem":"other","name":"wheels"},"version":"4.2.0"}],"cvss":8.1,"severity":"High","kev":{"listed":false},"epss":{"probability":null,"percentile":null,"score_date":null},"published_at":"2026-10-12T00:02:29Z","modified_at":"2026-10-12T00:02:29Z","provenance":[{"source":"GitHub Advisory Database","url":"https://github.com/wheels-dev/wheels/security/advisories/GHSA-2qh9-qcxq-f8qc","fetched_at":"2026-10-28T20:58:01.013507Z","source_modified_at":"2026-10-12T00:02:29Z"}],"sources":["GitHub Advisory Database"],"references":[],"locations":[],"motoko_assessment":{"status":"requires_architecture_review","automatic_remediation":false},"classification":{"method":"product-first software-layer rules","rules_version":"2.1","matched_on":null,"confidence":"unknown","reviewed":false},"change_timestamp":"2026-10-12T00:02:29Z","content_hash":"8eeec42889db3bb19f7953fe3979c00d3f430dcb8006bf02043520da2f6065fd"}}
