CVE-2026-59185: Identrail Cross-tenant IDOR Client-supplied GitHub App Installation_id Is Vulnerability

HIGH
Advisory Identifier: GHSA-cp3j-m783-3ph5
CVSS 8.5
CWE-639 CWE-862
Published
Advisory Summary

CVE-2026-59185 is a HIGH (CVSS 8.5) client-supplied github app installation_id is vulnerability (CWE-639: Authorization Bypass Through User-Controlled Key) affecting Identrail Cross-tenant IDOR libraries in the Go ecosystem. The issue involves client-supplied github app installation_id is bound to the caller's workspace without ownership verification. Remediation is available by upgrading affected packages to version 1.0.2.

CVE-2026-59185 at a Glance

CVE Identifier CVE-2026-59185
GHSA Identifier GHSA-cp3j-m783-3ph5
Severity HIGH
CVSS v3.1 Base Score 8.5
CWE Classification CWE-639: Authorization Bypass Through User-Controlled Key
Affected Product Identrail Cross-tenant IDOR
Package Ecosystem Go
Published Date
Last Updated

Security Impact

CVSS: 8.5

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:N).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required Low (PR:L)
User Interaction None (UI:N)
Scope Changed (S:C)
Confidentiality High (C:H)
Integrity Low (I:L)
Availability None (A:N)

How to Fix CVE-2026-59185

To remediate this vulnerability, upgrade all affected Identrail Cross-tenant IDOR dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

github.com/identrail/identrail fixed: 1.0.2
Upgrade github.com/identrail/identrail to 1.0.2
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for github.com/identrail/identrail

How to Check if You Are Affected

To determine whether your application is affected by CVE-2026-59185, inspect your project dependencies for Identrail Cross-tenant IDOR:

inspect dependencies for github.com/identrail/identrail

Analyze the terminal output to locate any version of Identrail Cross-tenant IDOR in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 1.0.2), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-639: Authorization Bypass Through User-Controlled Key, where the system's authorization functionality does not prevent one user from gaining access to another user's data or record by modifying the key value identifying the data. In Identrail Cross-tenant IDOR, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

## Summary identrail's GitHub App connection-completion endpoint binds a fully client-supplied `installation_id` to the caller's workspace without verifying that the installation belongs to, or was installed by, the workspace that initiated the connect flow. identrail then mints a GitHub App installation access token for the supplied `installation_id` using the app's own JWT, so an authenticated tenant can link any other identrail customer's GitHub App installation into their own workspace and read that victim organization's private repositories. ## Affected code (default-on path, no feature flag) - Route: `internal/api/router.go:3590` — `POST /v1/workspaces/:workspace_id/projects/:project_id/github/connect/complete`. `installation_id` is read from the JSON body or the attacker-controlled `X-GitHub-Installation-ID` header (`router.go:3582-3588`). - Service: `internal/api/github_connect.go:781` `CompleteGitHubConnection`. The `state` token IS rigorously bound to the caller's scope (`github_connect.go:818`: `if stateRecord.TenantID != scope.TenantID || stateRecord.WorkspaceID != project.WorkspaceID || stateRecord.ProjectID != project.ProjectID { ... }`), but the only check on `installation_id` is `request.InstallationID <= 0` (`:794`). The raw client value is persisted as the workspace's connection (`:840`). - Cross-tenant read primitive: `internal/connectors/github/repositories.go:39` `ListInstallationRepositories` → `internal/connectors/github/app.go:170` mints a token via `POST /app/installations/{installationId}/access_tokens` signed with the App JWT, succeeding for any installation where identrail's app is installed. The feature-flagged V2 path `CompleteGitHubConnector` (`github_connect.go:447`, default off) shares the gap and is additionally weaker (matches pending connector by `state` value alone with no caller-scope re-check); a single fix should cover both. ## Intent proof The code binds `state` to `{TenantID, WorkspaceID, ProjectID}` and re-verifies it at completion (`:818`), demonstrating it understands binding is required. The asymmetry — `state` bound, `installation_id` unbound — is the missed check. ## Exploitation 1. Attacker is any authenticated identrail tenant; they call `StartGitHubConnection` for their own workspace and receive a `state`. 2. Attacker calls the completion route with `{state: <their state>, installation_id: V}` where V is a victim org's identrail GitHub App installation id (installation ids are not secret — they appear in post-install redirect URLs, webhook payloads, the org's GitHub App settings, and are enumerable integers). 3. `CompleteGitHubConnection` accepts (state matches attacker scope), `ListInstallationRepositories(V)` mints a token for V and lists the victim org's private repos, and the connection is persisted under the attacker's workspace. 4. Attacker now reads the victim org's private repository inventory and can drive posture scans/repo reads via their own workspace. Impact: cross-tenant disclosure of another customer organization's private GitHub repositories and metadata. ## Remediation Bind `installation_id` with the same rigor as `state`: capture it from GitHub's signed post-install redirect (`setup_url`/`callback_url`) and pin it to the pending state at start time, and/or after minting verify the installation's `account` matches the org the initiating workspace is authorized for.

CVE-2026-59185 Affected Identrail Cross-tenant IDOR Versions

1 component(s)
Fixed Versions:
1.0.2
Product / Package Ecosystem Affected Versions Fixed Version
github.com/identrail/identrail
Go
< 1.0.2
1.0.2

