Intelligence

The Agent Has an Identity. So Does the Person Behind It. GitLab Requires Both.

GitLab 19.3, released 20 August 2026, removed the feature flag around composite identity and added a documented field for who authorized an agent's action. Composite identity itself is not new. GitLab's own documentation records it as introduced a year earlier, generally available months before 19.3, and automatic since. What is new is a system that can now show its work: an audit event attributed to a service account, with the human who authorized it recorded alongside it, and only for the execution surfaces where that identity mechanism actually runs.

Event analysed: . This analysis was published on 21 August 2026.

When GitLab's Duo Agent Platform runs a flow on a developer's behalf, whose permissions govern what it can touch, and can either the human or the service account end up with more access than they already had on their own?

Neither one, by design. GitLab's own documentation describes composite identity as combining a service account, the automated actor that performs the action, with the human user who initiated the request, into a single token. Authorization is intersectional: the flow can reach a project only if both the human and the service account already have access to it, and the effective role it runs with is whichever of the two roles is more restrictive. Attribution splits deliberately. Commits and the audit event author field name the service account, so automated activity is identifiable as automated. The human who triggered it is recorded alongside it, in the token's scope and, since GitLab 19.3, in a dedicated set of audit fields, so the action stays traceable to a person. GitLab's documentation is explicit that this mechanism applies only where flows and agents execute on runners, which covers foundational flows, custom flows and external agents. It does not apply to GitLab Duo Agentic Chat in the UI or IDE, which authenticates as the human user directly and relies on per call approval instead. Composite identity itself is not a 19.3 launch. GitLab's own documentation dates its introduction to GitLab 18.3, general availability to GitLab 18.8, and automatic inclusion in the Duo Agent Platform to GitLab 18.9, a full year before 19.3 removed the feature flag and added the audit attribution fields described here. Updated 27 August 2026: GitLab's own CVE-2026-18252 patch shows what composite identity does not cover. It can correctly bind a runner based flow to a service account and a human initiator while a separate failure lets the agent that flow runs, the Duo Claude agent, consume configuration from a source GitLab has not described as entitled to define what it executes, and GitLab's advisory says that produced arbitrary CI command execution for an authenticated Developer role user. GitLab does not describe composite identity itself as bypassed.

Update, 27 August 2026: This record now includes CVE-2026-18252, a Duo Claude agent vulnerability GitLab patched in versions 19.3.1, 19.2.5 and 19.1.7 on 26 August 2026, and a dedicated Authority Provenance ledger for it, in a new section before this record's closing pattern discussion. The original analysis of composite identity below, its mechanism, its history and its documented scope, is unchanged.

GitLab shipped version 19.3 on 20 August 2026, and the coverage that followed described a company scaling agentic AI across trusted software delivery workflows. That framing is easy to read as composite identity, GitLab's mechanism for authorizing what an AI agent can touch, arriving alongside it. GitLab's own documentation says otherwise, in enough detail to check. Composite identity is a year older than the release being covered. What 19.3 actually did to it is narrower, and more useful to understand precisely, than a launch.

What composite identity actually authorizes

GitLab's documentation defines composite identity as an authentication and authorization mechanism that combines two identities into a single token: a service account, described as the agent that performs the actual action, and a human user, the person who initiated the request. Every service account used by the Duo Agent Platform carries one, because every action a service account performs there was triggered by a human.

The authorization logic is intersectional, and GitLab's documentation uses that word. A flow has access to a project only if both the triggering user has access to it and the service account has been added to it. Role is resolved the same way: the flow runs with a one time composite identity combining the user's role and the service account's Developer role, whichever is more restrictive. GitLab's own example is direct. If the user is a Maintainer but the service account is a Developer, the flow runs as a Developer. Neither side can lend the other authority it does not already have, and neither side's access shrinks the other's floor. The documentation names this directly as what prevents privilege escalation by either the human user or the service account.

What is independently verified here comes from reading GitLab's own documentation source directly, not from GitLab's marketing description of it. Automated fetching of docs.gitlab.com and about.gitlab.com is blocked in Moona's tooling environment, so we retrieved the exact underlying documentation files, composite_identity.md, security_threats.md, ai-audit-events.md, audit_event_schema.md and flows/custom.md, directly from the gitlab-org/gitlab repository on gitlab.com, which is reachable and is the source those pages are built from. Every specific mechanism, table and history date in this piece is quoted or closely paraphrased from that material. We did not operate a live GitLab instance to confirm the documented behavior against a running deployment, so this is GitLab's documented design, independently read, not independently reproduced.

