mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-09-15 20:52:21 +02:00
Merge commit from fork
* fix(security): stop API tokens reaching privileged agent tools A bearer API token resolves to the human who minted it, and minting is admin-only, so every owner-keyed privilege check in the agent path answers "admin". A token issued for a narrow integration therefore reached bash and python with the authority of the account that created it. Three independent routes to that sink, each closed here. The token could answer its own tool-approval prompt. An approval records that a person authorized one dangerous action, and a token cannot make that statement, so /api/chat_stream now refuses an approval resume from a bearer caller. The chat-session grant was reconstructable from caller-supplied message metadata. Two routes persist a metadata blob on the caller's behalf, so the shape of a resolved approval card could be written straight into a transcript and was then read back as authority. The server now signs the grant when it resolves an approval and verifies that signature when reading it back, binding it to the chat and the approval it was issued for. Both routes also drop server-owned keys from an inbound blob. A run driven by a token inherited its owner's tool set. Such a run is now capped at the non-admin policy regardless of who minted the credential, which holds even where no approval is raised at all. The human path is unchanged: a browser session still receives the prompt, still approves, and a granted chat-session scope still carries to later turns in that chat. Scope enforcement across the wider route surface is a separate gap and is not addressed here. * fix scoped chat delegation boundaries * fix(auth): reject malformed chat approval signatures --------- Co-authored-by: RaresKeY <158580472+RaresKeY@users.noreply.github.com>
This commit is contained in:
@@ -41,6 +41,45 @@ def _is_api_token_request(request: Request) -> bool:
|
||||
return bool(getattr(request.state, "api_token", False))
|
||||
|
||||
|
||||
def is_delegated_credential(request: Request) -> bool:
|
||||
"""Whether this request arrived on a credential acting FOR a human.
|
||||
|
||||
A bearer API token is minted by a person and then handed to something
|
||||
else: an integration, a script, a third party. :func:`effective_user`
|
||||
resolves it back to that person for ownership and attribution, which is
|
||||
correct for data but wrong for authority. Only admins can mint tokens, so
|
||||
every token resolves to an admin, and any gate that asks "is the owner an
|
||||
admin?" answers yes for a credential the owner has given away.
|
||||
|
||||
Security decisions about what the AGENT may do should ask this instead, so
|
||||
a token cannot inherit the shell merely because its owner could use one.
|
||||
"""
|
||||
return _is_api_token_request(request)
|
||||
|
||||
|
||||
def require_api_token_scope(request: Request, scope: str) -> Optional[str]:
|
||||
"""Require ``scope`` when the request is authenticated by an API token.
|
||||
|
||||
Browser sessions are unaffected. Scoped bearer routes use this before
|
||||
touching owner data so resolving the token back to its owner never also
|
||||
grants the owner's interactive-session authority.
|
||||
"""
|
||||
if not _is_api_token_request(request):
|
||||
return get_current_user(request)
|
||||
scopes = set(getattr(request.state, "api_token_scopes", []) or [])
|
||||
if scope not in scopes:
|
||||
raise HTTPException(403, f"API token missing required scope: {scope}")
|
||||
owner = getattr(request.state, "api_token_owner", None)
|
||||
if not owner:
|
||||
raise HTTPException(403, "API token has no owner")
|
||||
return owner
|
||||
|
||||
|
||||
def require_chat_api_token_scope(request: Request) -> Optional[str]:
|
||||
"""FastAPI dependency for chat/session/history bearer surfaces."""
|
||||
return require_api_token_scope(request, "chat")
|
||||
|
||||
|
||||
def require_authenticated_request(request: Request) -> str:
|
||||
"""Allow either a browser session or a valid bearer API token.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user