fix(publish): sanitize server-controlled artifact path (GHSA-x55v-q459-68ch)#4989
Merged
proggeramlug merged 2 commits intoJun 11, 2026
Merged
Conversation
added 2 commits
June 11, 2026 11:48
…9-68ch) perry publish trusted the build server's ArtifactReady.artifact_name and download_path verbatim when constructing the local destination path. Because PathBuf::join does not normalize .. or reject absolute paths, a malicious hub could write downloaded content anywhere the process can write (e.g. ../../.ssh/authorized_keys), and in the self-hosted-hub local-copy path could also copy out arbitrary local files via a server-chosen download_path. - sanitize_artifact_name() reduces artifact_name to a bare, traversal-free file name (rejects absolute paths, ., .., and embedded separators) before it is joined onto the output directory. Closes the arbitrary-write vector. - server_is_local() gates the download_path local-copy shortcut to loopback hubs only; a remote hub's local filesystem path is never honored, closing the arbitrary local-file-read vector. Remote hubs fall back to HTTP download. Adds unit tests covering accepted names, traversal payloads, and the loopback gate.
proggeramlug
added a commit
that referenced
this pull request
Jun 11, 2026
Security release. Bumps [workspace.package].version 0.5.1158 -> 0.5.1159 (+ Cargo.lock, CLAUDE.md version line) and prepends a v0.5.1159 CHANGELOG entry. The only code change since v0.5.1158 is #4989, which fixes a path traversal / arbitrary file write in perry publish (GHSA-x55v-q459-68ch). After merge: tag v0.5.1159 + publish the GitHub release, then set the advisory's patched version to 0.5.1159 and publish it. Co-authored-by: Ralph Küpper <ralph@skelpo.com>
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.
Summary
Fixes the path-traversal / arbitrary-file-write reported in GHSA-x55v-q459-68ch.
perry publishprocessesArtifactReadyWebSocket messages from the build server and used the server-suppliedartifact_name(anddownload_path) verbatim when building the local destination path. SincePathBuf::joindoes not normalize..or reject absolute paths, a malicious/compromised hub could:artifact_name = "../../.ssh/authorized_keys"(or an absolute path) and have downloaded content written anywhere the process can write.download_pathto any local file (e.g.~/.aws/credentials) and have it copied into the output directory.The primary multi-victim vector is a malicious PR setting
[publish] server = "https://attacker…"in a repo'sperry.toml; CI runs (--no-interactive/ non-TTY) get no confirmation prompt.Fix
sanitize_artifact_name()reduces the server-supplied name to a single, traversal-free file name (rejects empty,.,.., embedded/or\, absolute/drive-prefixed paths) before it's joined onto the output dir. This closes the arbitrary-write vector for both paths.server_is_local()gates thedownload_pathlocal-copy shortcut to loopback hubs only (localhost,127.0.0.0/8,::1). A remote hub's local filesystem path is meaningless and is no longer honored — remote hubs fall back to the existing HTTP download. This closes the arbitrary local-file-read vector.Tests
Added unit tests in
commands/publish/tests.rs:localhost/127.0.0.1/[::1]allowed; public hosts, private LAN IPs, and unparseable URLs rejected)cargo test -p perry --bins publish::tests→ 27 passed, 0 failed.Notes
download_pathwill transparently fall back to HTTP download.