{{ message }}
storage: dotgit, reject path traversal in reference names - #2254
Merged
pjbgf merged 2 commits intoJul 17, 2026
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a storage-layer validation to prevent path traversal via malicious reference names when DotGit reads/writes/removes loose refs under .git/<name>. This backports the v6 containment behavior into the v5 dotgit storage implementation.
Changes:
- Introduces
validReferenceNameand applies it toSetRef,Ref, andRemoveRefin dotgit storage. - Adds tests covering escaping reference names, including NTFS/HFS-disguised traversal patterns.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
pjbgf
force-pushed
the
v5-dotgit-ref-name-containment
branch
from
July 15, 2026 22:23
81e392c to
0ca956b
Compare
Backport of the v6 reference-name containment (go-git#2247) to v5. A loose reference is stored verbatim at ".git/<name>", so a name with a "." or ".." path component, a volume prefix, or a control character — for instance one advertised by a malicious remote and mapped through a refspec — could climb out of its reference sub-tree and read, overwrite, or delete unrelated metadata such as .git/config. validReferenceName guards SetRef, Ref and RemoveRef at the storage choke point. The per-component check is delegated to pathutil.IsHFSDot and pathutil.IsNTFSDot with "." as the needle, exactly as validSubmoduleName does, so besides bare "." and ".." it also rejects components that resolve to ".." after HFS+ Unicode normalisation or NTFS trailing-space/period/ADS canonicalisation (e.g. "..::$INDEX_ALLOCATION", ".<U+200C>."). Both checks run unconditionally since a name can be authored on one OS and reach this layer on another. v5 has no reflog storage methods, so only the three reference entry points are guarded. Assisted-by: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Paulo Gomes <paulo@entire.io>
Add plumbing.ReferenceName.IsSafe, mirroring Git's refname_is_safe (refs.c): a name is safe only when it lives under refs/ without escaping the sub-tree, or is a one-level [A-Z_] pseudo-ref (HEAD, ORIG_HEAD, ...). validReferenceName now gates on IsSafe before its filesystem-specific hardening (control characters, NTFS/HFS ".." disguises). This closes the remaining gap where a single-level name such as "config" or "index" would resolve onto top-level .git metadata, while still accepting the pseudo-refs and refs/ names real callers use. The check stays at the filesystem storage boundary, matching upstream; the in-memory backend is intentionally left permissive. The storage conformance suite used bare single-level names (foo, bar) that are invalid on a filesystem ref store; these now use refs/ names. Assisted-by: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Paulo Gomes <paulo@entire.io>
pjbgf
force-pushed
the
v5-dotgit-ref-name-containment
branch
from
July 17, 2026 15:35
0ca956b to
3b306ef
Compare
Sirherobrine23
pushed a commit
to Sirherobrine23/gitea-runner
that referenced
this pull request
Aug 8, 2026
…rity] (#1156) This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [github.com/go-git/go-git/v5](https://github.com/go-git/go-git) | `v5.19.1` → `v5.19.2` |  |  | --- ### go-git: Worktree operations may follow symlinks [CVE-2026-71556](https://nvd.nist.gov/vuln/detail/CVE-2026-71556) / [GHSA-hc8v-wwc9-vgxm](GHSA-hc8v-wwc9-vgxm) <details> <summary>More information</summary> #### Details ##### Impact A symlink traversal issue in `go-git` could allow worktree operations to modify files outside the intended worktree path. The `worktreeFilesystem` wrapper rejected dangerous path strings, including paths containing `.git`, parent-directory components, or control characters. However, it did not prevent filesystem operations from following symbolic links that were already present in the worktree. As a result, a path that is safe when evaluated as a string could still resolve into the repository's Git metadata directory. For example, if `s` is a symbolic link to `.git`, writing to `s/config` would modify `.git/config`. A symbolic link at the final path component could also be followed. For example, if `s` points directly to `.git/config`, opening `s` for writing with truncation could overwrite the repository configuration. Exploitation requires an attacker to be able to introduce or control a symbolic link in the worktree and cause the application to perform a write through that path. Applications using `storage/memory` for their Storer, or `go-billy/memfs` for their `Worktree`, are not affected by this vulnerability. ##### Patches The issue has been addressed by making the worktree filesystem wrapper a symlink-safe boundary. Worktree operations now reject paths where an existing symbolic link in any path component could cause the operation to escape the intended worktree location, including symbolic links at the final component. Users of filesystem-backed worktrees should upgrade to a patched version. ##### Credits Thanks to @​kodareef5 for reporting this issue and working with the go-git security team toward its resolution. 🥇 We would also like to thank @​HughLewis20, who independently reported the same issue while a fix was already in progress. #### Severity - CVSS Score: 7.1 / 10 (High) - Vector String: `CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:L` #### References - [https://github.com/go-git/go-git/security/advisories/GHSA-hc8v-wwc9-vgxm](https://github.com/go-git/go-git/security/advisories/GHSA-hc8v-wwc9-vgxm) - [https://github.com/go-git/go-git/commit/008a78f2dd86f52544ddff8b8e8ddeecdf3f7aab](https://github.com/go-git/go-git/commit/008a78f2dd86f52544ddff8b8e8ddeecdf3f7aab) - [https://github.com/go-git/go-git/commit/661d1c7f101d34e002a3cfcf8dbea5b7421d07ac](https://github.com/go-git/go-git/commit/661d1c7f101d34e002a3cfcf8dbea5b7421d07ac) - [https://github.com/go-git/go-git](https://github.com/go-git/go-git) - [https://github.com/go-git/go-git/releases/tag/v5.19.2](https://github.com/go-git/go-git/releases/tag/v5.19.2) - [https://github.com/go-git/go-git/releases/tag/v6.0.0-alpha.5](https://github.com/go-git/go-git/releases/tag/v6.0.0-alpha.5) This data is provided by [OSV](https://osv.dev/vulnerability/GHSA-hc8v-wwc9-vgxm) and the [GitHub Advisory Database](https://github.com/github/advisory-database) ([CC-BY 4.0](https://github.com/github/advisory-database/blob/main/LICENSE.md)). </details> --- ### go-git: Malicious reference names may modify files outside the reference storage [CVE-2026-71557](https://nvd.nist.gov/vuln/detail/CVE-2026-71557) / [GHSA-qgq7-7hm3-q39j](GHSA-qgq7-7hm3-q39j) <details> <summary>More information</summary> #### Details ##### Impact A path traversal issue in `go-git` could allow malicious reference names to access files outside the repository's intended reference storage. Loose references are stored under `.git/<reference-name>`. The reference name was previously used as a path without verifying that the resolved path remained within the reference storage. A name such as `refs/heads/../../config` could therefore resolve to unrelated repository metadata such as `.git/config` or `.git/HEAD`. A malicious Git server could advertise such a reference name. The name may also survive refspec mapping; for example, it could be mapped to `refs/remotes/origin/../../config` during a clone or fetch operation. This vulnerability affects filesystem-backed repositories using the `storage/filesystem` package and its `dotgit` reference storage. Users relying exclusively on the in-memory storage implementation, `storage/memory`, are not affected, because reference names are not resolved as filesystem paths. Exploitation requires an application using `go-git` with filesystem-backed storage to interact with a malicious Git server or otherwise process attacker-controlled reference names. ##### Patches The issue has been addressed by validating reference names at the `dotgit` storage entry points and rejecting names whose resolved paths could escape the reference storage. Users of filesystem-backed storage should upgrade to a patched version. ##### Workarounds Applications that exclusively use `storage/memory` are not affected and do not require a workaround for this vulnerability. For applications using filesystem-backed storage, avoid cloning from or fetching from untrusted Git servers until an upgrade is possible. Applications that directly construct or process reference names may also validate them before passing them to filesystem-backed `go-git` storage. Application-level validation should only be considered a temporary mitigation and does not replace upgrading to a patched version. ##### References - Fixes: - go-git/go-git#2247 - go-git/go-git#2254 ##### Credits Thanks to @​Saku0512 for reporting this issue and @​Sahana2524 for proposing the initial fix. 🙇 #### Severity - CVSS Score: 6.3 / 10 (Medium) - Vector String: `CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:L` #### References - [https://github.com/go-git/go-git/security/advisories/GHSA-qgq7-7hm3-q39j](https://github.com/go-git/go-git/security/advisories/GHSA-qgq7-7hm3-q39j) - [https://github.com/go-git/go-git/pull/2247](https://github.com/go-git/go-git/pull/2247) - [https://github.com/go-git/go-git/pull/2254](https://github.com/go-git/go-git/pull/2254) - [https://github.com/go-git/go-git/commit/4a0e66d555de5f9a30c31e2df64f445f42bd01e7](https://github.com/go-git/go-git/commit/4a0e66d555de5f9a30c31e2df64f445f42bd01e7) - [https://github.com/go-git/go-git/commit/da9f7d8a0e98b475600177348d6ece384a370f36](https://github.com/go-git/go-git/commit/da9f7d8a0e98b475600177348d6ece384a370f36) - [https://github.com/go-git/go-git](https://github.com/go-git/go-git) - [https://github.com/go-git/go-git/releases/tag/v5.19.2](https://github.com/go-git/go-git/releases/tag/v5.19.2) - [https://github.com/go-git/go-git/releases/tag/v6.0.0-alpha.5](https://github.com/go-git/go-git/releases/tag/v6.0.0-alpha.5) This data is provided by [OSV](https://osv.dev/vulnerability/GHSA-qgq7-7hm3-q39j) and the [GitHub Advisory Database](https://github.com/github/advisory-database) ([CC-BY 4.0](https://github.com/github/advisory-database/blob/main/LICENSE.md)). </details> --- ### Release Notes <details> <summary>go-git/go-git (github.com/go-git/go-git/v5)</summary> ### [`v5.19.2`](https://github.com/go-git/go-git/releases/tag/v5.19.2) [Compare Source](go-git/go-git@v5.19.1...v5.19.2) #### What's Changed - build: Update module golang.org/x/crypto to v0.52.0 \[SECURITY] (releases/v5.x) by [@​go-git-renovate](https://github.com/go-git-renovate)\[bot] in [#​2150](go-git/go-git#2150) - build: Update module github.com/go-git/go-git/v5 to v5.19.1 \[SECURITY] (releases/v5.x) by [@​go-git-renovate](https://github.com/go-git-renovate)\[bot] in [#​2141](go-git/go-git#2141) - build: Update module golang.org/x/net to v0.55.0 \[SECURITY] (releases/v5.x) by [@​go-git-renovate](https://github.com/go-git-renovate)\[bot] in [#​2152](go-git/go-git#2152) - git: Worktree: Add stores index entires with backslashes on Windows by [@​joshblum](https://github.com/joshblum) in [#​2262](go-git/go-git#2262) - storage: dotgit, reject path traversal in reference names by [@​pjbgf](https://github.com/pjbgf) in [#​2254](go-git/go-git#2254) - build: Update module golang.org/x/net to v0.56.0 \[SECURITY] (releases/v5.x) by [@​go-git-renovate](https://github.com/go-git-renovate)\[bot] in [#​2267](go-git/go-git#2267) - build: Update module golang.org/x/text to v0.39.0 \[SECURITY] (releases/v5.x) by [@​go-git-renovate](https://github.com/go-git-renovate)\[bot] in [#​2268](go-git/go-git#2268) - \[v5] git: worktree, make the filesystem wrapper a symlink-safe boundary by [@​pjbgf](https://github.com/pjbgf) in [#​2277](go-git/go-git#2277) **Full Changelog**: <go-git/go-git@v5.19.1...v5.19.2> </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - "" - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xOTEuMiIsInVwZGF0ZWRJblZlciI6IjQzLjE5MS4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119--> --------- Co-authored-by: silverwind <2021+silverwind@noreply.gitea.com> Reviewed-on: https://gitea.com/gitea/runner/pulls/1156 Reviewed-by: silverwind <2021+silverwind@noreply.gitea.com> Co-authored-by: Renovate Bot <renovate-bot@gitea.com>
This was referenced Aug 8, 2026
This was referenced Aug 18, 2026
This was referenced Aug 21, 2026
This was referenced Aug 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Backport of the v6 reference-name containment (#2247 and #2257) to v5.
A loose reference is stored verbatim at
.git/<name>, so a name with a.or..path component, a volume prefix, or a control character — for instance one advertised by a malicious remote and mapped through a refspec — could climb out of its reference sub-tree and read, overwrite, or delete unrelated metadata such as .git/config. validReferenceName guards SetRef, Ref and RemoveRef at the storage choke point.The per-component check is delegated to
pathutil.IsHFSDotandpathutil.IsNTFSDotwith.as the needle, exactly asvalidSubmoduleNamedoes, so besides bare.and..it also rejects components that resolve to..afterHFS+Unicode normalisation or NTFS trailing-space/period/ADS canonicalisation (e.g...::$INDEX_ALLOCATION,.<U+200C>.). Both checks run unconditionally since a name can be authored on one OS and reach this layer on another.