Skip to content

fix(security): scope git clone tokens to their exact app repository - #456

Open
karishnu wants to merge 1 commit into
stagingfrom
fix/git-clone-token-repository-scope
Open

karishnu wants to merge 1 commit into
stagingfrom
fix/git-clone-token-repository-scope

Conversation

@karishnu

@karishnu karishnu commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Git clone tokens were minted as ordinary access JWTs and verified only by checking that the token subject owned the requested app; the app-specific sessionId claim was never checked at verification time, so a token minted for one private app could clone any other private app owned by the same user.
  • Replace the token shape with a dedicated, purpose-scoped credential (worker/utils/gitCloneToken.ts) bound to { userId, target }, where target discriminates between a Think app Space repository and an agent-managed repository.
  • Both git smart-HTTP endpoints (info/refs, git-upload-pack) now require an exact target match in addition to current ownership before serving repository data.
  • The new token can no longer be parsed as a normal API access token (JWTUtils.verifyToken() rejects it).
  • Malformed Basic auth headers now return 401 instead of an uncaught atob() exception surfacing as 500.

Files changed

  • worker/utils/gitCloneToken.ts (new) - git-only JWT claims/signer/verifier
  • worker/agents/index.ts - shared resolver mapping an app id to its repository target, reused by minting and verification
  • worker/api/controllers/appView/controller.ts - mint tokens scoped to the resolved target
  • worker/api/handlers/git-protocol.ts - verify target + ownership before serving repository data; fix malformed Basic-auth handling
  • worker/utils/gitCloneToken.test.ts, worker/api/handlers/git-protocol.test.ts (new) - regression coverage

Test plan

  • bunx vitest run worker/utils/gitCloneToken.test.ts worker/api/handlers/git-protocol.test.ts (18/18 passing)
  • bun run typecheck
  • bun run lint
  • bun run build
  • Manual review of same-owner cross-app reuse, cross-backend confusion, cross-owner tokens, generic-token rejection, and malformed auth header handling

Git clone tokens were minted as ordinary access JWTs and verified only
by checking that the token subject owned the requested app. This let a
token minted for one private app clone any other private app owned by
the same user, since the app-specific sessionId claim was never
checked at verification time.

Replace the token shape with a dedicated, purpose-scoped credential
that binds the owner and the exact repository backend (Think app Space
vs. agent-managed git). Both git smart-HTTP endpoints now require an
exact target match in addition to current ownership, and the token can
no longer be parsed as a normal API access token.

- worker/utils/gitCloneToken.ts: git-only JWT claims/signer/verifier
  bound to { userId, target } where target discriminates Space vs.
  agent repositories
- worker/agents/index.ts: shared resolver mapping an app id to its
  repository target, reused by both minting and verification
- worker/api/controllers/appView/controller.ts: mint tokens scoped to
  the resolved target instead of a generic access token
- worker/api/handlers/git-protocol.ts: verify target + ownership
  before serving repository data; treat malformed Basic auth as 401
  instead of a 500
- add regression coverage for cross-app reuse, cross-backend
  confusion, cross-owner tokens, generic-token rejection, and
  malformed auth headers
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant