Reject SCP receive through pre-existing symlinks#1034
Open
yosuke-wolfssl wants to merge 1 commit into
Open
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR mitigates an SCP receive path-traversal vulnerability where an authenticated peer could escape the configured destination directory by targeting pre-existing symlinks (directory or file) during uploads. It adds symlink rejection in the SCP receive callback and factors existing SFTP symlink detection into a shared helper for consistent confinement behavior.
Changes:
- Add symlink guards to SCP receive path handling for both directory entry (NEW_DIR) and file creation (NEW_FILE).
- Promote SFTP’s symlink detection into a shared
wIsSymlink()helper (with feature/build gating) and reuse it in SFTP confinement checks. - Add a unit regression test covering both symlinked-directory and symlinked-file escape attempts.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
src/wolfscp.c |
Rejects SCP receive operations that would follow pre-existing symlinks when entering directories or opening files. |
src/wolfsftp.c |
Replaces the local symlink check with shared wIsSymlink() for SFTP path confinement. |
src/port.c |
Introduces shared cross-platform wIsSymlink() implementation (POSIX lstat / Windows reparse point attributes). |
wolfssh/port.h |
Declares wIsSymlink() behind WOLFSSH_HAVE_SYMLINK and SFTP/SCP feature gates. |
tests/unit.c |
Adds regression test ensuring SCP receive aborts when a planted symlink would escape the destination. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
0127e25 to
a47d723
Compare
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #1034
Scan targets checked: wolfssh-bugs, wolfssh-src
No new issues found in the changed files. ✅
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 a path-traversal vulnerability in the default SCP receive callback
wsScpRecvCallback().On POSIX and Windows builds, an authenticated SCP peer could write outside the destination directory by uploading into a pre-existing symlink.
In the
WOLFSSH_SCP_NEW_DIRhandler,WMKDIRreturningEEXISTwas silently accepted and the subsequentWCHDIRfollowed a planted symlink, moving the working directory outsidescpBasePath; every laterWFOPENthen wrote to the escaped location.A pre-existing file symlink was likewise followed by the
WOLFSSH_SCP_NEW_FILEopen.GetScpFileNamerejects..and/but offers no protection against valid-named symlinks, so a peer with a planted symlink (via SFTPSSH_FXP_SYMLINK, a shell session, or another upload mechanism) could write to arbitrary filesystem locations.The
WOLFSSL_NUCLEUSpath was unaffected as it builds an absolute path and runswolfSSH_CleanPath.Addressed by f_4660.
Changes
WCHDIR(fileName)(directory case) and beforeWFOPEN(fileName, "wb")(file case) that refuses to follow a symlink, mirroring the symlink defense already used by SFTP. The guards compile out whereWOLFSSH_HAVE_SYMLINKis undefined, so link-less embedded filesystems are unchanged.SFTP_IsSymlinkcheck to a singlewIsSymlink()inport.c(declared inport.h), and call it from both the SCP and SFTP path-confinement paths. The name follows the cross-platformw*convention inport.h(wStat,wMkDir, …);WS_*is reserved for the Windows-API emulation shims.wIsSymlink()lives in the always-compiledport.c, but its filesystem dependencies (WSTAT_T/WLSTAT/S_ISLNKon POSIX,WS_GetFileAttributesExAon Windows) and its only callers exist solely in the SFTP/SCP code. Gated it on(WOLFSSH_SFTP || WOLFSSH_SCP)in addition toWOLFSSH_HAVE_SYMLINKso a default./configurebuild (no SFTP/SCP/SSHD) still compiles.test_ScpRecvCallback_SymlinkGuardtotests/unit.c, covering both the directory and file symlink cases plus positive controls for normal new directory/file creation.Files
src/wolfscp.c— symlink guards inWOLFSSH_SCP_NEW_DIR/WOLFSSH_SCP_NEW_FILEsrc/wolfsftp.c— use sharedwIsSymlink()inGetAndCleanPath()src/port.c,wolfssh/port.h— sharedwIsSymlink()helper + feature gatetests/unit.c— regression testChangeLog.md— vulnerability entryTesting
make checkpasses for default,--enable-scp,--enable-sftp, and--enable-scp --enable-sftpbuilds.(negative control confirms it catches the bug).
scripts/scp.testend-to-end passes (normal SCP dir/file uploads still work).tests/unit.testis clean (no use-after-free, overflow,or runtime-error reports).
./configure && make(no SFTP/SCP/SSHD) compiles, confirming thebuild gate.