GitHub connector
Connector id:githubFixed host:
api.github.com (GitHub Enterprise Server is not supported)
Quick start
Authenticate the GitHub CLI, then run Cynative from the same environment:Credential discovery
Cynative asks the GitHub CLI auth library (go-gh) for a token forgithub.com. Cynative does not read these variables itself; go-gh does. Because Cynative always queries the literal github.com host, go-gh’s enterprise / GH_HOST branches never apply.
GH_TOKEN— highest-precedence GitHub token; read by go-gh forgithub.com.GITHUB_TOKEN— second-precedence token (also the GitHub Actions built-in token).GH_PATH— path to theghexecutable go-gh shells out to for the keyring-fallback token lookup.GH_CONFIG_DIR— directory go-gh reads thegh auth logintoken (hosts.yml) from.
GET /user request (yielding the @login identity shown in the startup inventory). When /user is inconclusive — a GitHub App installation token, an Actions GITHUB_TOKEN, or a rate-limit condition — Cynative falls back to GET /rate_limit, a universally-accessible, rate-limit-exempt endpoint.
References:
- GitHub CLI environment variables —
GH_TOKEN/GITHUB_TOKEN,GH_PATH,GH_CONFIG_DIR. - Authenticating to the GitHub REST API — fine-grained vs classic personal access tokens.
Target selection
The GitHub connector always targets the public GitHub REST API atapi.github.com — the host is hardcoded. It additionally authorizes the GitHub-owned download hosts codeload.github.com, release-assets.githubusercontent.com, and objects.githubusercontent.com (GET/HEAD only) so release-asset and tarball redirects can be followed.
Change the identity by changing the token: run gh auth login, or export GH_TOKEN (highest precedence) or GITHUB_TOKEN. The host is not configurable.
Request usage
Useauth_provider: "github". No connector-specific auth object is required.
Hardening
Host pinning
Host pinning allows onlyapi.github.com and the three GitHub-owned download hosts. The download hosts are GET/HEAD-only, regardless of the configured permissions. Redirects are never followed — a 3xx is returned to the model, which must request the Location URL explicitly (re-entering host pinning and action authorization on each hop).
Category + access-level classification
The in-process classifier resolves each REST request to its GitHub category/subcategory and the required access level (read or write), then allows it only when the configuredconnectors.github.permissions ceiling permits that level for that category.
- The check runs before the token is attached, so a disallowed request is rejected without the credential ever leaving the process.
- The classifier is backed by GitHub’s first-party OpenAPI description, distilled into a category routing table, fetched anonymously and cached from
raw.githubusercontent.com. - A REST request that cannot be classified fails closed. The
secret-scanningcategory is denied by the secure baseline even for reads, because its read endpoints can leak secret material. - The GraphQL API (
/graphql) is not supported and is always denied.
Secret-scanning protection
Secret-scanning protection is layered: the table admission guard rejects any fetched spec that maps asecret-scanning template to another category; the secret-scanning: none baseline in the default exposure blocks all such requests at the ceiling; and unknown routes fail closed.
Cynative configuration
connectors.github.permissions is a category[/subcategory] → read|write|none ceiling. Omit it entirely for the secure default (read everything except secret-scanning). The most-specific match wins (category/subcategory → category → default). write implies read; none denies even reads.
default=write, an opened secret-scanning, or any category:write override), the startup inventory line is loud (⚠) and names exactly what was widened.
Defense at a glance (GitHub)
GitHub limitations
- The connector supports
api.github.comand the listed download hosts. GitHub Enterprise Server hosts are not supported. - Actions-artifact downloads are not supported: GitHub redirects them to per-account Azure blob endpoints, which are outside the GitHub-owned host invariant.
- A configured
permissionsceiling never expands the GitHub token’s own scopes — the effective capability is the intersection of the two. Settingissues: writedoes nothing if theghtoken cannot write issues. - There is no client-side credential downscoping. A PAT,
gh, or OAuth token has its scopes fixed at creation. - The category routing table requires egress to
raw.githubusercontent.com. With no network and no local cache, the connector fails closed — everyapi.github.comrequest is denied with agithub_hardening: category table not readyerror.
GitLab connector
Connector id:gitlabDefault host:
gitlab.com (configurable for self-managed instances)
Quick start
Authenticate with the GitLab CLI or export a Personal Access Token:Credential discovery
Cynative resolves a token for the configured host (defaultgitlab.com) in this order:
- Token environment variable —
GITLAB_TOKEN, thenGITLAB_ACCESS_TOKEN, thenOAUTH_TOKEN(glab’s precedence order). The first non-empty value is used, exec-free, and takes precedence over any glab credential. - glab (
glab auth credential-helper) — when no token env var is set, Cynative delegates to the pinnedglabbinary (requires glab v1.85.2+), which readsconfig.ymlor the OS keyring, refreshes an expired OAuth token, and prints the credential as JSON.
GITLAB_TOKEN— first-precedence token.GITLAB_ACCESS_TOKEN— second-precedence token.OAUTH_TOKEN— third-precedence token.GLAB_CONFIG_DIR— exclusive override of glab’s config directory.XDG_CONFIG_HOME— adds$XDG_CONFIG_HOME/glab-cli/config.ymlas a config location.
glab binary is missing or too old, the connector is skipped loudly with a steer to install/upgrade glab or set GITLAB_TOKEN.
Registration and validation: When a token is discovered, Cynative validates it live at startup with a dial-guarded GET /api/v4/user before registering. An invalid, expired, or unreachable token shows the connector as unavailable with a reason rather than registering and failing every request.
GitLab 18.9 or later is required for self-managed instances (when using api_reference; the connector itself still registers but api_reference is unavailable for older instances).
References:
- GitLab CLI (glab) —
GITLAB_TOKEN,GLAB_CONFIG_DIR;glab auth loginandglab auth credential-helper. - GitLab personal access token scopes —
read_api(least-privilege read),api(full),read_repository,read_user.
Target selection
The GitLab connector targets GitLab SaaS —https://gitlab.com, REST API /api/v4 — by default. The instance is chosen by Cynative config (connectors.gitlab.host, default gitlab.com) and host-pinned. The target is not selected per request; the URL must match the served host.
To point at a self-managed instance: set connectors.gitlab.host: gitlab.example.com (or CYNATIVE_CONNECTORS_GITLAB_HOST). Optionally set connectors.gitlab.api_host when API calls go to a different host than the login host, append :port for a non-443 instance, set allow_private_network: true for a private network, and ca_cert for a private CA.
Request usage
Useauth_provider: "gitlab". No connector-specific auth object is required.
gitlab.com with your configured host (or api_host).
Hardening
Host and port pinning
Host pinning allows only the configuredhost (default gitlab.com), or api_host when set. The TLS port is pinned too — the request URL’s port must match the configured port (or 443 when none is configured). Redirects are never followed.
The connector serves the /api/v4 REST API only. A request whose path is not under /api/v4 is not category-classifiable and fails closed (ErrUnclassifiable).
Per-category exposure classification
The in-process classifier resolves each REST request to its GitLab category and required access level (read or write), then allows it only when the configuredconnectors.gitlab.permissions ceiling permits that level for that category.
- The check runs before the token is attached.
- Reads are
GET,HEAD,OPTIONS(plus thePOST /api/v4/markdowndocumentation-render endpoint); everything else is a write. - The
ci-variablescategory is denied by the secure baseline (even for reads) because its read endpoints return plaintext CI/CD variable values. Any OpenAPI template whose path contains avariablessegment is mapped to theci-variablescategory at table-distillation time. - The GraphQL API (
/api/graphql) is not supported and is always denied. - A path with a
.or..segment, raw or percent-encoded, is denied.
Model-supplied-credential rejection
The connector is the sole setter of credential material. The following are rejected:Private-Token, Job-Token, Deploy-Token, X-Gitlab-Static-Object-Token, Authorization, Proxy-Authorization, X-Ms-Authorization-Auxiliary, and Cookie headers; URL userinfo; the GitLab request-parameter credentials token, private_token, access_token, job_token (in query string, urlencoded, multipart, or JSON body); the feed_token / rss_token feed credentials; and the sudo impersonation control. After all checks pass, Cynative injects Authorization: Bearer <token>.
Dial-time IP authorization
By default, internal IP ranges (RFC1918, loopback, link-local including cloud metadata, ULA, IPv4-mapped forms) are denied. Setallow_private_network: true for self-managed GitLab instances on private networks. An unconditional floor remains denied even with the opt-in: loopback, link-local, and all private (ULA) IPv6 (fc00::/7) — ULA IPv6 stays denied because every major cloud parks its IPv6 instance-metadata service there.
CA certificate (self-managed with a private CA)
Setconnectors.gitlab.ca_cert to the path of a PEM CA certificate file. skip_tls_verify is not supported — TLS validation cannot be bypassed.
Cynative configuration
Target and connection settings
host is the login host (the key glab uses in config.yml). Append :port to either host or api_host for a non-443 instance (e.g. host: gitlab.internal:8443).
Exposure and authorization
connectors.gitlab.permissions is a category → read|write|none ceiling. Omit it entirely for the secure default (read everything except ci-variables). write implies read; none denies even reads.
default=write, an opened ci-variables, or any category:write override), the startup inventory line is loud (⚠).
Defense at a glance (GitLab)
GitLab limitations
- CI job tokens (endpoint-restricted) are out of scope. Cynative authenticates via
Authorization: Bearer, which accepts PATs, project/group access tokens, and OAuth tokens. - The category routing table needs egress to
gitlab.com. With no network and no local cache the connector fails closed. - Container Registry and Pages use separate hosts and authentication paths not covered by this connector.
- Subpath-mounted installations (e.g.
https://example.com/gitlab/) are not supported. - A glab credential requires the
glabbinary (v1.85.2+) onPATH. SetGITLAB_TOKENfor a fully exec-free path. - One instance per run. Cynative registers at most one GitLab provider per session.
- No runtime credential downscoping. The token’s scopes are fixed at issue time. The
permissionsceiling narrows what Cynative will attempt but never expands the token’s own scopes. - Private (ULA) IPv6 instances are unsupported even with
allow_private_network: true. Front a self-managed instance with an RFC1918 IPv4 or global-unicast IPv6 address instead. - A literal
tokenfield in a request body is rejected. GitLab readsparams[:token](the pipeline-trigger credential) from any body encoding, so any model-suppliedtokenfield fails closed. Use the Bearer-authenticatedPOST /projects/:id/pipelineendpoint instead of the trigger endpoint. skip_tls_verifyis not supported. Useca_certfor self-managed instances with a private CA.

