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 (#7728 report), 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 not managedBy: '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: true does 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions