Skip to content

Upgrade @better-auth/oauth-provider once 1.7.0 is stable (GHSA-p2fr-6hmx-4528) #10

Description

@wiverson

Dependabot flags GHSA-p2fr-6hmx-4528
(medium) against @better-auth/oauth-provider. We are on 1.6.25; the
vulnerable range is >= 1.4.8, < 1.7.0-beta.4, and the 1.6.x stable line is
not being patched
.

Analysed rather than deferred — the conclusion is that it is not exploitable in
this deployment, but the alert stays open until we can upgrade, so the reasoning
belongs somewhere findable.

The defect

The provider accepts the RFC 8707 resource parameter only at the token
endpoint, never at /oauth2/authorize. The resource a client states when the
user authorises is discarded; whatever it sends at token exchange is honoured on
its own, checked only against the server-wide validAudiences allowlist. The
refresh grant has the same gap — the audience is re-derived from the refresh
request body, because no resource from the original grant is retained.

So the token audience is a per-request, client-chosen value rather than a
property of the authorisation. RFC 8707 expects the AS to record resources at
authorisation and let the token endpoint narrow them, never widen.

Why we match the detector

Two of the advisory's three conditions hold:

  • We are on a vulnerable version.
  • We configure two audiences, in src/server/auth.ts:
    validAudiences: [env.baseUrl, ${env.baseUrl}/api/mcp]. The advisory notes
    a single-entry deployment cannot mint a token for a different audience; ours
    can.

Why it is not exploitable here

The third condition — resource servers make authorization decisions based on
that aud value
— does not hold.

  • There is exactly one resource server, and it accepts both audiences.
    mcpHandler in src/server/mcp/oauth.ts verifies
    audience: [env.baseUrl, "${env.baseUrl}/api/mcp"]. It is the only JWT
    consumer in the codebase — nothing else verifies against the JWKS, and the
    admin UI uses Better Auth session cookies rather than these tokens. Swapping
    between the two allow-listed audiences moves a token from /api/mcp to
    /api/mcp.
  • Privilege comes from scopes, not audience. accessFromScopes derives
    read/write from vault:read / vault:write, and the advisory states scope
    checks are independent of the resource, so this cannot widen access.
  • Completing the flow requires the operator. Dynamic client registration is
    open, so anyone may register a client, but authorisation requires signing in
    and approving at the consent screen. A client that gets that far already holds
    the scopes granted to it; the audience swap adds nothing.

The spec-compliance gap is real regardless, and that is what the upgrade fixes.

Why not act now

Both documented workarounds cost more than the bug does here:

  • Reduce validAudiences to one entry — would reject clients sending the
    other resource value and risks breaking working MCP connectors, to close a
    path that leads nowhere in this topology.
  • Take 1.7.0-beta.4 — a beta, a breaking API change
    (customAccessTokenClaims.resource becomes a resources array, uncovered
    resources return invalid_target), and a schema migration.

What to do

  • Watch for stable @better-auth/[email protected].
  • Upgrade, then run npx auth migrate.
  • Re-check customAccessTokenClaims usage against the renamed resources array.
  • Re-run the OAuth flow end to end with Claude Desktop and Codex — the
    breaking change touches exactly the resource-indicator handling those
    clients rely on.
  • Close this and confirm the Dependabot alert clears.

The condition this analysis rests on

Both validAudiences entries must keep naming the same resource server. If a
second, genuinely distinct resource server is ever added to that allowlist while
we are still on 1.6.x, the escalation becomes real. A comment to that effect
belongs next to validAudiences in src/server/auth.ts — worth adding whether
or not this issue is actioned soon.

Metadata

Metadata

Assignees

No one assigned

    Labels

    futureDeliberately deferred; not needed for MVP

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions