Repository navigation
Description
Summary
When a user creates an API key over HTTP (POST /api/api-keys), the accounts and max_amount constraints on its permissions are silently dropped. The key is stored without the account and purchase-amount limits the caller asked for. providers, services and regions survive.
This was found while working on #83 (PR #940). The reviewer on #940 agreed it should be tracked separately. It is pre-existing and #940 doesn't change it.
Cause
The two layers use different JSON field names for the same constraint, and the API-key path converts between them with a JSON round-trip:
- The handler decodes the body into
api.CreateAPIKeyRequest→api.Permission→api.PermissionConstraint(internal/api/types.go:371). Its JSON tags areaccountsandmax_amount, which match the OpenAPI spec (internal/api/openapi.yaml, around line 2706). auth.Service.CreateAPIKeyAPI(internal/auth/service_apikeys_api.go:191) receives that value asany. Itjson.Marshals it andjson.Unmarshals it intoauth.APICreateAPIKeyRequest, whosePermissionsare[]auth.Permission.auth.PermissionConstraints(internal/auth/types.go:59) tags those fieldsaccount_idsandmax_purchase_amount. The unmarshal ignoresaccountsandmax_amount, soAccountIDsandMaxPurchaseAmountcome out empty.
Groups don't have this problem. They map the fields explicitly in apiPermissionToPermission / permissionToAPIPermission (internal/auth/service_api.go:184-214).
Impact
A key the caller meant to restrict to particular accounts or a purchase cap is created without those limits. It's still bounded by the owner's group permissions and the group ceiling, so it can't exceed what the owner can already do. It is not a privilege escalation past the owner. But the narrower scope the user asked for is silently not applied, and nothing in the response says so.
I haven't checked whether the listing (APIKeyInfo.Permissions, also []auth.Permission) shows the constraints back in the account_ids shape, which would hide the drop from API clients that read accounts. The fix PR should check this.
Expected
The account and amount constraints on POST /api/api-keys are stored and enforced, using the documented accounts / max_amount field names. The listing should return them in the same shape.
Suggested fix
Have APICreateAPIKeyRequest carry []APIPermission (the API-shaped type), convert with the existing apiPermissionToPermission, and add a regression test that posts accounts / max_amount through the real handler and checks the stored key.
Suggested labels (I can't apply them): type/security, type/bug, priority/p2, severity/medium.
🤖 Generated with Claude Code
Activity
IAmJSD commentedon Oct 16, 2026
Claiming: working on this