> For the complete documentation index, see [llms.txt](https://paymasterdocs.gitbook.io/paymasterdocs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://paymasterdocs.gitbook.io/paymasterdocs/vectors-of-paymaster/general-vectors/signature-reuse-risk.md).

# Signature Reuse Risk

## Cross-chain signature replay attack possibility

{% hint style="info" %}
The signature must include the chainId
{% endhint %}

Like in a `VerifyingPaymaster`, when the paymaster includes logic to verify signatures, there are cases where it generates a separate hash using the `getHash` function instead of using the `userOpHash` passed as a parameter. If the `getHash` function in the paymaster does not include the `chainId`, there is a risk of the paymaster’s signature being reused across different chains.

\*\*The userOpHash is generated by the Entrypoint and includes the chainId.

Example Code:

```solidity
src/vulnerableVerifyingPaymaster.sol

function getHash(UserOperation calldata userOp)
    public view returns (bytes32) { // @audit change to view
        //can't use userOp.hash(), since it contains also the paymasterAndData itself.
        return keccak256(abi.encode(
                userOp.getSender(),
                userOp.nonce,
                keccak256(userOp.initCode),
                keccak256(userOp.callData),
                userOp.callGasLimit,
                userOp.verificationGasLimit,
                userOp.preVerificationGas,
                userOp.maxFeePerGas,
                userOp.maxPriorityFeePerGas
            ));
    }
```

* Mitigation : Include the `chainId` in the `getHash` function, or use the `userOpHash` passed as a parameter.

```solidity
src/goodVerifyingPaymaster.sol

function getHash(UserOperation calldata userOp)
    public view returns (bytes32) { // @audit change to view
        //can't use userOp.hash(), since it contains also the paymasterAndData itself.
        return keccak256(abi.encode(
                userOp.getSender(),
                userOp.nonce,
                keccak256(userOp.initCode),
                keccak256(userOp.callData),
                userOp.callGasLimit,
                userOp.verificationGasLimit,
                userOp.preVerificationGas,
                userOp.maxFeePerGas,
                userOp.maxPriorityFeePerGas,
+		block.chainid // @audit add chain id
            ));
    }
```

***

## Signature without Nonce.

{% hint style="info" %}
The signature must include the Nonce.
{% endhint %}

Like in a `VerifyingPaymaster`, when the paymaster includes logic to verify signatures, there are cases where it generates a separate hash using the `getHash` function instead of using the `userOpHash` passed as a parameter. If the `getHash` function in the paymaster does not include the `nonce`, there is a risk of the paymaster’s signature being reused.

\*\* The userOpHash is generated by the Entrypoint and includes the nonce of UserOperation.

If the paymaster’s signature is reused, users could repeatedly submit the same UserOperation, which may drain the paymaster’s funds.

Exmaple Code:

```solidity
src/vurnerableVerifyingPaymaster.sol

function getHash(UserOperation calldata userOp)
    public view returns (bytes32) { // @audit change to view
        //can't use userOp.hash(), since it contains also the paymasterAndData itself.
        return keccak256(abi.encode(
                userOp.getSender(),
                keccak256(userOp.initCode),
                keccak256(userOp.callData),
                userOp.callGasLimit,
                userOp.verificationGasLimit,
                userOp.preVerificationGas,
                userOp.maxFeePerGas,
                userOp.maxPriorityFeePerGas,
		block.chainid
            ));
    }
```

* Mitigation : Include the `nonce` in the `getHash` function, or use the `userOpHash` passed as a parameter.

```solidity
src/goodVerifyingPaymaster.sol

function getHash(UserOperation calldata userOp)
    public view returns (bytes32) { // @audit change to view
        //can't use userOp.hash(), since it contains also the paymasterAndData itself.
        return keccak256(abi.encode(
                userOp.getSender(),
+               userOp.nonce,
                keccak256(userOp.initCode),
                keccak256(userOp.callData),
                userOp.callGasLimit,
                userOp.verificationGasLimit,
                userOp.preVerificationGas,
                userOp.maxFeePerGas,
                userOp.maxPriorityFeePerGas,
		block.chainid
            ));
    }
```
