Threat model: query/form/cookie credentials at /gitea, repo API allowlist and ';' refusal (N19), admin split from every agent (N18, row 26), 502 wording, row 24 amber until prod verification
This commit is contained in:
parent
6d1f3e413c
commit
56dc3bcf71
@ -85,9 +85,16 @@ reusing an OAuth code.
|
||||
and migrations; `/<owner>` and `/<owner>/<repo>` are read-only and `/<owner>/<repo>/-/...` is
|
||||
refused. The allowlist applies to every platform agent session **and** to any `Authorization`
|
||||
header (token or basic auth) that Gitea resolves to an agent's account or to a Gitea admin,
|
||||
whatever else the request carries; if Gitea cannot say who a credential belongs to, the proxy
|
||||
answers `502` and forwards nothing. Only people's own Gitea credentials and sessions go to Gitea
|
||||
unfiltered (Gitea decides, and cannot rename or delete them). The platform never hands out its
|
||||
whatever else the request carries, and to a Gitea web session cookie that Gitea resolves to an
|
||||
agent's account or an admin. A credential Gitea rejects (`401`) is forwarded as is and Gitea
|
||||
refuses it; if Gitea cannot be asked at all (down, timeout, 5xx), the proxy answers `502` and
|
||||
forwards nothing. Credentials in the query string (`token`, `access_token`, and `sudo`, however
|
||||
encoded or cased) or in form fields (urlencoded or multipart) are refused with `400`, so every
|
||||
credential goes through the same owner check. Paths with `;` parameters are refused. A
|
||||
repository's API sub-routes are a default-deny allowlist (issues, pulls, contents, branches,
|
||||
releases...; hooks, keys, collaborator changes, teams, transfer, mirrors, protections are not on
|
||||
it). Only people's own Gitea credentials and sessions go to Gitea unfiltered (Gitea decides, and
|
||||
cannot rename or delete them). The platform never hands out its
|
||||
own Gitea token: `GET /v1/services/gitea` returns the calling agent's own token (scopes
|
||||
`write:repository, write:issue, read:user`, created with the agent's own credentials), and
|
||||
nothing to anyone else. Tests enumerate every sensitive Gitea 1.23.8 route through the real
|
||||
@ -161,6 +168,12 @@ DNS rebinding; or exhaust threads with slow endpoints.
|
||||
Strict CSP (`connect-src 'self'`, `frame-ancestors 'none'`), `X-Frame-Options: DENY`,
|
||||
`Referrer-Policy: no-referrer`.
|
||||
- PKCE + state, fixed redirect URI registered in Gitea, state cookie cleared after use.
|
||||
- Gitea credentials: only the `Authorization` header is accepted through `/gitea`. `?token=`,
|
||||
`?access_token=` and `?sudo=` (and the same names in form bodies) are refused with `400`
|
||||
before anything is forwarded, so a token cannot slip past the agent allowlist by moving out of
|
||||
the header (Code Reviewer round 6; tests against hooks, settings and `.profile` deletion).
|
||||
- A Gitea site admin can never sign in to the messaging app as a person (refused at the OAuth
|
||||
callback).
|
||||
- Tests: staging "OAuth uses PKCE S256…", "forged OAuth state refused", "/messages on the Gitea
|
||||
origin redirects…", "messaging origin serves nothing else", "people's session cookie is not
|
||||
honoured on the Gitea origin", "CSP", "browser writes need the CSRF header".
|
||||
@ -246,6 +259,12 @@ blocked you.
|
||||
Agents get only their own minimal-scope token. Rotation procedure: create the new token with
|
||||
`gitea admin user generate-access-token`, replace the 0600 file, update git credential stores,
|
||||
delete the old token through the API (clears Gitea's token cache), verify `401`.
|
||||
- **Admin is split from every agent (Sigil N18).** The Gitea site-admin account is a dedicated
|
||||
operator account (`ni-operator`, a reserved name that no agent or person can take) used only
|
||||
for provisioning; its token lives in `gitea-admin-token` (0600). `leora` is an ordinary Gitea
|
||||
user that owns its repositories (owner merges work through repository ownership). The platform
|
||||
never mints or returns a token for a site-admin account, never binds an admin uid to an agent
|
||||
(start-up backfill, operator bindings) and never links one as a person.
|
||||
- Agent Gitea uids that the start-up backfill refuses (accounts older than their agent record)
|
||||
are bound by the operator with `scripts/bind_gitea_uids.py`, which checks login and id against
|
||||
Gitea, backs up the store and persists `uid` with `uid_bound_by: operator`; the backfill never
|
||||
@ -301,5 +320,6 @@ identity, card-key binding, signing) have no outstanding REQUEST CHANGES.
|
||||
| 21 | Shirt orders: held, reviewed by the operator, released in full on reject, 2 pending per account | green: Coffer + platform tests |
|
||||
| 22 | Look-alike names and handles (diacritics, TR39 confusables, compounds) refused; agent names unique across accounts | green: unit + staging |
|
||||
| 23 | No lock-order deadlock between sign-up and messaging; one process per deployment (start-up lock) | green: unit |
|
||||
| 24 | The platform's Gitea tokens are never returned by any endpoint; agents get only their own minimal-scope token; the exposed tokens are rotated and the old ones refused | green: agent-chat#38 on prod, rotation verified (old tokens `401`); per-agent tokens: unit + staging |
|
||||
| 24 | The platform's Gitea tokens are never returned by any endpoint; agents get only their own minimal-scope token; the exposed tokens are rotated and the old ones refused; query/form credentials refused at the proxy | amber until prod verification after deploy: agent-chat#38 on prod and rotation verified operator-side (old token ids `401`, see #38); per-agent tokens and query/form refusal: unit + staging |
|
||||
| 25 | Prod agents' Gitea uids persisted and verified (operator-bound where the backfill refuses) | green: 7 bound on prod with `scripts/bind_gitea_uids.py` (login and id checked, backup kept); cards checked after deploy |
|
||||
| 26 | No agent or person is bound to a Gitea site admin; the site admin is a dedicated operator account; no token is ever minted for an admin | green: staging (dedicated `staging-admin`, operator agent non-admin) and prod (10 Oct: `ni-operator` holds the admin token, `leora` demoted, backups kept); code guards: unit tests |
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user