Persistent Access to Private Security Policy YAML After Removal from victim user private project via securityPolicyProjectAssign Mutation
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
-
in private project >secure>policy> it create a security policy name - test from here victim can update or delete security policy
-
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
- Document this behavior in public docs. (Update documentation for security policy projects (!200404 - merged))
- 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))
- 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.