References

Frequently Asked Questions

What is CVE-2026-59185?
CVE-2026-59185 is a security vulnerability in Identrail Cross-tenant IDOR involving Client-supplied GitHub App installation_id is bound to the caller's workspace without ownership verification under CWE-639: Authorization Bypass Through User-Controlled Key.
Which Identrail Cross-tenant IDOR versions are affected?
Affected versions include releases prior to 1.0.2 across affected packages: github.com/identrail/identrail.
What version fixes CVE-2026-59185?
Upgrading to 1.0.2 (or the latest patched release for your respective branch) resolves the vulnerability.
Is github.com/identrail/identrail affected?
Yes, github.com/identrail/identrail is affected in releases prior to 1.0.2. Upgrade your dependency to 1.0.2 or later.
What is the CVSS score of CVE-2026-59185?
CVE-2026-59185 has a CVSS v3.1 base score of 8.5 (HIGH) with vector string CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:N.
What CWE is associated with CVE-2026-59185?
CVE-2026-59185 is classified under CWE-639: Authorization Bypass Through User-Controlled Key (The system's authorization functionality does not prevent one user from gaining access to another user's data or record by modifying the key value identifying the data.).
How can I check Go dependencies for CVE-2026-59185?
Run the dependency tree command: 'inspect dependencies for github.com/identrail/identrail'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-cp3j-m783-3ph5",
  "modified" : "2026-09-09T23:52:14Z",
  "published" : "2026-09-09T23:52:14Z",
  "aliases" : [ "CVE-2026-59185" ],
  "summary" : "Identrail Cross-tenant IDOR: Client-supplied GitHub App installation_id is bound to the caller's workspace without ownership verification",
  "details" : "## Summary\n\nidentrail's GitHub App connection-completion endpoint binds a fully client-supplied `installation_id` to the caller's workspace without verifying that the installation belongs to, or was installed by, the workspace that initiated the connect flow. identrail then mints a GitHub App installation access token for the supplied `installation_id` using the app's own JWT, so an authenticated tenant can link any other identrail customer's GitHub App installation into their own workspace and read that victim organization's private repositories.\n\n## Affected code (default-on path, no feature flag)\n\n- Route: `internal/api/router.go:3590` — `POST /v1/workspaces/:workspace_id/projects/:project_id/github/connect/complete`. `installation_id` is read from the JSON body or the attacker-controlled `X-GitHub-Installation-ID` header (`router.go:3582-3588`).\n- Service: `internal/api/github_connect.go:781` `CompleteGitHubConnection`. The `state` token IS rigorously bound to the caller's scope (`github_connect.go:818`: `if stateRecord.TenantID != scope.TenantID || stateRecord.WorkspaceID != project.WorkspaceID || stateRecord.ProjectID != project.ProjectID { ... }`), but the only check on `installation_id` is `request.InstallationID <= 0` (`:794`). The raw client value is persisted as the workspace's connection (`:840`).\n- Cross-tenant read primitive: `internal/connectors/github/repositories.go:39` `ListInstallationRepositories` → `internal/connectors/github/app.go:170` mints a token via `POST /app/installations/{installationId}/access_tokens` signed with the App JWT, succeeding for any installation where identrail's app is installed.\n\nThe feature-flagged V2 path `CompleteGitHubConnector` (`github_connect.go:447`, default off) shares the gap and is additionally weaker (matches pending connector by `state` value alone with no caller-scope re-check); a single fix should cover both.\n\n## Intent proof\n\nThe code binds `state` to `{TenantID, WorkspaceID, ProjectID}` and re-verifies it at completion (`:818`), demonstrating it understands binding is required. The asymmetry — `state` bound, `installation_id` unbound — is the missed check.\n\n## Exploitation\n\n1. Attacker is any authenticated identrail tenant; they call `StartGitHubConnection` for their own workspace and receive a `state`.\n2. Attacker calls the completion route with `{state: <their state>, installation_id: V}` where V is a victim org's identrail GitHub App installation id (installation ids are not secret — they appear in post-install redirect URLs, webhook payloads, the org's GitHub App settings, and are enumerable integers).\n3. `CompleteGitHubConnection` accepts (state matches attacker scope), `ListInstallationRepositories(V)` mints a token for V and lists the victim org's private repos, and the connection is persisted under the attacker's workspace.\n4. Attacker now reads the victim org's private repository inventory and can drive posture scans/repo reads via their own workspace.\n\nImpact: cross-tenant disclosure of another customer organization's private GitHub repositories and metadata.\n\n## Remediation\n\nBind `installation_id` with the same rigor as `state`: capture it from GitHub's signed post-install redirect (`setup_url`/`callback_url`) and pin it to the pending state at start time, and/or after minting verify the installation's `account` matches the org the initiating workspace is authorized for.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Go",
      "name" : "github.com/identrail/identrail"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "1.0.2"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/identrail/identrail/security/advisories/GHSA-cp3j-m783-3ph5"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/identrail/identrail/commit/835e40517509d6ef5405c27fbf14f579bedff0e7"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/identrail/identrail"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/identrail/identrail/releases/tag/v1.0.2"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-639", "CWE-862" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-09-09T23:52:14Z",
    "nvd_published_at" : null
  }
}