From 55e2001a0b7d3cb1060909c45ee737435969f9d2 Mon Sep 17 00:00:00 2001 From: Muzry Date: Sat, 22 Nov 2025 05:51:03 +0800 Subject: [PATCH] Check the JWT secret length (#15939) **What type of PR is this?** Bug fix **What does this PR do? Why is it needed?** Previously, JWT secrets longer than 256 bits could cause client compatibility issues. For example, Prysm would accept longer secrets while Geth strictly requires exactly 32 bytes, causing Geth startup failures when using the same secret file. This change enforces the Engine API specification requirement that JWT secrets must be exactly 256 bits (32 bytes), ensuring consistent behavior across different client implementations. **Which issues(s) does this PR fix?** Fixes # **Other notes for review** **Acknowledgements** - [x] I have read [CONTRIBUTING.md](https://github.com/prysmaticlabs/prysm/blob/develop/CONTRIBUTING.md). - [x] I have included a uniquely named [changelog fragment file](https://github.com/prysmaticlabs/prysm/blob/develop/CONTRIBUTING.md#maintaining-changelogmd). - [x] I have added a description to this PR with sufficient context for reviewers to understand this PR. --------- Co-authored-by: james-prysm <90280386+james-prysm@users.noreply.github.com> --- changelog/muzry-fix-jwt-length.md | 2 ++ cmd/beacon-chain/execution/options.go | 6 +++--- cmd/beacon-chain/execution/options_test.go | 14 +++++++++++++- 3 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 changelog/muzry-fix-jwt-length.md diff --git a/changelog/muzry-fix-jwt-length.md b/changelog/muzry-fix-jwt-length.md new file mode 100644 index 0000000000..149f7dc521 --- /dev/null +++ b/changelog/muzry-fix-jwt-length.md @@ -0,0 +1,2 @@ +### Fixed +- Check the JWT secret length is exactly 256 bits (32 bytes) as per Engine API specification diff --git a/cmd/beacon-chain/execution/options.go b/cmd/beacon-chain/execution/options.go index a1a4325ced..3b505bfdba 100644 --- a/cmd/beacon-chain/execution/options.go +++ b/cmd/beacon-chain/execution/options.go @@ -41,7 +41,7 @@ func FlagOptions(c *cli.Context) ([]execution.Option, error) { // // The secret must be stored as a hex-encoded string within a file in the filesystem. // If the --jwt-secret flag is provided to Prysm, but the file cannot be read, or does not contain a hex-encoded -// key of at least 256 bits, the client should treat this as an error and abort the startup. +// key of 256 bits, the client should treat this as an error and abort the startup. func parseJWTSecretFromFile(c *cli.Context) ([]byte, error) { jwtSecretFile := c.String(flags.ExecutionJWTSecretFlag.Name) if jwtSecretFile == "" { @@ -59,8 +59,8 @@ func parseJWTSecretFromFile(c *cli.Context) ([]byte, error) { if err != nil { return nil, err } - if len(secret) < 32 { - return nil, errors.New("provided JWT secret should be a hex string of at least 32 bytes") + if len(secret) != 32 { + return nil, errors.New("provided JWT secret should be a hex string of 32 bytes") } log.Infof("Finished reading JWT secret from %s", jwtSecretFile) return secret, nil diff --git a/cmd/beacon-chain/execution/options_test.go b/cmd/beacon-chain/execution/options_test.go index e62a3d3181..9b7cbf6171 100644 --- a/cmd/beacon-chain/execution/options_test.go +++ b/cmd/beacon-chain/execution/options_test.go @@ -63,7 +63,19 @@ func Test_parseJWTSecretFromFile(t *testing.T) { set.String(flags.ExecutionJWTSecretFlag.Name, fullPath, "") ctx := cli.NewContext(&app, set, nil) _, err := parseJWTSecretFromFile(ctx) - require.ErrorContains(t, "should be a hex string of at least 32 bytes", err) + require.ErrorContains(t, "should be a hex string of 32 bytes", err) + }) + t.Run("more than 32 bytes", func(t *testing.T) { + app := cli.App{} + set := flag.NewFlagSet("test", 0) + fullPath := filepath.Join(t.TempDir(), "foohex") + secret := bytesutil.PadTo([]byte("foo"), 33) + hexData := fmt.Sprintf("%#x", secret) + require.NoError(t, file.WriteFile(fullPath, []byte(hexData))) + set.String(flags.ExecutionJWTSecretFlag.Name, fullPath, "") + ctx := cli.NewContext(&app, set, nil) + _, err := parseJWTSecretFromFile(ctx) + require.ErrorContains(t, "should be a hex string of 32 bytes", err) }) t.Run("bad data", func(t *testing.T) { app := cli.App{}