From a3279c352ab779742a9c6136a2eeac2fe3b132a3 Mon Sep 17 00:00:00 2001 From: Karan Kurani Date: Mon, 13 Apr 2026 23:32:12 +0530 Subject: [PATCH] recovery: add O_NOFOLLOW|O_EXCL to prevent symlink-following in recovery file creation WriteRecoveryInstructions() opens the recovery README with os.OpenFile using O_WRONLY|O_CREATE without O_NOFOLLOW. When fscrypt encrypt runs as root, this allows a local attacker to place a symlink at the recovery file path, causing root to write through the symlink and then fchown the target file to the attacker. Adding O_EXCL|O_NOFOLLOW aligns with the existing security pattern in filesystem.go:608 and filesystem.go:747. --- actions/recovery.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/actions/recovery.go b/actions/recovery.go index 2bb8a23d..3000be66 100644 --- a/actions/recovery.go +++ b/actions/recovery.go @@ -23,6 +23,7 @@ import ( "os" "strconv" + "golang.org/x/sys/unix" "google.golang.org/protobuf/proto" "github.com/google/fscrypt/crypto" @@ -91,7 +92,7 @@ func AddRecoveryPassphrase(policy *Policy, dirname string) (*crypto.Key, *Protec // passphrase in a different location if they actually need it. func WriteRecoveryInstructions(recoveryPassphrase *crypto.Key, recoveryProtector *Protector, policy *Policy, path string) error { - file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0600) + file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_EXCL|unix.O_NOFOLLOW, 0600) if err != nil { return err }