Threat model
Security
Greenlight’s threat model assumes the coding agent is helpful but not trusted, the citizen developer is well-intentioned but inexperienced, and the network is hostile by default. The design decisions across the platform follow from that frame.
Actors
Section titled “Actors”| Actor | What they can do | What they cannot do |
|---|---|---|
| Citizen developer | Talk to their agent, watch their app run, see audit events for their app. | Run privileged operations on the cluster, edit org policy, reach apps they don’t own. |
| Coding agent | Call MCP tools as the bound user, open PRs, propose Knowledge edits, inspect granted data through results-only tools, run the app locally through the paired CLI. | Escalate beyond the bound user’s RBAC, bypass the policy check, write to Knowledge directly, receive a raw credential or environment value. |
| Admin / Org Owner | Register integrations from the catalog or a custom path, edit policy (Org Owner only), override the policy check (with audit), kill or restore apps. | Read integration secret values, rewrite the audit log, mint a fake workload identity. |
| External attacker on the network | Reach the cluster’s public ingress. | Reach app pods directly, reach the control plane, mint workload credentials, exfil via app pods. |
| Compromised app pod | Run code in the namespace, reach the integrations it was granted (through the broker, or directly when the integration is injected). | Reach other apps, reach upstreams it was not granted, modify its own namespace policy. |
Trust boundaries
Section titled “Trust boundaries”The platform has five trust boundaries that matter for an attack path discussion:
- The IdP boundary — between the customer’s user directory and Greenlight. Crossed by OIDC SSO.
- The control plane boundary — between Greenlight’s services and everything else. Crossed only by authenticated API and MCP calls. Where the updater is enabled, a compromised control-plane pod can create any Job in
greenlight-updater(the Role grantscreate, not a clone-only constraint), which includes running under the updater’s cloud identity. - The data-access boundary — between app pods and upstream systems. Every reach is governed by an IT-approved integration grant. Proxied integrations cross it only through authorized, audited broker calls — the pod holds no upstream credential. Injected integrations (the wire-protocol sources a proxy can’t front) cross it as a direct call from the pod using a credential in its environment; narrowing outbound to that one host is planned and not yet enforced.
- The cluster boundary — between app namespaces and the rest of the customer’s cloud. Crossed only through the ingress controller and the data broker.
- The customer boundary — between the customer’s cloud environment and Shift. Greenlight never crosses this; the customer’s data, code, and end users stay in their cloud. Updates cross it in one direction only: the customer-owned updater pulls digest-pinned releases and applies them under a customer-owned identity that is scoped to the Greenlight-managed resources and cannot expand its own access, with delete protection built into the infrastructure templates so no automatic run can destroy a data-bearing resource. Shift holds no credential into the customer’s cloud.
Specific scenarios
Section titled “Specific scenarios”Compromised coding agent
Section titled “Compromised coding agent”A malicious or hijacked agent session can only do what the bound user can do. It cannot escalate, cannot impersonate, cannot reach an app it has no permission for, cannot bypass the policy check on the way to merge. It never holds a credential or environment value either: the agent investigates real data through results-only inspection tools that run inside the control plane, and runs the app through a paired CLI that injects values into the local process — no secret transits the agent’s context. The damage ceiling is “what the bound user could do directly,” and every action is in the audit log with actor_kind=agent. Probing Greenlight’s agent OAuth endpoints — replaying authorization codes, guessing PKCE verifiers, presenting a mismatched client — does not mint a token either; each rejection writes an auth.authorize.failed or auth.token_exchange.failed audit event with a distinguishable reason, so spikes show up in the IT audit view.
Compromised app
Section titled “Compromised app”App-level compromise — code execution inside a pod via an upstream vulnerability — is bounded by the namespace and by what the pod holds. The app cannot reach other apps and cannot mint a new workload identity. It can currently reach the public internet: outbound restriction is not yet enforced (Network isolation is explicit about what holds today), so the bound on exfiltration is that the pod carries no upstream credential for a proxied integration rather than that the packet is dropped. It can use the integrations it was granted, which is the same thing the legitimate app could do; revoking those grants at the dashboard stops the bleeding immediately. For a proxied integration the pod holds only a workload key — no upstream secret — so a revoked grant cuts access on the very next call. For an injected integration the raw credential does live in the pod’s environment; revoking the grant cuts it at the app’s next deploy, and rotating the credential is one dashboard action. Narrowing that pod’s outbound to the one granted host is the planned addition.
Malicious pull request
Section titled “Malicious pull request”A PR that tries to slip a committed secret, an unapproved base image, a dependency carrying a critical vulnerability, or a manifest requesting data it was never granted past the gate fails the policy check. The author cannot self-merge; the policy check is enforced server-side, not just as a status hint. An override is possible for an org admin and is fully audited.
Leaked integration credential
Section titled “Leaked integration credential”Integration credentials live in the cloud-managed secret store, not in the control-plane database. A database leak does not produce a credential. For proxied integrations—the default for HTTP sources—a leak from an app pod does not produce the upstream credential either: the app never holds it, only the broker does, and the pod carries just a short-lived workload key. For an injected integration the credential is delivered into the pod’s environment by design, so a pod compromise exposes that one upstream; rotating the credential is one dashboard action.
Stolen end-user session
Section titled “Stolen end-user session”The audit log captures the user the agent or end user was acting as. Step-up authentication and session invalidation are the IdP’s responsibility and apply globally. Any session Greenlight issues — the dashboard cookie, a paired CLI session, an app preview session — is tied back to that user and is cut by deactivating them; there is no Greenlight-side session that outlives the user’s access.
What Greenlight does not claim
Section titled “What Greenlight does not claim”Greenlight protects against the scenarios above. It does not claim to:
- Protect against a compromised IdP. If your identity provider is owned, your trust assumptions are broken globally.
- Protect against a malicious cloud administrator. Anyone with administrative access to the installation’s cloud boundary can read its managed secrets, alter the control plane, and bypass application-layer controls.
- Protect against an insider with
org_adminrights misusing those rights. The audit log makes the misuse visible; it cannot prevent it.
These are the same caveats any in-cloud platform inherits. Greenlight is a governance layer on top of them, not a replacement for them.