From f3a5642236eaecd30d7995e07ffc0194fdf547f9 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Sat, 30 Aug 2025 00:40:25 +0200 Subject: [PATCH 01/10] fix: enforce identity CID size limits - validate --inline-limit against verifcid.MaxDigestSize - add error when --hash=identity exceeds size limit - add tests for identity CID overflow scenarios - update help text to show maximum inline limit This prevents creation of unbounded identity CIDs by enforcing the 128-byte limit defined in verifcid.MaxDigestSize. Fixes #6011 --- core/commands/add.go | 9 +- core/commands/files.go | 1 + docs/examples/kubo-as-a-library/go.mod | 2 +- docs/examples/kubo-as-a-library/go.sum | 4 +- go.mod | 2 +- go.sum | 4 +- test/cli/identity_cid_test.go | 310 +++++++++++++++++++++++++ test/dependencies/go.mod | 2 +- test/dependencies/go.sum | 4 +- 9 files changed, 328 insertions(+), 10 deletions(-) create mode 100644 test/cli/identity_cid_test.go diff --git a/core/commands/add.go b/core/commands/add.go index b24eab0833d..662476a93b7 100644 --- a/core/commands/add.go +++ b/core/commands/add.go @@ -16,6 +16,7 @@ import ( "github.com/ipfs/boxo/files" mfs "github.com/ipfs/boxo/mfs" "github.com/ipfs/boxo/path" + "github.com/ipfs/boxo/verifcid" cmds "github.com/ipfs/go-ipfs-cmds" ipld "github.com/ipfs/go-ipld-format" coreiface "github.com/ipfs/kubo/core/coreiface" @@ -203,7 +204,7 @@ https://github.com/ipfs/kubo/blob/master/docs/config.md#import cmds.IntOption(maxHAMTFanoutOptionName, "Limit the maximum number of links of a UnixFS HAMT directory node to this (power of 2, multiple of 8). WARNING: experimental, Import.UnixFSHAMTDirectorySizeThreshold is safer. Default: Import.UnixFSHAMTDirectoryMaxFanout"), // Experimental Features cmds.BoolOption(inlineOptionName, "Inline small blocks into CIDs. WARNING: experimental"), - cmds.IntOption(inlineLimitOptionName, "Maximum block size to inline. WARNING: experimental").WithDefault(32), + cmds.IntOption(inlineLimitOptionName, fmt.Sprintf("Maximum block size to inline. Maximum: %d bytes. WARNING: experimental", verifcid.MaxIdentityDigestSize)).WithDefault(32), cmds.BoolOption(noCopyOptionName, "Add the file using filestore. Implies raw-leaves. WARNING: experimental"), cmds.BoolOption(fstoreCacheOptionName, "Check the filestore for pre-existing blocks. WARNING: experimental"), cmds.BoolOption(preserveModeOptionName, "Apply existing POSIX permissions to created UnixFS entries. WARNING: experimental, forces dag-pb for root block, disables raw-leaves"), @@ -262,6 +263,12 @@ https://github.com/ipfs/kubo/blob/master/docs/config.md#import hashFunStr, _ := req.Options[hashOptionName].(string) inline, _ := req.Options[inlineOptionName].(bool) inlineLimit, _ := req.Options[inlineLimitOptionName].(int) + + // Validate inline-limit doesn't exceed verifcid.MaxIdentityDigestSize + if inline && inlineLimit > verifcid.MaxIdentityDigestSize { + return fmt.Errorf("inline-limit %d exceeds maximum allowed size of %d bytes", inlineLimit, verifcid.MaxIdentityDigestSize) + } + toFilesStr, toFilesSet := req.Options[toFilesOptionName].(string) preserveMode, _ := req.Options[preserveModeOptionName].(bool) preserveMtime, _ := req.Options[preserveMtimeOptionName].(bool) diff --git a/core/commands/files.go b/core/commands/files.go index 12a96eba2a5..e2543b50bde 100644 --- a/core/commands/files.go +++ b/core/commands/files.go @@ -1366,6 +1366,7 @@ func getPrefixNew(req *cmds.Request) (cid.Builder, error) { if !ok { return nil, fmt.Errorf("unrecognized hash function: %s", strings.ToLower(hashFunStr)) } + prefix.MhType = hashFunCode prefix.MhLength = -1 } diff --git a/docs/examples/kubo-as-a-library/go.mod b/docs/examples/kubo-as-a-library/go.mod index 5e728552d71..7e16a99eebc 100644 --- a/docs/examples/kubo-as-a-library/go.mod +++ b/docs/examples/kubo-as-a-library/go.mod @@ -7,7 +7,7 @@ go 1.25 replace github.com/ipfs/kubo => ./../../.. require ( - github.com/ipfs/boxo v0.34.0 + github.com/ipfs/boxo v0.34.1-0.20250830024429-9b014be0bccb github.com/ipfs/kubo v0.0.0-00010101000000-000000000000 github.com/libp2p/go-libp2p v0.43.0 github.com/multiformats/go-multiaddr v0.16.1 diff --git a/docs/examples/kubo-as-a-library/go.sum b/docs/examples/kubo-as-a-library/go.sum index 50a10c6b65c..4bf3cd40b66 100644 --- a/docs/examples/kubo-as-a-library/go.sum +++ b/docs/examples/kubo-as-a-library/go.sum @@ -287,8 +287,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.25.0 h1:OqNqsGZPX8zh3eFMO8Lf8EHRRnSGBMqcd github.com/ipfs-shipyard/nopfs/ipfs v0.25.0/go.mod h1:BxhUdtBgOXg1B+gAPEplkg/GpyTZY+kCMSfsJvvydqU= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= -github.com/ipfs/boxo v0.34.0 h1:pMP9bAsTs4xVh8R0ZmxIWviV7kjDa60U24QrlGgHb1g= -github.com/ipfs/boxo v0.34.0/go.mod h1:kzdH/ewDybtO3+M8MCVkpwnIIc/d2VISX95DFrY4vQA= +github.com/ipfs/boxo v0.34.1-0.20250830024429-9b014be0bccb h1:PTwRSCPyRdfK2EV+Y0xKBgf2EycmCECyQ6hOvmWBusA= +github.com/ipfs/boxo v0.34.1-0.20250830024429-9b014be0bccb/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0= github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA= github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU= github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk= diff --git a/go.mod b/go.mod index 0396b9e0f86..e75a8e428f5 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/hashicorp/go-version v1.7.0 github.com/ipfs-shipyard/nopfs v0.0.14 github.com/ipfs-shipyard/nopfs/ipfs v0.25.0 - github.com/ipfs/boxo v0.34.0 + github.com/ipfs/boxo v0.34.1-0.20250830024429-9b014be0bccb github.com/ipfs/go-block-format v0.2.2 github.com/ipfs/go-cid v0.5.0 github.com/ipfs/go-cidutil v0.1.0 diff --git a/go.sum b/go.sum index a5c243b03d4..86f166b4d94 100644 --- a/go.sum +++ b/go.sum @@ -354,8 +354,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.25.0 h1:OqNqsGZPX8zh3eFMO8Lf8EHRRnSGBMqcd github.com/ipfs-shipyard/nopfs/ipfs v0.25.0/go.mod h1:BxhUdtBgOXg1B+gAPEplkg/GpyTZY+kCMSfsJvvydqU= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= -github.com/ipfs/boxo v0.34.0 h1:pMP9bAsTs4xVh8R0ZmxIWviV7kjDa60U24QrlGgHb1g= -github.com/ipfs/boxo v0.34.0/go.mod h1:kzdH/ewDybtO3+M8MCVkpwnIIc/d2VISX95DFrY4vQA= +github.com/ipfs/boxo v0.34.1-0.20250830024429-9b014be0bccb h1:PTwRSCPyRdfK2EV+Y0xKBgf2EycmCECyQ6hOvmWBusA= +github.com/ipfs/boxo v0.34.1-0.20250830024429-9b014be0bccb/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0= github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA= github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU= github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk= diff --git a/test/cli/identity_cid_test.go b/test/cli/identity_cid_test.go new file mode 100644 index 00000000000..2cc2fc94f0e --- /dev/null +++ b/test/cli/identity_cid_test.go @@ -0,0 +1,310 @@ +package cli + +import ( + "fmt" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/ipfs/boxo/verifcid" + "github.com/ipfs/kubo/config" + "github.com/ipfs/kubo/test/cli/harness" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestIdentityCIDOverflowProtection(t *testing.T) { + t.Parallel() + + t.Run("ipfs add --hash=identity with small data succeeds", func(t *testing.T) { + t.Parallel() + node := harness.NewT(t).NewNode().Init().StartDaemon() + defer node.StopDaemon() + + // small data that fits in identity CID + smallData := "small data" + tempFile := filepath.Join(node.Dir, "small.txt") + err := os.WriteFile(tempFile, []byte(smallData), 0644) + require.NoError(t, err) + + res := node.IPFS("add", "--hash=identity", tempFile) + assert.NoError(t, res.Err) + cid := strings.Fields(res.Stdout.String())[1] + + // verify it's actually using identity hash + res = node.IPFS("cid", "format", "-f", "%h", cid) + assert.NoError(t, res.Err) + assert.Equal(t, "identity", res.Stdout.Trimmed()) + }) + + t.Run("ipfs add --hash=identity with large data fails", func(t *testing.T) { + t.Parallel() + node := harness.NewT(t).NewNode().Init().StartDaemon() + defer node.StopDaemon() + + // data larger than verifcid.MaxIdentityDigestSize + largeData := strings.Repeat("x", verifcid.MaxIdentityDigestSize+50) + tempFile := filepath.Join(node.Dir, "large.txt") + err := os.WriteFile(tempFile, []byte(largeData), 0644) + require.NoError(t, err) + + res := node.RunIPFS("add", "--hash=identity", tempFile) + assert.NotEqual(t, 0, res.ExitErr.ExitCode()) + // should error with identity digest too large message + assert.Contains(t, res.Stderr.String(), "identity digest too large") + }) + + t.Run("ipfs add --inline with valid --inline-limit succeeds", func(t *testing.T) { + t.Parallel() + node := harness.NewT(t).NewNode().Init().StartDaemon() + defer node.StopDaemon() + + smallData := "small inline data" + tempFile := filepath.Join(node.Dir, "inline.txt") + err := os.WriteFile(tempFile, []byte(smallData), 0644) + require.NoError(t, err) + + // use limit just under the maximum + limit := verifcid.MaxIdentityDigestSize - 10 + res := node.IPFS("add", "--inline", fmt.Sprintf("--inline-limit=%d", limit), tempFile) + assert.NoError(t, res.Err) + cid := strings.Fields(res.Stdout.String())[1] + + // verify the CID is using identity hash (inline) + res = node.IPFS("cid", "format", "-f", "%h", cid) + assert.NoError(t, res.Err) + assert.Equal(t, "identity", res.Stdout.Trimmed()) + + // verify the codec (may be dag-pb or raw depending on kubo version) + res = node.IPFS("cid", "format", "-f", "%c", cid) + assert.NoError(t, res.Err) + // Accept either raw or dag-pb as both are valid for inline data + codec := res.Stdout.Trimmed() + assert.True(t, codec == "raw" || codec == "dag-pb", "expected raw or dag-pb codec, got %s", codec) + }) + + t.Run("ipfs add --inline with excessive --inline-limit fails", func(t *testing.T) { + t.Parallel() + node := harness.NewT(t).NewNode().Init().StartDaemon() + defer node.StopDaemon() + + smallData := "data" + tempFile := filepath.Join(node.Dir, "inline2.txt") + err := os.WriteFile(tempFile, []byte(smallData), 0644) + require.NoError(t, err) + + excessiveLimit := verifcid.MaxIdentityDigestSize + 50 + res := node.RunIPFS("add", "--inline", fmt.Sprintf("--inline-limit=%d", excessiveLimit), tempFile) + assert.NotEqual(t, 0, res.ExitErr.ExitCode()) + assert.Contains(t, res.Stderr.String(), fmt.Sprintf("inline-limit %d exceeds maximum allowed size of %d bytes", excessiveLimit, verifcid.MaxIdentityDigestSize)) + }) + + t.Run("ipfs files write --hash=identity appending to identity CID switches to configured hash", func(t *testing.T) { + t.Parallel() + node := harness.NewT(t).NewNode().Init().StartDaemon() + defer node.StopDaemon() + + // create initial small file with identity CID + initialData := "initial" + tempFile := filepath.Join(node.Dir, "initial.txt") + err := os.WriteFile(tempFile, []byte(initialData), 0644) + require.NoError(t, err) + + res := node.IPFS("add", "--hash=identity", tempFile) + assert.NoError(t, res.Err) + cid1 := strings.Fields(res.Stdout.String())[1] + + // verify initial CID uses identity + res = node.IPFS("cid", "format", "-f", "%h", cid1) + assert.NoError(t, res.Err) + assert.Equal(t, "identity", res.Stdout.Trimmed()) + + // copy to MFS + res = node.IPFS("files", "cp", fmt.Sprintf("/ipfs/%s", cid1), "/identity-file") + assert.NoError(t, res.Err) + + // append data that would exceed identity CID limit + appendData := strings.Repeat("a", verifcid.MaxIdentityDigestSize) + appendFile := filepath.Join(node.Dir, "append.txt") + err = os.WriteFile(appendFile, []byte(appendData), 0644) + require.NoError(t, err) + + // append to the end of the file + // get the current data size + res = node.IPFS("files", "stat", "--format", "", "/identity-file") + assert.NoError(t, res.Err) + size := res.Stdout.Trimmed() + // this should succeed because DagModifier in boxo handles the overflow + res = node.IPFS("files", "write", "--hash=identity", "--offset="+size, "/identity-file", appendFile) + assert.NoError(t, res.Err) + + // check that the file now uses non-identity hash + res = node.IPFS("files", "stat", "--hash", "/identity-file") + assert.NoError(t, res.Err) + newCid := res.Stdout.Trimmed() + + // verify new CID does NOT use identity + res = node.IPFS("cid", "format", "-f", "%h", newCid) + assert.NoError(t, res.Err) + assert.NotEqual(t, "identity", res.Stdout.Trimmed()) + + // verify it switched to a cryptographic hash + assert.Equal(t, config.DefaultHashFunction, res.Stdout.Trimmed()) + }) + + t.Run("ipfs files write --hash=identity with small write creates identity CID", func(t *testing.T) { + t.Parallel() + node := harness.NewT(t).NewNode().Init().StartDaemon() + defer node.StopDaemon() + + // create a small file with identity hash directly in MFS + smallData := "small" + tempFile := filepath.Join(node.Dir, "small.txt") + err := os.WriteFile(tempFile, []byte(smallData), 0644) + require.NoError(t, err) + + // write to MFS with identity hash + res := node.IPFS("files", "write", "--create", "--hash=identity", "/mfs-identity", tempFile) + assert.NoError(t, res.Err) + + // verify using identity CID + res = node.IPFS("files", "stat", "--hash", "/mfs-identity") + assert.NoError(t, res.Err) + cid := res.Stdout.Trimmed() + + // verify CID uses identity hash + res = node.IPFS("cid", "format", "-f", "%h", cid) + assert.NoError(t, res.Err) + assert.Equal(t, "identity", res.Stdout.Trimmed()) + + // verify content + res = node.IPFS("files", "read", "/mfs-identity") + assert.NoError(t, res.Err) + assert.Equal(t, smallData, res.Stdout.Trimmed()) + }) + + t.Run("raw node with identity CID converts to UnixFS when appending", func(t *testing.T) { + t.Parallel() + node := harness.NewT(t).NewNode().Init().StartDaemon() + defer node.StopDaemon() + + // create raw block with identity CID + rawData := "raw" + tempFile := filepath.Join(node.Dir, "raw.txt") + err := os.WriteFile(tempFile, []byte(rawData), 0644) + require.NoError(t, err) + + res := node.IPFS("block", "put", "--format=raw", "--mhtype=identity", tempFile) + assert.NoError(t, res.Err) + rawCid := res.Stdout.Trimmed() + + // verify initial CID uses identity hash and raw codec + res = node.IPFS("cid", "format", "-f", "%h", rawCid) + assert.NoError(t, res.Err) + assert.Equal(t, "identity", res.Stdout.Trimmed()) + + res = node.IPFS("cid", "format", "-f", "%c", rawCid) + assert.NoError(t, res.Err) + assert.Equal(t, "raw", res.Stdout.Trimmed()) + + // copy to MFS + res = node.IPFS("files", "cp", fmt.Sprintf("/ipfs/%s", rawCid), "/raw-identity") + assert.NoError(t, res.Err) + + // append data + appendData := "appended" + appendFile := filepath.Join(node.Dir, "append-raw.txt") + err = os.WriteFile(appendFile, []byte(appendData), 0644) + require.NoError(t, err) + + // get current data size for appending + res = node.IPFS("files", "stat", "--format", "", "/raw-identity") + assert.NoError(t, res.Err) + size := res.Stdout.Trimmed() + res = node.IPFS("files", "write", "--hash=identity", "--offset="+size, "/raw-identity", appendFile) + assert.NoError(t, res.Err) + + // verify content + res = node.IPFS("files", "read", "/raw-identity") + assert.NoError(t, res.Err) + assert.Equal(t, rawData+appendData, res.Stdout.Trimmed()) + + // check that it's now a UnixFS structure (dag-pb) + res = node.IPFS("files", "stat", "--hash", "/raw-identity") + assert.NoError(t, res.Err) + newCid := res.Stdout.Trimmed() + + res = node.IPFS("cid", "format", "-f", "%c", newCid) + assert.NoError(t, res.Err) + assert.Equal(t, "dag-pb", res.Stdout.Trimmed()) + + res = node.IPFS("files", "stat", "/raw-identity") + assert.NoError(t, res.Err) + assert.Contains(t, res.Stdout.String(), "Type: file") + }) + + t.Run("ipfs add --inline-limit at exactly max size succeeds", func(t *testing.T) { + t.Parallel() + node := harness.NewT(t).NewNode().Init().StartDaemon() + defer node.StopDaemon() + + // create small data that will be inlined + smallData := "test data for inline" + tempFile := filepath.Join(node.Dir, "exact.txt") + err := os.WriteFile(tempFile, []byte(smallData), 0644) + require.NoError(t, err) + + // exactly at the limit should succeed + res := node.IPFS("add", "--inline", fmt.Sprintf("--inline-limit=%d", verifcid.MaxIdentityDigestSize), tempFile) + assert.NoError(t, res.Err) + cid := strings.Fields(res.Stdout.String())[1] + + // verify it uses identity hash (inline) since data is small enough + res = node.IPFS("cid", "format", "-f", "%h", cid) + assert.NoError(t, res.Err) + assert.Equal(t, "identity", res.Stdout.Trimmed()) + }) + + t.Run("ipfs add --inline-limit one byte over max fails", func(t *testing.T) { + t.Parallel() + node := harness.NewT(t).NewNode().Init().StartDaemon() + defer node.StopDaemon() + + smallData := "test" + tempFile := filepath.Join(node.Dir, "oneover.txt") + err := os.WriteFile(tempFile, []byte(smallData), 0644) + require.NoError(t, err) + + // one byte over should fail + overLimit := verifcid.MaxIdentityDigestSize + 1 + res := node.RunIPFS("add", "--inline", fmt.Sprintf("--inline-limit=%d", overLimit), tempFile) + assert.NotEqual(t, 0, res.ExitErr.ExitCode()) + assert.Contains(t, res.Stderr.String(), fmt.Sprintf("inline-limit %d exceeds maximum allowed size of %d bytes", overLimit, verifcid.MaxIdentityDigestSize)) + }) + + t.Run("ipfs add --inline with data larger than limit uses configured hash", func(t *testing.T) { + t.Parallel() + node := harness.NewT(t).NewNode().Init().StartDaemon() + defer node.StopDaemon() + + // data larger than inline limit + largeData := strings.Repeat("y", 100) + tempFile := filepath.Join(node.Dir, "toolarge.txt") + err := os.WriteFile(tempFile, []byte(largeData), 0644) + require.NoError(t, err) + + // set inline limit smaller than data + res := node.IPFS("add", "--inline", "--inline-limit=50", tempFile) + assert.NoError(t, res.Err) + cid := strings.Fields(res.Stdout.String())[1] + + // verify it's NOT using identity hash (data too large for inline) + res = node.IPFS("cid", "format", "-f", "%h", cid) + assert.NoError(t, res.Err) + assert.NotEqual(t, "identity", res.Stdout.Trimmed()) + + // should use configured hash + assert.Equal(t, config.DefaultHashFunction, res.Stdout.Trimmed()) + }) +} diff --git a/test/dependencies/go.mod b/test/dependencies/go.mod index 962e3093a2a..ab4ebcb19f0 100644 --- a/test/dependencies/go.mod +++ b/test/dependencies/go.mod @@ -134,7 +134,7 @@ require ( github.com/huin/goupnp v1.3.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/ipfs/bbloom v0.0.4 // indirect - github.com/ipfs/boxo v0.34.0 // indirect + github.com/ipfs/boxo v0.34.1-0.20250830024429-9b014be0bccb // indirect github.com/ipfs/go-bitfield v1.1.0 // indirect github.com/ipfs/go-block-format v0.2.2 // indirect github.com/ipfs/go-cid v0.5.0 // indirect diff --git a/test/dependencies/go.sum b/test/dependencies/go.sum index a8018cc80c3..178e2a3eacf 100644 --- a/test/dependencies/go.sum +++ b/test/dependencies/go.sum @@ -332,8 +332,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= -github.com/ipfs/boxo v0.34.0 h1:pMP9bAsTs4xVh8R0ZmxIWviV7kjDa60U24QrlGgHb1g= -github.com/ipfs/boxo v0.34.0/go.mod h1:kzdH/ewDybtO3+M8MCVkpwnIIc/d2VISX95DFrY4vQA= +github.com/ipfs/boxo v0.34.1-0.20250830024429-9b014be0bccb h1:PTwRSCPyRdfK2EV+Y0xKBgf2EycmCECyQ6hOvmWBusA= +github.com/ipfs/boxo v0.34.1-0.20250830024429-9b014be0bccb/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0= github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA= github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU= github.com/ipfs/go-block-format v0.2.2 h1:uecCTgRwDIXyZPgYspaLXoMiMmxQpSx2aq34eNc4YvQ= From 26957553d0f8ae91d35d27bfcc409af8c7a0088a Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Sat, 30 Aug 2025 05:00:13 +0200 Subject: [PATCH 02/10] fix: update to use new verifcid sentinel errors - replace deprecated ErrBelowMinimumHashLength with ErrDigestTooSmall - update sharness test error messages to match new sentinel errors --- gc/gc.go | 2 +- test/sharness/t0275-cid-security.sh | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/gc/gc.go b/gc/gc.go index 1d4805a66e3..ac3f3d08fda 100644 --- a/gc/gc.go +++ b/gc/gc.go @@ -165,7 +165,7 @@ func Descendants(ctx context.Context, getLinks dag.GetLinks, set *cid.Set, roots } verboseCidError := func(err error) error { - if strings.Contains(err.Error(), verifcid.ErrBelowMinimumHashLength.Error()) || + if strings.Contains(err.Error(), verifcid.ErrDigestTooSmall.Error()) || strings.Contains(err.Error(), verifcid.ErrPossiblyInsecureHashFunction.Error()) { err = fmt.Errorf("\"%s\"\nPlease run 'ipfs pin verify'"+ // nolint " to list insecure hashes. If you want to read them,"+ diff --git a/test/sharness/t0275-cid-security.sh b/test/sharness/t0275-cid-security.sh index e8d26555052..7f8764d3f61 100755 --- a/test/sharness/t0275-cid-security.sh +++ b/test/sharness/t0275-cid-security.sh @@ -15,7 +15,7 @@ test_expect_success "adding using unsafe function fails with error" ' ' test_expect_success "error reason is pointed out" ' - grep "insecure hash functions not allowed" add_out || test_fsh cat add_out + grep "potentially insecure hash functions not allowed" add_out || test_fsh cat add_out ' test_expect_success "adding using too short of a hash function gives out an error" ' @@ -23,7 +23,7 @@ test_expect_success "adding using too short of a hash function gives out an erro ' test_expect_success "error reason is pointed out" ' - grep "hashes must be at least 20 bytes long" block_out + grep "digest too small" block_out ' @@ -35,7 +35,7 @@ test_cat_get() { test_expect_success "error reason is pointed out" ' - grep "insecure hash functions not allowed" ipfs_cat + grep "potentially insecure hash functions not allowed" ipfs_cat ' @@ -45,7 +45,7 @@ test_cat_get() { ' test_expect_success "error reason is pointed out" ' - grep "hashes must be at least 20 bytes long" ipfs_get + grep "digest too small" ipfs_get ' } From f915117761de707ee1c181fd993c7a2c33764d92 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Sat, 30 Aug 2025 18:34:04 +0200 Subject: [PATCH 03/10] refactor: use verifcid.DefaultMaxIdentityDigestSize constant - replace hardcoded 128 byte limit with named constant - improve code clarity and maintainability - align with boxo verifcid package updates --- core/commands/add.go | 8 ++++---- docs/examples/kubo-as-a-library/go.mod | 2 +- docs/examples/kubo-as-a-library/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- test/cli/identity_cid_test.go | 18 +++++++++--------- test/dependencies/go.mod | 2 +- test/dependencies/go.sum | 4 ++-- 8 files changed, 22 insertions(+), 22 deletions(-) diff --git a/core/commands/add.go b/core/commands/add.go index 662476a93b7..c2d5687243c 100644 --- a/core/commands/add.go +++ b/core/commands/add.go @@ -204,7 +204,7 @@ https://github.com/ipfs/kubo/blob/master/docs/config.md#import cmds.IntOption(maxHAMTFanoutOptionName, "Limit the maximum number of links of a UnixFS HAMT directory node to this (power of 2, multiple of 8). WARNING: experimental, Import.UnixFSHAMTDirectorySizeThreshold is safer. Default: Import.UnixFSHAMTDirectoryMaxFanout"), // Experimental Features cmds.BoolOption(inlineOptionName, "Inline small blocks into CIDs. WARNING: experimental"), - cmds.IntOption(inlineLimitOptionName, fmt.Sprintf("Maximum block size to inline. Maximum: %d bytes. WARNING: experimental", verifcid.MaxIdentityDigestSize)).WithDefault(32), + cmds.IntOption(inlineLimitOptionName, fmt.Sprintf("Maximum block size to inline. Maximum: %d bytes. WARNING: experimental", verifcid.DefaultMaxIdentityDigestSize)).WithDefault(32), cmds.BoolOption(noCopyOptionName, "Add the file using filestore. Implies raw-leaves. WARNING: experimental"), cmds.BoolOption(fstoreCacheOptionName, "Check the filestore for pre-existing blocks. WARNING: experimental"), cmds.BoolOption(preserveModeOptionName, "Apply existing POSIX permissions to created UnixFS entries. WARNING: experimental, forces dag-pb for root block, disables raw-leaves"), @@ -264,9 +264,9 @@ https://github.com/ipfs/kubo/blob/master/docs/config.md#import inline, _ := req.Options[inlineOptionName].(bool) inlineLimit, _ := req.Options[inlineLimitOptionName].(int) - // Validate inline-limit doesn't exceed verifcid.MaxIdentityDigestSize - if inline && inlineLimit > verifcid.MaxIdentityDigestSize { - return fmt.Errorf("inline-limit %d exceeds maximum allowed size of %d bytes", inlineLimit, verifcid.MaxIdentityDigestSize) + // Validate inline-limit doesn't exceed the maximum identity digest size + if inline && inlineLimit > verifcid.DefaultMaxIdentityDigestSize { + return fmt.Errorf("inline-limit %d exceeds maximum allowed size of %d bytes", inlineLimit, verifcid.DefaultMaxIdentityDigestSize) } toFilesStr, toFilesSet := req.Options[toFilesOptionName].(string) diff --git a/docs/examples/kubo-as-a-library/go.mod b/docs/examples/kubo-as-a-library/go.mod index 7e16a99eebc..44aacb18197 100644 --- a/docs/examples/kubo-as-a-library/go.mod +++ b/docs/examples/kubo-as-a-library/go.mod @@ -7,7 +7,7 @@ go 1.25 replace github.com/ipfs/kubo => ./../../.. require ( - github.com/ipfs/boxo v0.34.1-0.20250830024429-9b014be0bccb + github.com/ipfs/boxo v0.34.1-0.20250830162938-3025889071e9 github.com/ipfs/kubo v0.0.0-00010101000000-000000000000 github.com/libp2p/go-libp2p v0.43.0 github.com/multiformats/go-multiaddr v0.16.1 diff --git a/docs/examples/kubo-as-a-library/go.sum b/docs/examples/kubo-as-a-library/go.sum index 4bf3cd40b66..decae977695 100644 --- a/docs/examples/kubo-as-a-library/go.sum +++ b/docs/examples/kubo-as-a-library/go.sum @@ -287,8 +287,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.25.0 h1:OqNqsGZPX8zh3eFMO8Lf8EHRRnSGBMqcd github.com/ipfs-shipyard/nopfs/ipfs v0.25.0/go.mod h1:BxhUdtBgOXg1B+gAPEplkg/GpyTZY+kCMSfsJvvydqU= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= -github.com/ipfs/boxo v0.34.1-0.20250830024429-9b014be0bccb h1:PTwRSCPyRdfK2EV+Y0xKBgf2EycmCECyQ6hOvmWBusA= -github.com/ipfs/boxo v0.34.1-0.20250830024429-9b014be0bccb/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0= +github.com/ipfs/boxo v0.34.1-0.20250830162938-3025889071e9 h1:p8YZ6IaH9jB9oMbgbAug/DNOSh/YpHLcqe8z3qQFMo0= +github.com/ipfs/boxo v0.34.1-0.20250830162938-3025889071e9/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0= github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA= github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU= github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk= diff --git a/go.mod b/go.mod index e75a8e428f5..d0450842a88 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/hashicorp/go-version v1.7.0 github.com/ipfs-shipyard/nopfs v0.0.14 github.com/ipfs-shipyard/nopfs/ipfs v0.25.0 - github.com/ipfs/boxo v0.34.1-0.20250830024429-9b014be0bccb + github.com/ipfs/boxo v0.34.1-0.20250830162938-3025889071e9 github.com/ipfs/go-block-format v0.2.2 github.com/ipfs/go-cid v0.5.0 github.com/ipfs/go-cidutil v0.1.0 diff --git a/go.sum b/go.sum index 86f166b4d94..f90c1657790 100644 --- a/go.sum +++ b/go.sum @@ -354,8 +354,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.25.0 h1:OqNqsGZPX8zh3eFMO8Lf8EHRRnSGBMqcd github.com/ipfs-shipyard/nopfs/ipfs v0.25.0/go.mod h1:BxhUdtBgOXg1B+gAPEplkg/GpyTZY+kCMSfsJvvydqU= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= -github.com/ipfs/boxo v0.34.1-0.20250830024429-9b014be0bccb h1:PTwRSCPyRdfK2EV+Y0xKBgf2EycmCECyQ6hOvmWBusA= -github.com/ipfs/boxo v0.34.1-0.20250830024429-9b014be0bccb/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0= +github.com/ipfs/boxo v0.34.1-0.20250830162938-3025889071e9 h1:p8YZ6IaH9jB9oMbgbAug/DNOSh/YpHLcqe8z3qQFMo0= +github.com/ipfs/boxo v0.34.1-0.20250830162938-3025889071e9/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0= github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA= github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU= github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk= diff --git a/test/cli/identity_cid_test.go b/test/cli/identity_cid_test.go index 2cc2fc94f0e..64b2288e1a7 100644 --- a/test/cli/identity_cid_test.go +++ b/test/cli/identity_cid_test.go @@ -43,8 +43,8 @@ func TestIdentityCIDOverflowProtection(t *testing.T) { node := harness.NewT(t).NewNode().Init().StartDaemon() defer node.StopDaemon() - // data larger than verifcid.MaxIdentityDigestSize - largeData := strings.Repeat("x", verifcid.MaxIdentityDigestSize+50) + // data larger than verifcid.DefaultMaxIdentityDigestSize + largeData := strings.Repeat("x", verifcid.DefaultMaxIdentityDigestSize+50) tempFile := filepath.Join(node.Dir, "large.txt") err := os.WriteFile(tempFile, []byte(largeData), 0644) require.NoError(t, err) @@ -66,7 +66,7 @@ func TestIdentityCIDOverflowProtection(t *testing.T) { require.NoError(t, err) // use limit just under the maximum - limit := verifcid.MaxIdentityDigestSize - 10 + limit := verifcid.DefaultMaxIdentityDigestSize - 10 res := node.IPFS("add", "--inline", fmt.Sprintf("--inline-limit=%d", limit), tempFile) assert.NoError(t, res.Err) cid := strings.Fields(res.Stdout.String())[1] @@ -94,10 +94,10 @@ func TestIdentityCIDOverflowProtection(t *testing.T) { err := os.WriteFile(tempFile, []byte(smallData), 0644) require.NoError(t, err) - excessiveLimit := verifcid.MaxIdentityDigestSize + 50 + excessiveLimit := verifcid.DefaultMaxIdentityDigestSize + 50 res := node.RunIPFS("add", "--inline", fmt.Sprintf("--inline-limit=%d", excessiveLimit), tempFile) assert.NotEqual(t, 0, res.ExitErr.ExitCode()) - assert.Contains(t, res.Stderr.String(), fmt.Sprintf("inline-limit %d exceeds maximum allowed size of %d bytes", excessiveLimit, verifcid.MaxIdentityDigestSize)) + assert.Contains(t, res.Stderr.String(), fmt.Sprintf("inline-limit %d exceeds maximum allowed size of %d bytes", excessiveLimit, verifcid.DefaultMaxIdentityDigestSize)) }) t.Run("ipfs files write --hash=identity appending to identity CID switches to configured hash", func(t *testing.T) { @@ -125,7 +125,7 @@ func TestIdentityCIDOverflowProtection(t *testing.T) { assert.NoError(t, res.Err) // append data that would exceed identity CID limit - appendData := strings.Repeat("a", verifcid.MaxIdentityDigestSize) + appendData := strings.Repeat("a", verifcid.DefaultMaxIdentityDigestSize) appendFile := filepath.Join(node.Dir, "append.txt") err = os.WriteFile(appendFile, []byte(appendData), 0644) require.NoError(t, err) @@ -256,7 +256,7 @@ func TestIdentityCIDOverflowProtection(t *testing.T) { require.NoError(t, err) // exactly at the limit should succeed - res := node.IPFS("add", "--inline", fmt.Sprintf("--inline-limit=%d", verifcid.MaxIdentityDigestSize), tempFile) + res := node.IPFS("add", "--inline", fmt.Sprintf("--inline-limit=%d", verifcid.DefaultMaxIdentityDigestSize), tempFile) assert.NoError(t, res.Err) cid := strings.Fields(res.Stdout.String())[1] @@ -277,10 +277,10 @@ func TestIdentityCIDOverflowProtection(t *testing.T) { require.NoError(t, err) // one byte over should fail - overLimit := verifcid.MaxIdentityDigestSize + 1 + overLimit := verifcid.DefaultMaxIdentityDigestSize + 1 res := node.RunIPFS("add", "--inline", fmt.Sprintf("--inline-limit=%d", overLimit), tempFile) assert.NotEqual(t, 0, res.ExitErr.ExitCode()) - assert.Contains(t, res.Stderr.String(), fmt.Sprintf("inline-limit %d exceeds maximum allowed size of %d bytes", overLimit, verifcid.MaxIdentityDigestSize)) + assert.Contains(t, res.Stderr.String(), fmt.Sprintf("inline-limit %d exceeds maximum allowed size of %d bytes", overLimit, verifcid.DefaultMaxIdentityDigestSize)) }) t.Run("ipfs add --inline with data larger than limit uses configured hash", func(t *testing.T) { diff --git a/test/dependencies/go.mod b/test/dependencies/go.mod index ab4ebcb19f0..999528ef495 100644 --- a/test/dependencies/go.mod +++ b/test/dependencies/go.mod @@ -134,7 +134,7 @@ require ( github.com/huin/goupnp v1.3.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/ipfs/bbloom v0.0.4 // indirect - github.com/ipfs/boxo v0.34.1-0.20250830024429-9b014be0bccb // indirect + github.com/ipfs/boxo v0.34.1-0.20250830162938-3025889071e9 // indirect github.com/ipfs/go-bitfield v1.1.0 // indirect github.com/ipfs/go-block-format v0.2.2 // indirect github.com/ipfs/go-cid v0.5.0 // indirect diff --git a/test/dependencies/go.sum b/test/dependencies/go.sum index 178e2a3eacf..044dab31570 100644 --- a/test/dependencies/go.sum +++ b/test/dependencies/go.sum @@ -332,8 +332,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= -github.com/ipfs/boxo v0.34.1-0.20250830024429-9b014be0bccb h1:PTwRSCPyRdfK2EV+Y0xKBgf2EycmCECyQ6hOvmWBusA= -github.com/ipfs/boxo v0.34.1-0.20250830024429-9b014be0bccb/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0= +github.com/ipfs/boxo v0.34.1-0.20250830162938-3025889071e9 h1:p8YZ6IaH9jB9oMbgbAug/DNOSh/YpHLcqe8z3qQFMo0= +github.com/ipfs/boxo v0.34.1-0.20250830162938-3025889071e9/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0= github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA= github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU= github.com/ipfs/go-block-format v0.2.2 h1:uecCTgRwDIXyZPgYspaLXoMiMmxQpSx2aq34eNc4YvQ= From b3bac624858205370e5beafe831b845e82420ad2 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Sat, 30 Aug 2025 19:07:48 +0200 Subject: [PATCH 04/10] docs: add v0.38 changelog highlights - document --inline-limit enforcement using DefaultMaxIdentityDigestSize - note ipfs files write fixes for codec preservation and raw node support - highlight identity CID overflow prevention --- docs/changelogs/v0.38.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docs/changelogs/v0.38.md b/docs/changelogs/v0.38.md index 3d2de2f9b6c..af7284e1ce2 100644 --- a/docs/changelogs/v0.38.md +++ b/docs/changelogs/v0.38.md @@ -18,6 +18,25 @@ This release was brought to you by the [Shipyard](https://ipshipyard.com/) team. ### ๐Ÿ”ฆ Highlights +#### ๐Ÿ› ๏ธ Important fixes for `ipfs files write` and `ipfs add --inline-limit` + +Several critical issues with file operations have been fixed: + +**`ipfs add --inline-limit` enforcement**: +- Now enforces a maximum limit respecting `boxo/verifcid.DefaultMaxIdentityDigestSize` +- Identity CIDs (multihash code 0x00) embed data directly without cryptographic verification +- Attempts to use `--inline-limit` values larger than `DefaultMaxIdentityDigestSize` will return an error: + ``` + Error: inline-limit 256 exceeds maximum allowed size of 128 bytes + ``` +- Protects IPFS nodes and gateways from potential abuse while maintaining compatibility with existing valid use cases + +**`ipfs files write` fixes**: +- **Codec preservation**: Files now correctly preserve raw node codec when modifying data under the chunker threshold, instead of incorrectly forcing everything to dag-pb +- **Raw node append support**: Append operations to raw nodes now work correctly by automatically converting them into UnixFS file structures. Previously these operations would fail with "expected protobuf dag node" errors +- **CID prefix inheritance**: Files with identity CIDs now properly inherit the full CID prefix from parent directories (version, codec, hash type, length), not just the hash type +- **Identity CID overflow prevention**: File modifications now prevent creation of identity CIDs exceeding `DefaultMaxIdentityDigestSize`, automatically switching to proper cryptographic hashes when needed + ### ๐Ÿ“ฆ๏ธ Important dependency updates ### ๐Ÿ“ Changelog From 163b0b8c35d1acef523daa5a79778560829c0376 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Tue, 2 Sep 2025 03:36:19 +0200 Subject: [PATCH 05/10] test: fix identity CID test assertion - update test to match actual error message format - remove unnecessary empty line in files.go --- core/commands/files.go | 1 - docs/examples/kubo-as-a-library/go.mod | 2 +- docs/examples/kubo-as-a-library/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- test/cli/identity_cid_test.go | 4 ++-- test/dependencies/go.mod | 2 +- test/dependencies/go.sum | 4 ++-- 8 files changed, 11 insertions(+), 12 deletions(-) diff --git a/core/commands/files.go b/core/commands/files.go index e2543b50bde..12a96eba2a5 100644 --- a/core/commands/files.go +++ b/core/commands/files.go @@ -1366,7 +1366,6 @@ func getPrefixNew(req *cmds.Request) (cid.Builder, error) { if !ok { return nil, fmt.Errorf("unrecognized hash function: %s", strings.ToLower(hashFunStr)) } - prefix.MhType = hashFunCode prefix.MhLength = -1 } diff --git a/docs/examples/kubo-as-a-library/go.mod b/docs/examples/kubo-as-a-library/go.mod index 44aacb18197..7341019fc53 100644 --- a/docs/examples/kubo-as-a-library/go.mod +++ b/docs/examples/kubo-as-a-library/go.mod @@ -7,7 +7,7 @@ go 1.25 replace github.com/ipfs/kubo => ./../../.. require ( - github.com/ipfs/boxo v0.34.1-0.20250830162938-3025889071e9 + github.com/ipfs/boxo v0.34.1-0.20250902010009-373354403a53 github.com/ipfs/kubo v0.0.0-00010101000000-000000000000 github.com/libp2p/go-libp2p v0.43.0 github.com/multiformats/go-multiaddr v0.16.1 diff --git a/docs/examples/kubo-as-a-library/go.sum b/docs/examples/kubo-as-a-library/go.sum index decae977695..3065a634503 100644 --- a/docs/examples/kubo-as-a-library/go.sum +++ b/docs/examples/kubo-as-a-library/go.sum @@ -287,8 +287,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.25.0 h1:OqNqsGZPX8zh3eFMO8Lf8EHRRnSGBMqcd github.com/ipfs-shipyard/nopfs/ipfs v0.25.0/go.mod h1:BxhUdtBgOXg1B+gAPEplkg/GpyTZY+kCMSfsJvvydqU= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= -github.com/ipfs/boxo v0.34.1-0.20250830162938-3025889071e9 h1:p8YZ6IaH9jB9oMbgbAug/DNOSh/YpHLcqe8z3qQFMo0= -github.com/ipfs/boxo v0.34.1-0.20250830162938-3025889071e9/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0= +github.com/ipfs/boxo v0.34.1-0.20250902010009-373354403a53 h1:Vzxu8WxN7feiFLzLBuiogktGvuaxhvqiQXjtDtFo2Ow= +github.com/ipfs/boxo v0.34.1-0.20250902010009-373354403a53/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0= github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA= github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU= github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk= diff --git a/go.mod b/go.mod index d0450842a88..2a450d88e4e 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/hashicorp/go-version v1.7.0 github.com/ipfs-shipyard/nopfs v0.0.14 github.com/ipfs-shipyard/nopfs/ipfs v0.25.0 - github.com/ipfs/boxo v0.34.1-0.20250830162938-3025889071e9 + github.com/ipfs/boxo v0.34.1-0.20250902010009-373354403a53 github.com/ipfs/go-block-format v0.2.2 github.com/ipfs/go-cid v0.5.0 github.com/ipfs/go-cidutil v0.1.0 diff --git a/go.sum b/go.sum index f90c1657790..bae01494ff3 100644 --- a/go.sum +++ b/go.sum @@ -354,8 +354,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.25.0 h1:OqNqsGZPX8zh3eFMO8Lf8EHRRnSGBMqcd github.com/ipfs-shipyard/nopfs/ipfs v0.25.0/go.mod h1:BxhUdtBgOXg1B+gAPEplkg/GpyTZY+kCMSfsJvvydqU= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= -github.com/ipfs/boxo v0.34.1-0.20250830162938-3025889071e9 h1:p8YZ6IaH9jB9oMbgbAug/DNOSh/YpHLcqe8z3qQFMo0= -github.com/ipfs/boxo v0.34.1-0.20250830162938-3025889071e9/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0= +github.com/ipfs/boxo v0.34.1-0.20250902010009-373354403a53 h1:Vzxu8WxN7feiFLzLBuiogktGvuaxhvqiQXjtDtFo2Ow= +github.com/ipfs/boxo v0.34.1-0.20250902010009-373354403a53/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0= github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA= github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU= github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk= diff --git a/test/cli/identity_cid_test.go b/test/cli/identity_cid_test.go index 64b2288e1a7..61a464ac5f7 100644 --- a/test/cli/identity_cid_test.go +++ b/test/cli/identity_cid_test.go @@ -51,8 +51,8 @@ func TestIdentityCIDOverflowProtection(t *testing.T) { res := node.RunIPFS("add", "--hash=identity", tempFile) assert.NotEqual(t, 0, res.ExitErr.ExitCode()) - // should error with identity digest too large message - assert.Contains(t, res.Stderr.String(), "identity digest too large") + // should error with digest too large message + assert.Contains(t, res.Stderr.String(), "digest too large") }) t.Run("ipfs add --inline with valid --inline-limit succeeds", func(t *testing.T) { diff --git a/test/dependencies/go.mod b/test/dependencies/go.mod index 999528ef495..a75203ee1cd 100644 --- a/test/dependencies/go.mod +++ b/test/dependencies/go.mod @@ -134,7 +134,7 @@ require ( github.com/huin/goupnp v1.3.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/ipfs/bbloom v0.0.4 // indirect - github.com/ipfs/boxo v0.34.1-0.20250830162938-3025889071e9 // indirect + github.com/ipfs/boxo v0.34.1-0.20250902010009-373354403a53 // indirect github.com/ipfs/go-bitfield v1.1.0 // indirect github.com/ipfs/go-block-format v0.2.2 // indirect github.com/ipfs/go-cid v0.5.0 // indirect diff --git a/test/dependencies/go.sum b/test/dependencies/go.sum index 044dab31570..4c6e920c28b 100644 --- a/test/dependencies/go.sum +++ b/test/dependencies/go.sum @@ -332,8 +332,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= -github.com/ipfs/boxo v0.34.1-0.20250830162938-3025889071e9 h1:p8YZ6IaH9jB9oMbgbAug/DNOSh/YpHLcqe8z3qQFMo0= -github.com/ipfs/boxo v0.34.1-0.20250830162938-3025889071e9/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0= +github.com/ipfs/boxo v0.34.1-0.20250902010009-373354403a53 h1:Vzxu8WxN7feiFLzLBuiogktGvuaxhvqiQXjtDtFo2Ow= +github.com/ipfs/boxo v0.34.1-0.20250902010009-373354403a53/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0= github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA= github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU= github.com/ipfs/go-block-format v0.2.2 h1:uecCTgRwDIXyZPgYspaLXoMiMmxQpSx2aq34eNc4YvQ= From a48d152ff25a2ac76f1f2283fd1505877a118bd2 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Tue, 2 Sep 2025 03:57:15 +0200 Subject: [PATCH 06/10] docs: changelog --- docs/changelogs/v0.38.md | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/docs/changelogs/v0.38.md b/docs/changelogs/v0.38.md index af7284e1ce2..306ff81e263 100644 --- a/docs/changelogs/v0.38.md +++ b/docs/changelogs/v0.38.md @@ -18,24 +18,19 @@ This release was brought to you by the [Shipyard](https://ipshipyard.com/) team. ### ๐Ÿ”ฆ Highlights -#### ๐Ÿ› ๏ธ Important fixes for `ipfs files write` and `ipfs add --inline-limit` +#### ๐Ÿ› ๏ธ Identity CID size enforcement and `ipfs files write` fixes -Several critical issues with file operations have been fixed: +**Identity CID size limits are now enforced** -**`ipfs add --inline-limit` enforcement**: -- Now enforces a maximum limit respecting `boxo/verifcid.DefaultMaxIdentityDigestSize` -- Identity CIDs (multihash code 0x00) embed data directly without cryptographic verification -- Attempts to use `--inline-limit` values larger than `DefaultMaxIdentityDigestSize` will return an error: - ``` - Error: inline-limit 256 exceeds maximum allowed size of 128 bytes - ``` -- Protects IPFS nodes and gateways from potential abuse while maintaining compatibility with existing valid use cases +Identity CIDs use [multihash `0x00`](https://github.com/multiformats/multicodec/blob/master/table.csv#L2) to embed data directly in the CID without hashing, which is useful for tiny data where a CID reference would be larger than the data itself. However, without size limits these could waste resources and enable abuse. This release enforces a maximum of 128 bytes for identity CIDs - attempting to exceed this limit will trigger an automatic switch to cryptographic hashing or return a clear error message. -**`ipfs files write` fixes**: -- **Codec preservation**: Files now correctly preserve raw node codec when modifying data under the chunker threshold, instead of incorrectly forcing everything to dag-pb -- **Raw node append support**: Append operations to raw nodes now work correctly by automatically converting them into UnixFS file structures. Previously these operations would fail with "expected protobuf dag node" errors -- **CID prefix inheritance**: Files with identity CIDs now properly inherit the full CID prefix from parent directories (version, codec, hash type, length), not just the hash type -- **Identity CID overflow prevention**: File modifications now prevent creation of identity CIDs exceeding `DefaultMaxIdentityDigestSize`, automatically switching to proper cryptographic hashes when needed +- `ipfs add --inline-limit` now enforces the 128-byte maximum +- `ipfs add --hash=identity` automatically switches to SHA-256 when data exceeds the limit +- `ipfs files write` prevents creation of oversized identity CIDs + +**Multiple `ipfs files write` bugs have been fixed** + +This release resolves several long-standing MFS issues: raw nodes now preserve their codec instead of being forced to dag-pb, append operations on raw nodes work correctly by converting to UnixFS when needed, and identity CIDs properly inherit the full CID prefix from parent directories. ### ๐Ÿ“ฆ๏ธ Important dependency updates @@ -45,4 +40,4 @@ Several critical issues with file operations have been fixed: -### ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ Contributors \ No newline at end of file +### ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ Contributors From af1cc5d44d4604fb617d0fd744b1bac85a151aef Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Tue, 9 Sep 2025 18:21:29 +0200 Subject: [PATCH 07/10] chore: latest boxo#1018 --- docs/examples/kubo-as-a-library/go.mod | 3 +-- docs/examples/kubo-as-a-library/go.sum | 4 ++-- go.mod | 3 +-- go.sum | 4 ++-- test/dependencies/go.mod | 2 +- test/dependencies/go.sum | 4 ++-- 6 files changed, 9 insertions(+), 11 deletions(-) diff --git a/docs/examples/kubo-as-a-library/go.mod b/docs/examples/kubo-as-a-library/go.mod index 7341019fc53..a076b050dd0 100644 --- a/docs/examples/kubo-as-a-library/go.mod +++ b/docs/examples/kubo-as-a-library/go.mod @@ -7,7 +7,7 @@ go 1.25 replace github.com/ipfs/kubo => ./../../.. require ( - github.com/ipfs/boxo v0.34.1-0.20250902010009-373354403a53 + github.com/ipfs/boxo v0.34.1-0.20250909161646-b497a55cdb60 github.com/ipfs/kubo v0.0.0-00010101000000-000000000000 github.com/libp2p/go-libp2p v0.43.0 github.com/multiformats/go-multiaddr v0.16.1 @@ -82,7 +82,6 @@ require ( github.com/ipfs/go-ds-measure v0.2.2 // indirect github.com/ipfs/go-ds-pebble v0.5.1 // indirect github.com/ipfs/go-fs-lock v0.1.1 // indirect - github.com/ipfs/go-ipfs-delay v0.0.1 // indirect github.com/ipfs/go-ipfs-ds-help v1.1.1 // indirect github.com/ipfs/go-ipfs-pq v0.0.3 // indirect github.com/ipfs/go-ipfs-redirects-file v0.1.2 // indirect diff --git a/docs/examples/kubo-as-a-library/go.sum b/docs/examples/kubo-as-a-library/go.sum index 3065a634503..33a382bb73a 100644 --- a/docs/examples/kubo-as-a-library/go.sum +++ b/docs/examples/kubo-as-a-library/go.sum @@ -287,8 +287,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.25.0 h1:OqNqsGZPX8zh3eFMO8Lf8EHRRnSGBMqcd github.com/ipfs-shipyard/nopfs/ipfs v0.25.0/go.mod h1:BxhUdtBgOXg1B+gAPEplkg/GpyTZY+kCMSfsJvvydqU= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= -github.com/ipfs/boxo v0.34.1-0.20250902010009-373354403a53 h1:Vzxu8WxN7feiFLzLBuiogktGvuaxhvqiQXjtDtFo2Ow= -github.com/ipfs/boxo v0.34.1-0.20250902010009-373354403a53/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0= +github.com/ipfs/boxo v0.34.1-0.20250909161646-b497a55cdb60 h1:/X+7DTnUfXSeYZPhFha6sAxz//HYRPEdn0q+GtDI6D4= +github.com/ipfs/boxo v0.34.1-0.20250909161646-b497a55cdb60/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0= github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA= github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU= github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk= diff --git a/go.mod b/go.mod index 2a450d88e4e..642663dd0d0 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/hashicorp/go-version v1.7.0 github.com/ipfs-shipyard/nopfs v0.0.14 github.com/ipfs-shipyard/nopfs/ipfs v0.25.0 - github.com/ipfs/boxo v0.34.1-0.20250902010009-373354403a53 + github.com/ipfs/boxo v0.34.1-0.20250909161646-b497a55cdb60 github.com/ipfs/go-block-format v0.2.2 github.com/ipfs/go-cid v0.5.0 github.com/ipfs/go-cidutil v0.1.0 @@ -146,7 +146,6 @@ require ( github.com/huin/goupnp v1.3.0 // indirect github.com/ipfs/bbloom v0.0.4 // indirect github.com/ipfs/go-bitfield v1.1.0 // indirect - github.com/ipfs/go-ipfs-delay v0.0.1 // indirect github.com/ipfs/go-ipfs-ds-help v1.1.1 // indirect github.com/ipfs/go-ipfs-pq v0.0.3 // indirect github.com/ipfs/go-ipfs-redirects-file v0.1.2 // indirect diff --git a/go.sum b/go.sum index bae01494ff3..840624bca45 100644 --- a/go.sum +++ b/go.sum @@ -354,8 +354,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.25.0 h1:OqNqsGZPX8zh3eFMO8Lf8EHRRnSGBMqcd github.com/ipfs-shipyard/nopfs/ipfs v0.25.0/go.mod h1:BxhUdtBgOXg1B+gAPEplkg/GpyTZY+kCMSfsJvvydqU= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= -github.com/ipfs/boxo v0.34.1-0.20250902010009-373354403a53 h1:Vzxu8WxN7feiFLzLBuiogktGvuaxhvqiQXjtDtFo2Ow= -github.com/ipfs/boxo v0.34.1-0.20250902010009-373354403a53/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0= +github.com/ipfs/boxo v0.34.1-0.20250909161646-b497a55cdb60 h1:/X+7DTnUfXSeYZPhFha6sAxz//HYRPEdn0q+GtDI6D4= +github.com/ipfs/boxo v0.34.1-0.20250909161646-b497a55cdb60/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0= github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA= github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU= github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk= diff --git a/test/dependencies/go.mod b/test/dependencies/go.mod index a75203ee1cd..42cdb0c0c9d 100644 --- a/test/dependencies/go.mod +++ b/test/dependencies/go.mod @@ -134,7 +134,7 @@ require ( github.com/huin/goupnp v1.3.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/ipfs/bbloom v0.0.4 // indirect - github.com/ipfs/boxo v0.34.1-0.20250902010009-373354403a53 // indirect + github.com/ipfs/boxo v0.34.1-0.20250909161646-b497a55cdb60 // indirect github.com/ipfs/go-bitfield v1.1.0 // indirect github.com/ipfs/go-block-format v0.2.2 // indirect github.com/ipfs/go-cid v0.5.0 // indirect diff --git a/test/dependencies/go.sum b/test/dependencies/go.sum index 4c6e920c28b..4f67300e514 100644 --- a/test/dependencies/go.sum +++ b/test/dependencies/go.sum @@ -332,8 +332,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= -github.com/ipfs/boxo v0.34.1-0.20250902010009-373354403a53 h1:Vzxu8WxN7feiFLzLBuiogktGvuaxhvqiQXjtDtFo2Ow= -github.com/ipfs/boxo v0.34.1-0.20250902010009-373354403a53/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0= +github.com/ipfs/boxo v0.34.1-0.20250909161646-b497a55cdb60 h1:/X+7DTnUfXSeYZPhFha6sAxz//HYRPEdn0q+GtDI6D4= +github.com/ipfs/boxo v0.34.1-0.20250909161646-b497a55cdb60/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0= github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA= github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU= github.com/ipfs/go-block-format v0.2.2 h1:uecCTgRwDIXyZPgYspaLXoMiMmxQpSx2aq34eNc4YvQ= From d0ae0d99c7b945c3ade07e0f8b8e8355a06a3467 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Tue, 9 Sep 2025 18:38:56 +0200 Subject: [PATCH 08/10] docs: clarify identity CIDs as experimental optimization highlight that identity CIDs were an experimental feature that was easy to misuse and could become an anti-pattern without proper limits --- docs/changelogs/v0.38.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelogs/v0.38.md b/docs/changelogs/v0.38.md index 6fb9a3a715c..47c0dd463a0 100644 --- a/docs/changelogs/v0.38.md +++ b/docs/changelogs/v0.38.md @@ -32,7 +32,7 @@ Gateway error pages now provide more actionable information during content retri **Identity CID size limits are now enforced** -Identity CIDs use [multihash `0x00`](https://github.com/multiformats/multicodec/blob/master/table.csv#L2) to embed data directly in the CID without hashing, which is useful for tiny data where a CID reference would be larger than the data itself. However, without size limits these could waste resources and enable abuse. This release enforces a maximum of 128 bytes for identity CIDs - attempting to exceed this limit will trigger an automatic switch to cryptographic hashing or return a clear error message. +Identity CIDs use [multihash `0x00`](https://github.com/multiformats/multicodec/blob/master/table.csv#L2) to embed data directly in the CID without hashing. This experimental optimization was designed for tiny data where a CID reference would be larger than the data itself, but without size limits it was easy to misuse and could turn into an anti-pattern that wastes resources and enables abuse. This release enforces a maximum of 128 bytes for identity CIDs - attempting to exceed this limit will trigger an automatic switch to cryptographic hashing or return a clear error message. - `ipfs add --inline-limit` now enforces the 128-byte maximum - `ipfs add --hash=identity` automatically switches to SHA-256 when data exceeds the limit From aa776fa3cbb263fa41d72cc81d173e1afeee6dba Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Tue, 9 Sep 2025 19:08:42 +0200 Subject: [PATCH 09/10] chore: boxo@main --- docs/examples/kubo-as-a-library/go.mod | 2 +- docs/examples/kubo-as-a-library/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- test/dependencies/go.mod | 2 +- test/dependencies/go.sum | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/examples/kubo-as-a-library/go.mod b/docs/examples/kubo-as-a-library/go.mod index a076b050dd0..5c675b68d7b 100644 --- a/docs/examples/kubo-as-a-library/go.mod +++ b/docs/examples/kubo-as-a-library/go.mod @@ -7,7 +7,7 @@ go 1.25 replace github.com/ipfs/kubo => ./../../.. require ( - github.com/ipfs/boxo v0.34.1-0.20250909161646-b497a55cdb60 + github.com/ipfs/boxo v0.34.1-0.20250909170220-e69f67e94c11 github.com/ipfs/kubo v0.0.0-00010101000000-000000000000 github.com/libp2p/go-libp2p v0.43.0 github.com/multiformats/go-multiaddr v0.16.1 diff --git a/docs/examples/kubo-as-a-library/go.sum b/docs/examples/kubo-as-a-library/go.sum index 33a382bb73a..2db25adf8fb 100644 --- a/docs/examples/kubo-as-a-library/go.sum +++ b/docs/examples/kubo-as-a-library/go.sum @@ -287,8 +287,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.25.0 h1:OqNqsGZPX8zh3eFMO8Lf8EHRRnSGBMqcd github.com/ipfs-shipyard/nopfs/ipfs v0.25.0/go.mod h1:BxhUdtBgOXg1B+gAPEplkg/GpyTZY+kCMSfsJvvydqU= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= -github.com/ipfs/boxo v0.34.1-0.20250909161646-b497a55cdb60 h1:/X+7DTnUfXSeYZPhFha6sAxz//HYRPEdn0q+GtDI6D4= -github.com/ipfs/boxo v0.34.1-0.20250909161646-b497a55cdb60/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0= +github.com/ipfs/boxo v0.34.1-0.20250909170220-e69f67e94c11 h1:EsCbOKE+giLtrFTysnbTzIRQENOiLdcpOY3kV3y6wlU= +github.com/ipfs/boxo v0.34.1-0.20250909170220-e69f67e94c11/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0= github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA= github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU= github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk= diff --git a/go.mod b/go.mod index 642663dd0d0..71a270dda95 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/hashicorp/go-version v1.7.0 github.com/ipfs-shipyard/nopfs v0.0.14 github.com/ipfs-shipyard/nopfs/ipfs v0.25.0 - github.com/ipfs/boxo v0.34.1-0.20250909161646-b497a55cdb60 + github.com/ipfs/boxo v0.34.1-0.20250909170220-e69f67e94c11 github.com/ipfs/go-block-format v0.2.2 github.com/ipfs/go-cid v0.5.0 github.com/ipfs/go-cidutil v0.1.0 diff --git a/go.sum b/go.sum index 840624bca45..636e701e243 100644 --- a/go.sum +++ b/go.sum @@ -354,8 +354,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.25.0 h1:OqNqsGZPX8zh3eFMO8Lf8EHRRnSGBMqcd github.com/ipfs-shipyard/nopfs/ipfs v0.25.0/go.mod h1:BxhUdtBgOXg1B+gAPEplkg/GpyTZY+kCMSfsJvvydqU= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= -github.com/ipfs/boxo v0.34.1-0.20250909161646-b497a55cdb60 h1:/X+7DTnUfXSeYZPhFha6sAxz//HYRPEdn0q+GtDI6D4= -github.com/ipfs/boxo v0.34.1-0.20250909161646-b497a55cdb60/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0= +github.com/ipfs/boxo v0.34.1-0.20250909170220-e69f67e94c11 h1:EsCbOKE+giLtrFTysnbTzIRQENOiLdcpOY3kV3y6wlU= +github.com/ipfs/boxo v0.34.1-0.20250909170220-e69f67e94c11/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0= github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA= github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU= github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk= diff --git a/test/dependencies/go.mod b/test/dependencies/go.mod index 42cdb0c0c9d..008cb676a9d 100644 --- a/test/dependencies/go.mod +++ b/test/dependencies/go.mod @@ -134,7 +134,7 @@ require ( github.com/huin/goupnp v1.3.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/ipfs/bbloom v0.0.4 // indirect - github.com/ipfs/boxo v0.34.1-0.20250909161646-b497a55cdb60 // indirect + github.com/ipfs/boxo v0.34.1-0.20250909170220-e69f67e94c11 // indirect github.com/ipfs/go-bitfield v1.1.0 // indirect github.com/ipfs/go-block-format v0.2.2 // indirect github.com/ipfs/go-cid v0.5.0 // indirect diff --git a/test/dependencies/go.sum b/test/dependencies/go.sum index 4f67300e514..27501efe95b 100644 --- a/test/dependencies/go.sum +++ b/test/dependencies/go.sum @@ -332,8 +332,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= -github.com/ipfs/boxo v0.34.1-0.20250909161646-b497a55cdb60 h1:/X+7DTnUfXSeYZPhFha6sAxz//HYRPEdn0q+GtDI6D4= -github.com/ipfs/boxo v0.34.1-0.20250909161646-b497a55cdb60/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0= +github.com/ipfs/boxo v0.34.1-0.20250909170220-e69f67e94c11 h1:EsCbOKE+giLtrFTysnbTzIRQENOiLdcpOY3kV3y6wlU= +github.com/ipfs/boxo v0.34.1-0.20250909170220-e69f67e94c11/go.mod h1:rXql6ncaLZZfLqDG3Cuw9ZYQKd3rMU5bk1TGXF0+ZL0= github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA= github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU= github.com/ipfs/go-block-format v0.2.2 h1:uecCTgRwDIXyZPgYspaLXoMiMmxQpSx2aq34eNc4YvQ= From d11f151ac7b5382d8077564098929b3edda61b70 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Tue, 9 Sep 2025 19:19:52 +0200 Subject: [PATCH 10/10] docs: fix changelog accuracy for identity CID behavior correct claim that --hash=identity auto-switches to SHA-256; it errors instead --- docs/changelogs/v0.38.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/changelogs/v0.38.md b/docs/changelogs/v0.38.md index 47c0dd463a0..3fe6ab477d9 100644 --- a/docs/changelogs/v0.38.md +++ b/docs/changelogs/v0.38.md @@ -32,10 +32,9 @@ Gateway error pages now provide more actionable information during content retri **Identity CID size limits are now enforced** -Identity CIDs use [multihash `0x00`](https://github.com/multiformats/multicodec/blob/master/table.csv#L2) to embed data directly in the CID without hashing. This experimental optimization was designed for tiny data where a CID reference would be larger than the data itself, but without size limits it was easy to misuse and could turn into an anti-pattern that wastes resources and enables abuse. This release enforces a maximum of 128 bytes for identity CIDs - attempting to exceed this limit will trigger an automatic switch to cryptographic hashing or return a clear error message. +Identity CIDs use [multihash `0x00`](https://github.com/multiformats/multicodec/blob/master/table.csv#L2) to embed data directly in the CID without hashing. This experimental optimization was designed for tiny data where a CID reference would be larger than the data itself, but without size limits it was easy to misuse and could turn into an anti-pattern that wastes resources and enables abuse. This release enforces a maximum of 128 bytes for identity CIDs - attempting to exceed this limit will return a clear error message. -- `ipfs add --inline-limit` now enforces the 128-byte maximum -- `ipfs add --hash=identity` automatically switches to SHA-256 when data exceeds the limit +- `ipfs add --inline-limit` and `--hash=identity` now enforce the 128-byte maximum (error when exceeded) - `ipfs files write` prevents creation of oversized identity CIDs **Multiple `ipfs files write` bugs have been fixed**