Skip to content

Check whether sys_session.token — a live session credential — serializes over the data API (ADR-0100 channel 3 has no read protection) #7823

Description

@os-zhuang

Status: UNMEASURED. Step one is a measurement, not a fix.

Raised as an out_of_scope_findings item by the #7728 dev (#7728report), who flagged it as "worth checking first" — i.e. potentially more serious than the card it fell out of. Filed unassigned; assign at the moment you start.

Nothing here has been observed on a running system. The #7728 dev inferred it structurally from the same code paths it measured for sys_api_key.key, and said so plainly. Treat every claim below as a hypothesis with a named place to check it.

The hypothesis

packages/platform-objects/src/identity/sys-session.object.ts:176 declares:

token: ... description: 'Opaque session token — never exposed in UI'

The mechanism that leaked sys_api_key.key — established on code in #7728 — is not field-specific:

  • the engine read path never consults hidden (no .hidden reference in engine.ts), so hidden: true does not strip a value from serialization; and
  • collectMaskedReadFields (packages/objectql/src/secret-fields.ts:88-96) masks password-typed fields only when the object is notmanagedBy: 'better-auth'.

sys_session is an auth-subsystem object, so if it carries managedBy: 'better-auth' the masking collector is inert on it too — ADR-0100's channel 3 (auth-subsystem one-way hashes and opaque tokens on plain text columns), which #7728 established has no read protection at all.

⚠️ Do NOT import #7728's framing — this is a different defect if it is one

#7728 is a false-declaration defect: its field claims "never exposed to clients", which is a serialization claim, and it was false.

This field claims "never exposed in UI". That is the narrower claim, and hidden: truedoes satisfy it. So:

  • If token serializes over the data API, the declaration is not thereby false — the defect would be a credential disclosure, argued on its own merits, not on a contradicted description.
  • Conversely a "fix the description" option does not exist here, because the description is not the thing that would be wrong.

The reason to rate this potentially above#7728 despite the weaker declaration: sys_api_key.key is a SHA-256 hash — not a usable credential, which is why #7728 was correctly kept public, unembargoed and off target:v17. A session token is the live credential itself. If it serializes to any persona that should not hold it, that is a real disclosure and the severity conversation is a different one.

Step one — measure before anything else

  1. Confirm whether sys_session is managedBy: 'better-auth' and whether token is a plain text column.
  2. On a real engine: create a session, then GET /api/v1/data/sys_session/{id} and the list endpoint. Does the token value come back, and to which personas?api-key-ui-lifecycle (secondary): the key column (SHA-256 hash) serializes over the data API, contradicting its own "never exposed to clients" description #7728's leak was admin-readable only, because ordinary personas are 403 on the object — establish the equivalent here rather than assuming it matches.
  3. Check whether anything legitimately reads token off a data-API response (the verifier using it as a where filter is not a read — that was the distinction that made api-key-ui-lifecycle (secondary): the key column (SHA-256 hash) serializes over the data API, contradicting its own "never exposed to clients" description #7728's strip safe).

"Latent, not live" is a complete and valid outcome. If the value never serializes, say so with the measurement and close the card — do not manufacture a fix for a path nothing exercises.

If it IS live

The fix vehicle is very likely the same one #7728 is parked on — there is currently no field-level mechanism that strips a value from the generic read path (secret encrypts at rest and would break the lookup; password is inert on better-auth objects; FLS is bypassed by system contexts and by admin). #7728's report contains the full elimination and a proposed design awaiting a maintainer ruling.

Do not build a parallel mechanism. If the measurement says live, report the dependency and stop — the PM will sequence this against #7728's ruling. Two competing masks would be a worse defect than either leak.

⛔ Do not relabel this a security card or embargo it pre-measurement; and do not assume the #7728 severity call transfers, in either direction.

Source

out_of_scope_findings#1 from the #7728 dev report. Sibling finding #2 (sys_account.password, sys-account.object.ts:208, hashed text, same unprotected class, makes no non-exposure claim) is recorded on #7728's escalation rather than filed separately — it has no independent symptom.

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions