Persistent Access to Private Security Policy YAML After Removal from victim user private project via securityPolicyProjectAssign Mutation

⚠️ Please read the process on how to fix security issues before starting to work on the issue. Vulnerabilities must be fixed in a security mirror.

HackerOne report #3166143 by weasterhacker on 2025-05-28, assigned to @fvpotvin:

Report | Attachments | How To Reproduce

Report

Hi team,

A business logic vulnerability in the securityPolicyProjectAssign GraphQL mutation allows a removed project member to persistently access and view updated security policy YAML content from a private project, despite no longer having the required Reporter role to access such data. Specifically, an attacker with initial Reporter access to a victim’s private project can link the victim project’s security policy to their own project. Even after the victim removes the attacker, the attacker can still view updates to the security policy YAML content (e.g., security_policy.yml) in their own project. This violates GitLab’s access controls, as the Reporter role is explicitly required to view the YAML code or security policy of a private project, and persists access after revocation, posing a significant risk of sensitive data exposure.

This issue is related to a previously fixed vulnerability (GitLab Issue #416647 (closed), #416647 (closed)), which likely addressed a similar unauthorized access issue but did not fully mitigate persistence of access after permission revocation.

The securityPolicyProjectAssign GraphQL mutation allows a user to assign a security policy project to a target project or group. According to GitLab’s documentation at https://docs.gitlab.com/user/application_security/policies/#link-to-a-security-policy-project, the following permissions are required:

The user must have the Owner role or a custom role with the manage_security_policy_link permission for the target project being linked.

The user must have at least the Reporter role or a custom role with the manage_security_policy_link permission for the project being assigned as the security policy project.

Additionally, to view the YAML code or security policy of a private project (e.g., the security_policy.yml file), a user must have at least the Reporter role in that project. This ensures that only authorized users with sufficient permissions can access sensitive security policy details, which may include scan configurations, approval settings, and other security-related rules.

Note-

The previous CVE recognized unauthorized access to security policy YAML as a vulnerability. In GitLab’s issue tracker for #416647 (closed) (comment 1452019550), comments specify that the security policy YAML could contain sensitive variables, which should be considered a vulnerability. Dominic Bauer explains:

“I believe we could consider it as a vulnerability, as potential variables could be stored in these policies and leaked as a result.”

Therefore, this report should also be treated as a vulnerability.

I identified a business logic flaw where an attacker can exploit this mutation to gain persistent access to a private project’s security policy YAML content, even after being removed and no longer holding the required Reporter role:

1.Initial Access and Linking:

The attacker, initially invited as a Reporter to the victim’s private project (victim-corp/private-project), uses the securityPolicyProjectAssign mutation to link the victim private's as the security policy for their own project (attacker-corp/attacker-project).

The mutation succeeds because the attacker has the Reporter role in the victim project (satisfying the minimum requirement for the security policy project) and the Owner role in their own project (satisfying the requirement for the target project).

2.Permission Revocation:

The victim removes the attacker from the private project, revoking their Reporter role and all access. At this point, the attacker no longer meets the requirement of having at least the Reporter role to view the YAML code or security policy of the private project.

3.Persistent Access to Updated YAML:

The victim updates the security policy YAML content in their project (e.g., modifying security_policy.yml).

Despite no longer having the required Reporter role or any access to the victim private project, the attacker can still view the updated YAML content in their own project under “Secure > Policies,” as the link between the attacker’s project and the victim’s security policy project persists.

This behavior indicates that GitLab does not re-check permissions to the security policy project when its policies are accessed or enforced on the linked project, allowing the attacker to retain unauthorized access to sensitive security policy updates after revocation, in violation of the explicit requirement for the Reporter role to view such data.

Steps to Reproduce:

Step 1: Set Up the Victim User and Project:

1.The victim user creates a private group (e.g., victim-corp).

2.Within this group, the victim creates a new private project (e.g., victim-corp/victim-private-project).

3.The victim sets up a security policy in this project with the following YAML configuration in security_policy.yml:

approval_policy:    
- name: test    
  description: test    
  enabled: true    
  rules:    
  - type: any_merge_request    
    branch_type: protected    
    commits: any    
  actions:    
  - type: require_approval    
    approvals_required: 1    
    role_approvers:    
    - owner    
  - type: send_bot_message    
    enabled: true    
  approval_settings:    
    block_branch_modification: true    
    prevent_pushing_and_force_pushing: true    
    prevent_approval_by_author: true    
    prevent_approval_by_commit_author: true    
    remove_approvals_with_new_commit: true    
    require_password_to_approve: false    
  fallback_behavior:    
    fail: closed  
  1. in private project >secure>policy> it create a security policy name - test from here victim can update or delete security policy

  2. it also create a private project -security project (for merging changes in security policy at victim private project security policy

Step 2: Invite the Attacker as a Reporter

6.The victim user invites the attacker (e.g., User B) to the victim private project with Reporter permissions.

Step 3: Attacker Creates Their Own Group and Project

7.The attacker creates a new group (e.g., attacker-corp) and a new project within this group (e.g., attacker-corp/attacker-project).

Step 4: Exploit the Vulnerability via GraphQL

8.The attacker executes the following GraphQL mutation to assign the victim’s security policy project to their own project:


mutation {    
  securityPolicyProjectAssign(input: { fullPath: "attacker-corp/attacker-project", securityPolicyProjectId: "gid://gitlab/Project/64192849" }) {    
    errors    
  }    
}

9.gid://gitlab/Project/64192849 is the Global ID of the victim’s private security policy project (victim-corp/victim-security-policy-project).

10.The mutation succeeds (errors: []), linking the victim project’s security policy to the attacker’s project.

11.The attacker navigates to “Secure > Policies” in their project (attacker-corp/attacker-project) and verifies that the security policy YAML content from the victim project is visible.

Step 5: Victim Removes the Attacker and Updates the Security Policy

12.The victim user removes the attacker from the victim private project and also from victim-security-policy-project, revoking their Reporter role and all access to the project.

13.The victim updates the security policy YAML content in the victim project, such as modifying the security_policy.yml file (e.g., changing the approvals_required to 2 or adding a new rule).

Step 6: Verify Persistent Access

14.The attacker, now with no access to the victim project and lacking the required Reporter role, navigates to “Secure > Policies” in their project (attacker-corp/attacker-project).

15.The attacker can view the updated YAML content of the victim project’s security policy, despite no longer having the necessary permissions to access such data in a private project.

Comparison to Fixed Issue:

This issue is related to GitLab Issue #416647 (closed), which likely addressed unauthorized access to private project data but did not fully mitigate persistence of access after permission revocation. The ability to view updated YAML content post-removal, despite the explicit requirement for the Reporter role, indicates that the fix for #416647 (closed) was incomplete

This issue is related to GitLab Issue #502857 (closed),IDOR in securityPolicyProjectAssign Mutation Allows Guest User to Read Security Policy YAML

video poc :

Impact

Impact:

This vulnerability has severe security implications due to the persistence of access and exposure of sensitive data:

Persistent Unauthorized Access:

After being removed from the victim project, the attacker retains the ability to view updates to the victim project’s security policy YAML content through their own project. This explicitly violates GitLab’s access controls, as the Reporter role is required to view the YAML code or security policy of a private project, and the attacker no longer holds this role.

The attacker can monitor sensitive changes to the security policy, including:

New scan configurations (e.g., types of vulnerabilities being scanned).

Policy scopes or exclusions, revealing the victim project’s security posture.

Approval settings or rules and code that might indicate operational security practices.

Data Exposure and Potential Exploitation:

The exposed YAML Code content may contain sensitive information about the victim project’s security practices, which the attacker can use for targeted attacks (e.g., identifying weaknesses in scan configurations or approval workflows).

If the security policies trigger scans or actions on the attacker’s project, the attacker might gain further insights (e.g., scan results or enforcement logs) that indirectly expose vulnerabilities in the victim project.

Attachments

Warning: Attachments received through HackerOne, please exercise caution!

How To Reproduce

Please add reproducibility information to this section:

Solution

  1. Document this behavior in public docs. (Update documentation for security policy projects (!200404 - merged))
  2. Create Epic and plan adding ability in UI for SPP owner to see what projects/groups are linked and give them option to revoke unwanted links. (Allow SPP owners more control over links (&18809))
  3. As a part of Policies v2: Reimagining Security Policy Manage... (&16664) we will have different approach for that; there will be no links at the Security Policy Project level; every policy will have it's own members with granular access controls.
Edited by Alexander Turinske