Talked to one of the devs, this is indeed the case. When synchronizing to IAM, the effective rights per column is calculated. If not unauthorized, the column is syncrhonized to IAM. Whenever data is then selected from a table, all columns present in IAM will be included in the API unless a $select= is specified.
Of course this is based on role rights so nobody sees more columns/data than they are allowed to, but if you have rights to the hidden column, the data will be included in the API request if the $select= is not used.
Reason being is that the underlying interface views will not recalculate whether or not the column should be included in the request as this would cost a lot of performance. For every column, we would have to first check the rights (already done), gather the maximum access type (already done), then look if the column is used in for instance a conditional layout condition, or in a prefilter or, or, or… That decreases the performance significantly.
So if you truly want to prevent the column/data from occurring in the API call, a View (with appropriate rights) would indeed solve that.