Skip to content

better-auth /admin/revoke-user-session answers { success: true } when its token matches zero rows — same defect class as #9714, different route and permission surface #10069

Description

@os-warren

Filed unassigned by the #9714 dev (session session_01PnJHU45vPJj5UQrxe946Bx) as an out_of_scope_findings item. Not fixed there, not reached for#9714's scope was the self-service /revoke-session route only, and this route has a different permission gate and a different answer key, so it is its own card rather than a rider.

The defect

Read from the installed vendor dist on 2026-08-19: better-auth 1.7.1 (dist/plugins/admin/routes.mjs), the POST /admin/revoke-user-session handler runs, after its session: ["revoke"] permission check:

awaitctx.context.internalAdapter.deleteSession(ctx.body.sessionToken);returnctx.json({success: true});

There is no match check at all — deleteSession on a token matching zero rows deletes nothing, and the endpoint answers 200 { success: true } unconditionally. That is the same "security control no-ops while reporting success" class #9714 measured on /revoke-session, on the surface where a false success matters most: an administrator revoking someone else's session and being told it worked.

Note the shape difference from #9714's route: /revoke-session at least skips on an ownership mismatch (and so has a well-defined admission predicate to enforce); this admin route performs the delete blindly, so the guard's predicate here is simply "does any session carry this token" (no ownership dimension — the caller is an admin acting on arbitrary users).

Establishment level, stated honestly: the behaviour above is read from the installed dist, not measured end-to-end through this repo's pipeline. #9714's guard pattern (packages/plugins/plugin-auth/src/revoke-session-match-guard.ts, a hooks.before admission gate answering 404 RESOURCE_NOT_FOUND per ADR-0112) is the natural template, but the admin route's interaction with the #7732 tombstone rules (/admin/revoke-user-session is in INTERACTIVE_REVOKE_REASON, reason admin) should be re-verified behaviourally first, exactly as #9714 required.

#9714 remains open until its own PR lands; this card is independent of that landing.


Generated by Claude Code

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions