@cryptotaxi247 / kubo / commits / 14fc754df

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 +}