Attribution splits on purpose

GitLab's documentation lists three reasons composite identity matters: traceability, because agent activity is attributed to a service account and shows up as such in audit logs and commit histories; security, the intersectional access already described; and accountability, because the human user's identity is embedded in the token, creating an audit trail that links the action back to the person who initiated it. The example GitLab gives is a commit: ask an agent to write tests, and the resulting commit shows the service account as author, not the human who asked for it.

There is one documented exception, and it is deliberate. When a flow opens a merge request, GitLab attributes the merge request itself to the human user rather than the service account, specifically to satisfy compliance frameworks that require segregation of duties, including SOC 2, SOX, ISO 27001 and FedRAMP. Those frameworks generally require that the person who authored a change is not also the one who approves it for production. GitLab's documentation frames prompting an agent to write code as equivalent, for that purpose, to writing the code directly, so the human stays the accountable author of the merge request even though the service account created the commits inside it.

Where it runs, and where it deliberately does not

GitLab's security documentation is specific about scope, and the specificity is the part worth reading closely. Composite identity is used, in GitLab's own words, when flows and agents execute on runners: foundational flows, custom flows, external agents and any flow started through the workflow API endpoint. The same page states plainly that composite identity does not apply to GitLab Duo Agentic Chat in the UI and IDE.

GitLab's documentation lays out why the surfaces are treated differently rather than uniformly. It describes three execution modes with three different security postures. Flows that execute in GitLab Runner jobs run with an isolated sandbox, configurable network egress controls, composite identity as the acting identity, and no human in the loop requirement at all, because the sandboxing and scope restrictions are the control. IDE and CLI agents that run on a developer's own machine authenticate as the human user directly, carry no sandbox, and require the user to approve both write API tool calls and terminal commands before they execute. GitLab Duo Agentic Chat in the GitLab UI also authenticates as the human user, also carries no sandbox, and requires approval for write API tool calls, though it has no terminal to approve commands against. Composite identity, in other words, is the control GitLab uses precisely where a human is not standing in the loop watching each call. Where a human is watching, GitLab's documented design substitutes approval for identity separation instead of layering both.

GitLab's own risk table makes the same point from the attacker's side. It rates flows on GitLab CI as breaking what GitLab calls the lethal trifecta, sandboxing, scope restriction and tool limitation together, because private data access is scoped to the top level group and external communication is sandboxed. It rates both IDE and CLI agents and UI Agentic Chat as carrying the full trifecta when tool restrictions are not applied, with security relying primarily on human approval instead. That is GitLab's own risk assessment of its own product, not Moona's inference from it.

What actually happened on 20 August 2026

GitLab's documentation carries a version history for composite identity, and it does not start at 19.3. It was introduced in GitLab 18.3 behind a feature flag named duo_workflow_use_composite_identity, disabled by default. It was enabled by default in GitLab 18.6. It reached general availability in GitLab 18.8. Composite identity was made automatic in the Duo Agent Platform, with the manual on or off setting removed, in GitLab 18.9. GitLab's own repository shows the 18.3 tag dated 20 August 2025, one calendar year, to the day, before the 19.3 tag dated 20 August 2026. What GitLab 19.3 did to composite identity itself was remove the now redundant feature flag, a full year after the mechanism first shipped and roughly seven months after it became generally available.

What is genuinely new in 19.3, and independently confirmed against GitLab's audit documentation, is attribution the system did not previously expose in this form. GitLab's audit event schema documentation dates a new behavior to 19.3: when a service account acts under a composite identity, the audit event's author_id field carries the service account's user ID, author_name reads as the service account's name followed by "on behalf of" and the human user's username, and the event's author_class field is set to a value GitLab documents as usable to identify composite identity events specifically in a SIEM. Separately, GitLab's AI audit events documentation dates its own 19.3 addition: when an agent session runs under composite identity, which it describes as the default identity for agent sessions, the session's audit events are attributed to the service account as author, and the event's details field carries the human user's ID, name and username in dedicated fields. Neither of those additions changes who is authorized to act. Both change what a compliance team or SIEM can now read back out of the audit trail without inferring it from a service account's naming convention.

GitLab 19.3 also introduced a third visibility tier for custom flows, called Restricted, sitting between the existing public and private options. A restricted flow can be viewed and enabled by any project inside the same top level group as the flow's managing project, but not outside it, and GitLab's documentation notes a public flow cannot be converted to restricted once a project outside that group hierarchy has already turned it on. That is a governance boundary on who can see and reuse a flow, not an identity mechanism, and it sits in the same 19.3 release as the audit changes for a reason: both are the kind of control an organization asks for once agents are already running in production, rather than the kind a vendor ships to announce that agents can run at all.

