Request-derived site is not authorized against the caller when spending AI credentials
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 970
- Forks
- 486
- Avg merge
- 3d 33m
- Merged PRs (30d)
- 170
Description
Description
The site whose AI credentials a request spends can be chosen by the caller through the Host header, and the resolved site is never checked against the caller's permissions.
Across the dotAI REST families, an explicitly named site is permission-checked and a request-derived one is not:
AiHostResolver.resolveHost/resolveHostStrict(used byCompletionsResource,AiProviderResource) checkfindHost(siteId, user)for an explicitsiteId, then fall back toWebAPILocator.getHostWebAPI().getCurrentHostNoThrow(request)with no check on the result./api/inference/v1follows the same shape:requireOverriddenHost(siteOverride, user)is checked,resolveFromRequest(request)resolves the server name asAPILocator.systemUser()and is not.
So a token that cannot read site B can still direct a request at site B by sending Host: b.example, and B pays for the inference.
Why this is not a one-line fix. Applying the explicit path's READ check to the request path returns 403 for every frontend user, who are explicitly supported callers and generally hold no READ permission on the Host object — confirmed by InferenceAuthorizationTest.test_completions_withFrontendUser_isAccepted failing when it was tried. Passing respectFrontendRoles = true instead makes that test pass but defeats the control, since most sites are frontend-readable and the cross-site case sails through.
The question is what authorises spending a site's AI budget. READ on the site is either too strict or too weak depending on which flag is set, which suggests it is the wrong control. Options worth weighing:
- scope an API token to the sites it may direct requests at
- a distinct permission for spending AI credit, separate from READ
- accept it explicitly for server-to-server use, and document that any authenticated caller may spend any site they can reach
Acceptance Criteria
- A decision on what authorises AI spend on a site, recorded rather than implied by the resolver's use of
systemUser - Applied consistently across
/api/v1/ai/*and/api/inference/v1, so the two families do not carry different authorization models - Frontend users remain able to use the endpoints that support them
- A test covering a caller directing a request at a site they have no business spending
Additional Context
- Raised in review of #37559. Pre-existing across the dotAI families rather than introduced there.
- Related and already fixed for the new family only: the
host_id/Hostrequest parameters were honoured on the unmatched-host fallback path (#37491 covers the shipped endpoints).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Read AiHostResolver.resolveHost and resolveHostStrict, then compare requireOverriddenHost with resolveFromRequest across the dotAI REST families. Run InferenceAuthorizationTest.test_completions_withFrontendUser_isAccepted while evaluating the authorization options. Done means one recorded authorization model is applied consistently, frontend users remain supported, and a test prevents spending on an unauthorized site.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- api, authorization, security
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100