fix(cmd): use restrictive file permissions for exported keys (#11246)
`ipfs key export` was using `os.Create` (0o666 pre-umask, typically 0o644) making exported private keys world-readable on multi-user systems. Use `os.OpenFile` with 0o600 to match the restrictive permissions the keystore itself uses for key files.
Marcin Rataj committed
Mar 24, 2026 at 16:26 UTC
14fc754df8cebaef85de108171f7e738afd0da44
2 files changed
+48
-2
core/commands/keystore.go
+2
-2
@@ -269,8 +269,8 @@ elsewhere. For example, using openssl to get a PEM with public key:
269
outPath = filepath.Clean(outPath)
270
}
271
272
- // create file
273
- file, err := os.Create(outPath)
272
+ // create file with owner-only permissions to protect private key material
273
+ file, err := os.OpenFile(outPath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o600)
274
if err != nil {
275
return err
276
}
test/cli/key_test.go
new
+46
@@ -0,0 +1,46 @@
1
+package cli
2
+
3
+import (
4
+ "os"
5
+ "path/filepath"
6
+ "runtime"
7
+ "testing"
8
+
9
+ "github.com/ipfs/kubo/test/cli/harness"
10
+ "github.com/stretchr/testify/assert"
11
+ "github.com/stretchr/testify/require"
12
+)
13
+
14
+func TestKeyExportFilePermissions(t *testing.T) {
15
+ t.Parallel()
16
+
17
+ if runtime.GOOS == "windows" {
18
+ t.Skip("Unix file permissions not applicable on Windows")
19
+ }
20
+
21
+ node := harness.NewT(t).NewNode().Init()
22
+
23
+ node.IPFS("key", "gen", "--type=ed25519", "testkey")
24
+
25
+ t.Run("libp2p-protobuf-cleartext format", func(t *testing.T) {
26
+ t.Parallel()
27
+ exportPath := filepath.Join(t.TempDir(), "testkey.key")
28
+ node.IPFS("key", "export", "testkey", "-o", exportPath)
29
+
30
+ info, err := os.Stat(exportPath)
31
+ require.NoError(t, err)
32
+ assert.Equal(t, os.FileMode(0o600), info.Mode().Perm(),
33
+ "exported key file should have owner-only permissions")
34
+ })
35
+
36
+ t.Run("pem-pkcs8-cleartext format", func(t *testing.T) {
37
+ t.Parallel()
38
+ exportPath := filepath.Join(t.TempDir(), "testkey.pem")
39
+ node.IPFS("key", "export", "testkey", "-o", exportPath, "-f", "pem-pkcs8-cleartext")
40
+
41
+ info, err := os.Stat(exportPath)
42
+ require.NoError(t, err)
43
+ assert.Equal(t, os.FileMode(0o600), info.Mode().Perm(),
44
+ "exported PEM key file should have owner-only permissions")
45
+ })
46
+}