What this record does not settle

This piece verifies what GitLab documents about its own system, read directly rather than through the company's own framing of it. It does not verify that the documented behavior holds under a running Duo Agent Platform deployment at scale, how many organizations have composite identity enforcing real authorization decisions today, or how the intersectional access rule behaves at the edges GitLab's documentation does not walk through, such as a service account added to a project after a flow has already been granted access to it elsewhere. GitLab's own documentation is also the only account we have of the mechanism's own history. We did not independently corroborate the 18.3 through 18.9 milestones against a second source, though the 18.3 and 19.3 tag dates in GitLab's own public repository, checked directly, are independent of GitLab's release messaging and confirm the one year gap the documentation's own history log describes.

CVE-2026-18252: what GitLab's own patch shows about configuration provenance

On 26 August 2026, GitLab published patch releases 19.3.1, 19.2.5 and 19.1.7 for CVE-2026-18252, an Inclusion of Functionality from Untrusted Control Sphere issue GitLab attributes to the Duo Claude AI agent. GitLab's own advisory language states the issue precisely: under certain conditions, an authenticated user with Developer role permissions could have executed arbitrary commands in a CI context, because the Claude agent processed configuration from a user-controlled source. GitLab records the affected range as GitLab EE from 18.9 before 19.1.7, 19.2 before 19.2.5 and 19.3 before 19.3.1, a CVSS 3.1 score of 7.3 (AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:N), and fixed versions 19.1.7, 19.2.5 and 19.3.1. GitLab.com already runs patched code, and GitLab states GitLab Dedicated customers require no separate action. This record treats the patch release page, the CVE record it documents, the eventual GitLab issue and any HackerOne report as one underlying development, consistent with how this record already treats a single artifact cited from more than one angle, rather than as separate pieces of market evidence.

The affected range is worth reading against what this record has already verified above. GitLab's documentation dates composite identity's move from optional to automatic, with the manual on or off setting removed, to GitLab 18.9, the same release CVE-2026-18252's affected range begins at. That is worth naming precisely, and also worth holding as a boundary rather than a conclusion. Composite identity is the mechanism GitLab uses to decide which project a flow can reach and which role it runs with. GitLab's own description of this vulnerability does not say that mechanism failed. It says a component downstream of that decision, the Claude agent, consumed configuration from a source GitLab has not described as entitled to define what the agent would then execute, and that consumption produced arbitrary commands in a CI context. Identity provenance, who a flow is authorized to act as and where, and configuration provenance, what is entitled to tell the agent what to do once it is acting, are different questions. GitLab's advisory describes a failure in the second one.

Precision matters here because it would be easy to overstate this. GitLab's advisory establishes an authenticated Developer role prerequisite, a user-controlled configuration source, Claude agent consumption of that configuration, and arbitrary command execution in a CI context. It does not establish, and this record does not claim, that composite identity itself was bypassed, that the attacker obtained Maintainer or Admin level access, that every project level authorization boundary was defeated, that the agent obtained access to the underlying host or cluster beyond its own CI job, or that this was exploited against a production instance before the patch. GitLab's own stated policy makes the underlying issue and any HackerOne report public 90 days after the patch release that fixed them; as of this update, three days after GitLab's own release date, Moona Intelligence found no public GitLab issue or HackerOne report for CVE-2026-18252, and this record does not guess at what either will eventually say.

What GitLab's advisory does not specify is exactly as important as what it does. GitLab's documentation, verified above, names execution surfaces that run under different security postures: foundational flows, custom flows and external agents, which execute on runners under composite identity, and GitLab Duo Agentic Chat in the UI and IDE, which authenticates as the human user directly and does not use composite identity at all. GitLab's own description of CVE-2026-18252, arbitrary commands in a CI context, places the failure inside the first group, the surfaces that actually run CI jobs, rather than inside chat or IDE agents, which do not execute inside a CI context in GitLab's own documented model. GitLab's advisory does not say which of foundational flows, custom flows or external agents specifically, or which execution path within them. This record states the affected agent surface as documented only at that level, CI-executing, runner based Duo Claude paths, and undocumented at the level of the specific flow type inside them, rather than treating the advisory's mention of the Duo Claude AI agent as coverage of the entire Duo Agent Platform.

The Authority Provenance ledger: CVE-2026-18252

