Assessment reports>Pyth Lazer>Critical findings>Signature bypass
Category: Coding Mistakes

Signature bypass

Critical Severity
Critical Impact
Low Likelihood

Description

verify_message incorrectly assumes that the layout of the calldata passed to the VerifyMessage instruction is as follows:

 Offset  Size  Handler argument name/Significance
      0     8  ANCHOR HEADER
      8     4  message_data length (4+64+32+2+psz)
     12        message_data
     12     4    SOLANA_FORMAT_MAGIC
     16    64    signature
     80    32    pubkey
    112     2    payload size (psz)
    114   psz    payload
114+psz     2  ed25519_instruction_index
116+psz     1  signature_index
117+psz     2  message_offset

Under this assumption, message_offset has a value of 12, referencing the offset of the data of the message_data vector in the raw encoding of the calldata for the VerifyMessage instruction.

The verify_message function performs several checks on the data contained in message_data using offsets computed assuming the storage layout outlined above.

However, if the calldata layout and message_offset are adjusted in the following way:

       Offset  Size  Handler argument name/Significance
            0     8  ANCHOR HEADER
            8     4  message_data length (4+64+32+2+psz)
           12        message_data
           12     4    SOLANA_FORMAT_MAGIC
           16    64    <UNUSED>
           80    32    PK1
          112     2    payload1 size (psz1)
          114  psz1    payload1
     114+psz1     4    <UNUSED>
     118+psz1    64    valid signature for PK2
     182+psz1    32    PK2
     214+psz1     2    payload2 size (psz2)
     216+psz1   psz    payload2
216+psz1+psz2     2  ed25519_instruction_index
218+psz1+psz2     1  signature_index
219+psz1+psz2     2  message_offset (114+psz1)

The verify_message function will read the public key, payload size and payload appearing earlier in the calldata, while the ec25519 instruction will reference the latter instances.

Thus, verify_message will incorrectly check that the PK1 public key appears in the list of trusted signers, while the ec25519 instruction will require a signature from a different PK2 public key. Additionally, the signed payload and the payload returned by verify_message also differ arbitrarily both in their content and their size.

Impact

If exploited, this issue allows to completely bypass signature verification of a price feed update, allowing to forge a price feed update with an arbitrary payload and that appears to originate from any address in the set of trusted signers.

The exploitability of this issue is conditional on the program invoking the VerifyMessage instruction. The attacker needs to have control over the message_offset provided to VerifyMessage. The official integration examples provided by Pyth Data Association did not allow the end user to specify the offset provided to the VerifyMessage instruction. These preconditions lower the likelyhood of the vulnerability. However, Lazer integrations are not required to use the examples provided by Pyth Data Association, and there seems to be some more advanced and reasonable scenarios where a program integrating with Lazer could give an attacker control over the offset argument.

Recommendations

It appears to be possible to entirely remove the message_offset argument, fixing its value to 12, which would constrain the data referenced by the ec25519 program to be aligned with the start of the message_data argument of the VerifyMessage instruction. Note that the offset used by the ec25519 program would still need to be checked to be 12 if removing the message_offset argument.

Remediation

This issue has been acknowledged by Pyth Data Association, and a fix was implemented in PR #2250.

The PR added a check requiring the message_data processed by the verify_message function to match the data considered by the ec25519 program.

Additionally, the message_offset argument indicating the start of the message data processed by the ec25519 program was removed.

The code could not be simplified further by requiring a stricter layout for the data processed by the ec25519 program, as Pyth Data Association indicated this flexibility is a requirement.

Zellic © 2025Back to top ↑