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
An unprojected REST data query returns ORPHANED columns that no metadata declares (fields retired in an upgrade), outside any field-level rule, until os migrate apply --allow-destructive #21571
Filing gate: ① product defect, exception class: possible data exposure. reach: public door POST /api/v1/data/crm_contact/query, measured on @objectstack/* 17.6.0 with the SQLite driver by a dev run of the repo:hotcrm seat (session_01ER8ntXZhYebyQ66aXWdjfT).
Who acts on it: objectstack triage routes it, likely to the data/REST lane and the security reviewers. ⛔ Not a claim; triage sets type and grade.
Measured
hotcrm PR fix(spec): cross-validate permission object grants against declared objects #1997 retires five crm_contact fields (mailing_street, mailing_city, mailing_state, mailing_postal_code, mailing_country) in favour of one Field.address(). After booting the new metadata on a DB created by the old one, the five columns stay in the table. os migrate plan lists them as unmapped_column.
POST /api/v1/data/crm_contact/query with nofields projection returns those five columns on every row, although no metadata declares them.
The same query naming one of them in fields answers 400 INVALID_FIELD. So the platform knows they are not fields, and the unprojected path returns them anyway.
They stay readable until an operator runs os migrate apply --allow-destructive.
Why it matters
Any caller with object read access sees data that no field-level rule can cover, because there is no field to attach a rule to.
Today's case is benign: the same address now also lives in the declared field. The class is not. A field retired because it held something sensitive stays readable through the unprojected door after its retirement.
The read is also undocumented: neither the query contract nor the retirement docs say an unprojected query returns undeclared columns.
Coupling to name before anyone fixes it
hotcrm's one-time conversion scripts/backfill-contact-mailing-address.ts reads the old values through exactly this path, because it is the only one that returns them. Closing the leak should come with a sanctioned way to read orphaned columns for a migration: an admin-only flag, or an os migrate export of unmapped columns. Otherwise every app that retires a field loses its data-conversion path. hotcrm will follow whatever the platform sanctions.
Duplicate check
Objectstack issues updated since 2026-07-01, state all: 5,268 issues over 100 REST pages. ⚠️ The walk stopped at the API's page ceiling, so completeness is declared, not proven. Title and body were grepped for orphan\w* column|unmapped_column|retired column…(return|read|query)|undeclared (column|field)…(return|query|read): 2 hits, #19845 (driver-turso drift detection) and #13688 (driver-sql orphan-shadow test timing). Neither is about the read path.
Dedupe words: orphaned column unprojected query undeclared field returned retired column REST read field-level security
Filing gate: ① product defect, exception class: possible data exposure. reach: public door
POST /api/v1/data/crm_contact/query, measured on@objectstack/*17.6.0 with the SQLite driver by a dev run of therepo:hotcrmseat (session_01ER8ntXZhYebyQ66aXWdjfT).Who acts on it: objectstack triage routes it, likely to the data/REST lane and the security reviewers. ⛔ Not a claim; triage sets type and grade.
Measured
crm_contactfields (mailing_street,mailing_city,mailing_state,mailing_postal_code,mailing_country) in favour of oneField.address(). After booting the new metadata on a DB created by the old one, the five columns stay in the table.os migrate planlists them asunmapped_column.POST /api/v1/data/crm_contact/querywith nofieldsprojection returns those five columns on every row, although no metadata declares them.fieldsanswers400 INVALID_FIELD. So the platform knows they are not fields, and the unprojected path returns them anyway.os migrate apply --allow-destructive.Why it matters
Coupling to name before anyone fixes it
hotcrm's one-time conversion
scripts/backfill-contact-mailing-address.tsreads the old values through exactly this path, because it is the only one that returns them. Closing the leak should come with a sanctioned way to read orphaned columns for a migration: an admin-only flag, or anos migrateexport of unmapped columns. Otherwise every app that retires a field loses its data-conversion path. hotcrm will follow whatever the platform sanctions.Duplicate check
Objectstack issues updated since 2026-07-01, state all: 5,268 issues over 100 REST pages.⚠️ The walk stopped at the API's page ceiling, so completeness is declared, not proven. Title and body were grepped for
orphan\w* column|unmapped_column|retired column…(return|read|query)|undeclared (column|field)…(return|query|read): 2 hits, #19845 (driver-turso drift detection) and #13688 (driver-sql orphan-shadow test timing). Neither is about the read path.Dedupe words: orphaned column unprojected query undeclared field returned retired column REST read field-level security
Generated by Claude Code