Authority grantor. Distinct actors sit behind this failure, and GitLab's own composite identity model, verified above, is precisely what keeps them distinct rather than collapsing them into one. The human initiator is the authenticated Developer role user GitLab's advisory names as the actor who could trigger the failure. The service account is the identity GitLab's Duo Agent Platform attaches to a runner based flow's own actions. Project or group membership decides which resources either identity can reach. GitLab's own runner infrastructure is what actually executes the resulting commands. GitLab's advisory establishes the first of these, the human initiator's Developer role, directly. It does not establish, and this record does not infer, that the vulnerability altered which service account, project membership or runner scope applied to the resulting action; those remain the mechanism this record verifies above, operating as documented.

Mandate or basis. Undocumented at the level GitLab has disclosed. GitLab's advisory establishes that the Claude agent processed configuration from a user-controlled source. It does not name that source, whether a repository file, a branch, a CI configuration, an agent configuration record or something else, and this record does not guess at it. What can be stated precisely is the analytical question the vulnerability raises rather than answers: who was entitled to define the execution mandate the agent then consumed. A Developer role legitimately allows a user to modify certain project content. GitLab's advisory does not establish that the specific content this vulnerability turned into an execution mandate was the kind of content a Developer role is meant to author, only that the agent treated it as authoritative when it executed.

Delegated scope. Kept separate here on purpose, because composite identity and this vulnerability answer different questions about the same flow. Composite identity, verified above, may have continued to correctly constrain which project a flow could reach and which role it ran with, the intersectional access rule this record has already established. GitLab's advisory does not describe that resource level authorization as having failed. What it describes is a command executing inside the CI environment already available to the agent, a distinct question from which project or role that environment was scoped to. This record does not infer that resource authorization itself was defeated merely because command execution was unauthorized.

Explicit limits. GitLab's own documented execution model, verified above, describes flows on runners as running inside an isolated sandbox with configurable network egress controls, the two controls GitLab's own risk table credits with breaking what it calls the lethal trifecta for that surface. GitLab's advisory does not state that CVE-2026-18252 defeated sandboxing or egress control, and this record does not claim the agent obtained unrestricted host or cluster access. The vulnerability's significance does not depend on that claim: an arbitrary command executing inside the CI job's own intended sandbox is still an unauthorized command, confined or not.

Inherited permissions or assumptions. This is what CVE-2026-18252 is actually about. GitLab's own architecture let a component with CI execution authority, the Claude agent acting inside a runner based flow, consume configuration from a source GitLab's advisory does not describe as vetted for that purpose. An authenticated Developer role's legitimate ability to author certain project content is not the same fact as that content being entitled to redefine what an unattended agent then executes. GitLab's advisory does not say which Developer level write permission was involved, and this record preserves that as undocumented rather than naming one.

Revocation or modification. GitLab shipped software remediation in 19.1.7, 19.2.5 and 19.3.1. GitLab.com already runs patched code, and GitLab's release states GitLab Dedicated customers require no separate action. This record describes that as what it is, a patch that prevents the vulnerable path from recurring, not as revocation of any command that already executed under an affected version, and not as a claim that configuration caches or session state require invalidation; GitLab's own release material does not say either of those is necessary, and this record does not add a step GitLab did not publish.

Challenge authority. GitLab's own documentation, verified above, states that flows on runners do not require human in the loop approval at all; sandboxing and composite identity's scope restriction are the documented control instead. This record does not claim CVE-2026-18252 bypassed a human approval step, because GitLab's own architecture for this execution surface does not document one existing to bypass. The more precise description, and the one this record uses, is a trusted configuration and authority context provenance failure: unattended execution relying on scope restriction and identity separation, and a source outside that model still reaching the agent's execution mandate.

Challenge integrity. Not established as this vulnerability's subject. GitLab's advisory does not describe an approval or confirmation mechanism at all in connection with CVE-2026-18252, so this record has nothing to assess for whether such a mechanism, had one existed, would itself have held. This dimension stays unknown rather than assumed clean or assumed broken.

Recovery. GitLab's patch prevents the vulnerable behavior from recurring. It does not, and by its nature could not, undo an effect an arbitrary command already produced under an affected version before the fix. GitLab's own material does not describe a recovery process for such an effect, and this record represents that as undocumented and inherently specific to whatever resources a given organization's CI runners could reach, not as an omission this record can fill in.

Provenance evidence quality. Uneven, and stated in parts rather than as one figure. Strongly documented: GitLab's own patch release chronology, the CVE identifier, the affected and fixed version ranges, the CVSS 3.1 score and vector, the Developer role prerequisite, and the description of arbitrary CI command execution following the Claude agent's consumption of user-controlled configuration. Weakly documented or currently absent: the specific configuration source involved, which of foundational flows, custom flows or external agents was affected, whether the underlying GitLab issue exists yet in a form this record could read, and any account of exploitation, in the wild or otherwise. GitLab's own disclosure policy accounts for the gap rather than leaving it unexplained: GitLab states vulnerability issues are normally made public 90 days after the patched release, and CVE-2026-18252 is three days old as of this update. This record treats that gap as embargoed rather than absent, and states each unknown as unknown rather than narrowing it with an inference GitLab has not published.

Where this sits in the pattern

Moona Intelligence has tracked what happens to a human's authorization once an agent starts passing it down a chain, and what permissions travel with an agent that creates another agent. Composite identity is a different answer to a related question: what happens to authority the instant an agent acts for a human, once. GitLab's documented model does not resolve that by granting the agent the human's authority, or by granting the human the service account's. It authorizes the intersection of both, so a Maintainer whose service account only holds Developer access gets a Developer's worth of agent, not a Maintainer's, and a broadly scoped service account gets no more reach than the human who invoked it that time actually had. Where GitLab draws the line between identity separation and human approval is the more interesting part: composite identity replaces the human in the loop entirely on runner based flows, and approval replaces composite identity entirely on the surfaces where a person is already watching. Two different answers to the same underlying question, deployed on different surfaces of the same product, is a more precise description of what GitLab actually shipped than a single feature that arrived in August 2026. CVE-2026-18252 adds a third distinction to the same pattern rather than reopening either of the first two: identity provenance, which composite identity governs, is not configuration provenance, what is entitled to define an unattended agent's execution mandate once its identity is already settled. A patched Cursor vulnerability this record has covered separately turned on a related but distinct gap, an approved command's displayed text standing in for the environment it would actually run inside. GitLab's failure here is upstream of that one: not what an approved action does once it executes, but whether the configuration an unattended agent executed was ever entitled to define the mandate in the first place.

Corrections and updates

: Added coverage of CVE-2026-18252, disclosed by GitLab in patch releases 19.3.1, 19.2.5 and 19.1.7 on 26 August 2026: an authenticated Developer role user could, under certain conditions, cause the Duo Claude agent to execute arbitrary commands in a CI context after it processed configuration from a user-controlled source, CVSS 3.1 7.3 (AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:N). Direct fetch of docs.gitlab.com is blocked in this session, as it was for the sources already in this record, so GitLab's own advisory text is corroborated here through multiple independently phrased web searches that converged on identical wording, and through GitLab's own repository tag data confirming the 19.3.1 and 19.1.7 release commits were cut 25 August 2026, the day before GitLab's stated release date. Added a dedicated Authority Provenance ledger distinguishing identity provenance, which composite identity governs and which this vulnerability is not described as having defeated, from configuration provenance, which the vulnerability concerns: an authenticated Developer role's ordinary content permissions are not the same fact as being entitled to define an unattended agent's execution mandate. This record does not claim composite identity was bypassed, that the attacker gained Maintainer or Admin access, that host or cluster level access was obtained beyond the CI job's own sandbox, or that the vulnerability was exploited before the patch; GitLab's advisory does not establish any of those, and none is inferred here. The affected agent surface is stated as documented only at the level of CI-executing, runner based Duo Claude paths, not as a specific flow type, because GitLab's advisory does not name one. The underlying GitLab issue and HackerOne report were not found public as of this update, consistent with GitLab's own stated 90 day disclosure policy, and are preserved as undocumented rather than inferred. The original analysis of composite identity, its history and its documented scope is unchanged.

Sources

This analysis interprets third-party reporting, research and announcements. Moona is not the original reporter of the underlying events.

[1]
Composite identity
GitLab Docs · 20 August 2026 · Technical documentation
[2]
Security threats in agentic systems
GitLab Docs · 20 August 2026 · Technical documentation
[3]
Audit AI events
GitLab Docs · 20 August 2026 · Technical documentation
[4]
Audit event schema and examples
GitLab Docs · 20 August 2026 · Technical documentation
[5]
Custom flows
GitLab Docs · 20 August 2026 · Technical documentation
[6]
v19.3.0-ee
GitLab, gitlab-org/gitlab (GitLab.com) · 20 August 2026 · Primary source
[7]
GitLab Patch Release: 19.3.1, 19.2.5, 19.1.7
GitLab Docs · 26 August 2026 · Technical documentation
[8]
v19.3.1-ee
GitLab, gitlab-org/gitlab (GitLab.com) · 25 August 2026 · Primary source

Related Intelligence

All Intelligence Records →