xanoutas/solidity-security-findings huggingface dataset:
Potential Reversion in Transfer due to LSP1 Interface Support Check
Audit: 2023-06-lukso-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-06-lukso/blob/9dbc96410b3052fc0fd9d423249d1fa42958cae8/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol#L454-L469
https://github.com/code-423n4/2023-06-lukso/blob/9dbc96410b3052fc0fd9d423249d1fa42958cae8/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol#L452-L466


# Vulnerability details

SORRY I HAVFE PREVIOUSLY SUBMITTED THIS ISSUE WITHOUT THE FIX... (FIRST TIME WARDEN FORGIVE ME)
## Impact
The transfer function in `LSP7DigitalAssetCore` & `LSP8DigitalAssetCore` includes a mandatory hook, `_notifyTokenSender`, which verifies if the sender supports `_INTERFACEID_LSP1`. However, if a token owner who initially implemented LSP1 interface ceases to support it, this verification fails, causing an error in the transfer function.

This is a significant issue as it can interrupt token transfers in situations like DeFi protocols, where a user might have granted permissions to a swapping pool. For example, an old UniversalProfile (UP) owner could have set a Universal Receiver Delegate under `_LSP1_UNIVERSAL_RECEIVER_DELEGATE_KEY`, which tries to call back setData on the UP. If the UP's new owner is an Externally Owned Account (EOA) that has not modified all keys of the old owner, this callback would fail, causing the transfer function to revert, disrupting swaps or other operations.



## Proof of Concept
This issue could occur when a UP changes its ownership from a contract (e.g., LSP6KeyManager) to an EOA. In such a case, the old Universal Receiver Delegate would attempt to call setData on the UP during the execution of the _notifyTokenSender hook, which would fail because EOAs don't support this function. This would cause a reversion in the transfer function, disrupting operations.

## Tools Used
The issue was identified through manual code review without the use of specific security tools.


## Recommended Mitigation Steps

Implement a `try-catch` block within the `_notifyTokenSender` function to ensure the function doesn't revert if the call fails. This approach can mitigate the immediate risk.


## Assessed type

DoS
Potential Reversion in Transfer due to LSP1 Interface Support Check
Audit: 2023-06-lukso-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-06-lukso/blob/9dbc96410b3052fc0fd9d423249d1fa42958cae8/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol#L452-L467
https://github.com/code-423n4/2023-06-lukso/blob/9dbc96410b3052fc0fd9d423249d1fa42958cae8/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAssetCore.sol#L454-L469


# Vulnerability details

## Impact
The transfer function in `LSP7DigitalAssetCore` & `LSP8DigitalAssetCore` includes a mandatory hook, `_notifyTokenSender`, which verifies if the sender supports `_INTERFACEID_LSP1`. However, if a token owner who initially implemented LSP1 interface ceases to support it, this verification fails, causing an error in the transfer function.

This is a significant issue as it can interrupt token transfers in situations like DeFi protocols, where a user might have granted permissions to a swapping pool. For example, an old UniversalProfile (UP) owner could have set a Universal Receiver Delegate under _LSP1_UNIVERSAL_RECEIVER_DELEGATE_KEY, which tries to call back setData on the UP. If the UP's new owner is an Externally Owned Account (EOA) that has not modified all keys of the old owner, this callback would fail, causing the transfer function to revert, disrupting swaps or other operations.

## Proof of Concept
This issue could occur when a UP changes its ownership from a contract (e.g., LSP6KeyManager) to an EOA. In such a case, the old Universal Receiver Delegate would attempt to call setData on the UP during the execution of the `_notifyTokenSender` hook, which would fail because EOAs don't support it (see LSP20). This would cause a reversion in the transfer function, disrupting operations.

## Tools Used

## Recommended Mitigation Steps


## Assessed type

DoS
Unrestricted Name and Symbol Modification in LSP7 and LSP8 Digital Assets
Audit: 2023-06-lukso-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-06-lukso/blob/9dbc96410b3052fc0fd9d423249d1fa42958cae8/contracts/LSP7DigitalAsset/LSP7DigitalAsset.sol#L28-L29
https://github.com/code-423n4/2023-06-lukso/blob/9dbc96410b3052fc0fd9d423249d1fa42958cae8/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol#L26-L27


# Vulnerability details

I HAVE ALREADY SUBMITTED THIS ISSUE HOWEVER I MESSED UP THE LINKS FOR IT. CAN YOU PLEASE DISREGARD THE PREVIOUS SUBMISSION? 

## Impact
The owner of a contract in LSP8IdentifiableDigitalAsset and LSP7DigitalAsset can arbitrarily change the name and symbol of a token after its deployment. This ability is due to the inheritance of the setData() function from ERC725YCore.sol implemented in LSP4DigitalAssetMetadata.

Such functionality poses a significant risk as these attributes can potentially influence the perceived value and trust of the token in the market. A sudden or unanticipated change in these attributes, like setting them to empty strings, may lead to confusion, decreased trust, and impact the intrinsic value of the token. Therefore, it could lead to market manipulations and potential financial loss for token holders.

## Proof of Concept
The issue is found in the ERC725YCore code, specifically in lines 62-68, where any data key can be overridden. This includes the name and symbol of the tokens under LSP7 and LSP8 contracts.

For direct code references, please see: [ERC725YCore.sol#L62-L68](https://github.com/ERC725Alliance/ERC725/blob/31574e1ac5259713e83c1b299800401a0737d483/implementations/contracts/ERC725YCore.sol#L62-L68)

## Tools Used
The code was reviewed manually without the use of specific security tools.


## Recommended Mitigation Steps

It is advisable to limit the ability to modify the token's name and symbol after the contract deployment. This can be achieved by:

Setting the name and symbol attributes as immutable. Once assigned during contract deployment, these variables cannot be changed.

Overriding the setData() function to disallow the modification of specific keys related to the token's name and symbol. This requires careful implementation to avoid unintentionally restricting modification of other necessary keys.

In general, any function or action that can influence the token's characteristics, perceived value, or operation should have appropriate access controls to prevent misuse and maintain the token's integrity.


## Assessed type

Other
abi.encodePacked() collision due to dynamic types usage that could lead to 
Audit: 2023-06-lukso-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-06-lukso/blob/9dbc96410b3052fc0fd9d423249d1fa42958cae8/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol#L356-L363
https://github.com/code-423n4/2023-06-lukso/blob/9dbc96410b3052fc0fd9d423249d1fa42958cae8/contracts/LSP6KeyManager/LSP6Modules/LSP6SetDataModule.sol#L544-L551


# Vulnerability details

## Impact
The use of abi.encodePacked() could lead to collision due to the dynamic types usage. 
Through abi.encodePacked(), Solidity supports a non-standard packed mode where:
 - Types shorter than 32 bytes are neither zero padded nor sign extended and
 - Dynamic types are encoded in-place and without the length.
 - Array elements are padded, but still encoded in-place
 - Structs as well as nested arrays are not supported.

abi.encode is used if you are dealing with more than one dynamic data type as it prevents collision.
abi.encodePacked takes all types of data and any amount of input.

## Proof of Concept
Contract: LSP6KeyManager

File: LSP6KeyManagerCore.sol

Code link: https://github.com/code-423n4/2023-06-lukso/blob/9dbc96410b3052fc0fd9d423249d1fa42958cae8/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol#L356-L363
code:
bytes memory encodedMessage = abi.encodePacked(
            LSP6_VERSION,
            block.chainid,
            nonce,
            validityTimestamps,
            msgValue,
            payload
        );

Contract: LSP6Modules

File: LSP6SetDataModule.sol

Code link: https://github.com/code-423n4/2023-06-lukso/blob/9dbc96410b3052fc0fd9d423249d1fa42958cae8/contracts/LSP6KeyManager/LSP6Modules/LSP6SetDataModule.sol#L544-L551
code:
length = uint16(
                bytes2(
                    abi.encodePacked(
                        allowedERC725YDataKeysCompacted[pointer],
                        allowedERC725YDataKeysCompacted[pointer + 1]
                    )
                )
            );



## Tools Used
Manual Review

## Recommended Mitigation Steps
According to solidity documentation, if you use abi.encodePacked for signatures, authentication or data integrity, make sure to always use the same types and check that at most one of them is dynamic. Unless there is a compelling reason, abi.encode should be preferred.
Do not use more than one dynamic type in abi.encodePacked(). Instead,use abi.encode() preferably.

Use:

code:
bytes memory encodedMessage = abi.encode(
            LSP6_VERSION,
            block.chainid,
            nonce,
            validityTimestamps,
            msgValue,
            payload
        );

 code:
length = uint16(
                bytes2(
                    abi.encode(
                        allowedERC725YDataKeysCompacted[pointer],
                        allowedERC725YDataKeysCompacted[pointer + 1]
                    )
                )
            );






## Assessed type

en/de-code
Unrestricted Name and Symbol Modification in LSP7 and LSP8 Digital Assets
Audit: 2023-06-lukso-findings
Severity: HIGH

# Lines of code

https://github.com/lukso-network/lsp-smart-contracts/blob/32ad32f942888398bf99b039e98e238c3146c1b3/contracts/LSP7DigitalAsset/LSP7DigitalAsset.sol#L26-L27
https://github.com/lukso-network/lsp-smart-contracts/blob/32ad32f942888398bf99b039e98e238c3146c1b3/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.sol#L24-L25


# Vulnerability details

## Impact
The owner of a contract in `LSP8IdentifiableDigitalAsset` and `LSP7DigitalAsset` can arbitrarily change the name and symbol of a token after its deployment. This ability is due to the inheritance of the `setData()` function from `ERC725YCore.sol` implemented in `LSP4DigitalAssetMetadata`.

Such functionality poses a significant risk as these attributes can potentially influence the perceived value and trust of the token in the market. A sudden or unanticipated change in these attributes, like setting them to empty strings, may lead to confusion, decreased trust, and impact the intrinsic value of the token. Therefore, it could lead to market manipulations and potential financial loss for token holders.

## Proof of Concept
The issue is found in the ERC725YCore code, specifically in lines 62-68, where any data key can be overridden. This includes the name and symbol of the tokens under LSP7 and LSP8 contracts.

For direct code references, please see: [ERC725YCore.sol#L62-L68](https://github.com/ERC725Alliance/ERC725/blob/develop/implementations/contracts/ERC725YCore.sol#L62-L68)

## Tools Used
The code was reviewed manually without the use of specific security tools.
## Recommended Mitigation Steps

It is advisable to limit the ability to modify the token's name and symbol after the contract deployment. This can be achieved by:
-Setting the name and symbol attributes as immutable. Once assigned during contract deployment, these variables cannot be changed.

- Overriding the `setData()` function to disallow the modification of specific keys related to the token's name and symbol. This requires careful implementation to avoid unintentionally restricting modification of other necessary keys.

In general, any function or action that can influence the token's characteristics, perceived value, or operation should have appropriate access controls to prevent misuse and maintain the token's integrity.


## Assessed type

Other
user with ADDEXTENSIONS and CHANGEEXTENSIONS will remove extension unintentional
Audit: 2023-06-lukso-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-06-lukso/blob/9dbc96410b3052fc0fd9d423249d1fa42958cae8/contracts/LSP6KeyManager/LSP6Modules/LSP6SetDataModule.sol#L302-L318


# Vulnerability details

## Summary

Adding extension use 4 bytes function selector to add new extension, and if user with ADDEXTENSIONS permission
also has CHANGEEXTENSIONS permission and wants to add new extension and there is an extension with that function selector, extension will be removed unintentional.

## Impact
- extension will be removed unintentional

## Proof of Concept
user with ADDEXTENSIONS permission and CHANGEEXTENSIONS permission wants to add new extension(not changing it) and LSP6SetDataModule.sol checks that user has both permissions or not, so it will pass, and extension will be removed.
```solidtiy
            // LSP17Extension:<bytes4>
        } else if (bytes12(inputDataKey) == _LSP17_EXTENSION_PREFIX) {
            // same as above. If controller has both permissions, do not read the `target` storage
            // to save gas by avoiding an extra external `view` call.
            if (
                controllerPermissions.hasPermission(
                    _PERMISSION_ADDEXTENSIONS | _PERMISSION_CHANGEEXTENSIONS
                )
            ) {
                return bytes32(0);
            }


            return
                _getPermissionToSetLSP17Extension(
                    controlledContract,
                    inputDataKey
                );
```
## Tools Used

manual

## Recommended Mitigation Steps
Don't pass if the user has both permission, and check that is there any extension with those function selector or not





## Assessed type

Other
msg-value-loop
Audit: 2023-06-lukso-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-06-lukso/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol#L145-L175
https://github.com/code-423n4/2023-06-lukso/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol#L192-L234


# Vulnerability details

## Impact
The use of msg.value in a loop in different places in the contract can introduce potential risks. The contract accepts Ether as part of its execution and relay calls. If the contract's logic does not handle or validate the msg.value appropriately, it can result in unintended Ether transfers. For example, if the contract expects a specific amount of Ether for a particular operation and msg.value is not properly validated, it can lead to Ether being locked in the contract or transferred incorrectly.
## Proof of Concept
LSP6KeyManagerCore.executeBatch(uint256[],bytes[]) use msg.value in a loop: revert LSP6BatchInsufficientValueSent(uint256,uint256)(totalValues,msg.value)

https://github.com/code-423n4/2023-06-lukso/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol#L145-L175

LSP6KeyManagerCore.executeBatch(uint256[],bytes[]) use msg.value in a loop: (totalValues += values[ii]) > msg.value

https://github.com/code-423n4/2023-06-lukso/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol#L145-L175

LSP6KeyManagerCore.executeRelayCallBatch(bytes[],uint256[],uint256[],uint256[],bytes[]) use msg.value in a loop: (totalValues += values[ii]) > msg.value

https://github.com/code-423n4/2023-06-lukso/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol#L192-L234

LSP6KeyManagerCore.executeRelayCallBatch(bytes[],uint256[],uint256[],uint256[],bytes[]) use msg.value in a loop: revert LSP6BatchInsufficientValueSent(uint256,uint256)(totalValues,msg.value)

https://github.com/code-423n4/2023-06-lukso/contracts/LSP6KeyManager/LSP6KeyManagerCore.sol#L192-L234

## Tools Used
Manual analysis
## Recommended Mitigation Steps


## Assessed type

Loop
Setting ownership to zero account in the function _renounceOwnership()
Audit: 2023-06-lukso-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-06-lukso/contracts/LSP14Ownable2Step/LSP14Ownable2Step.sol#L150-L179


# Vulnerability details

## Impact
In the _renounceOwnership() function, the call to _setOwner(address(0)) sets the owner address of the contract to address(0), which represents the zero address in Ethereum. This effectively removes the ownership of the contract, as the zero address is not a valid Ethereum address.
 By setting the ownership to the zero address, the contract effectively loses any controlling entity or authority. No one can claim ownership or execute privileged functions on behalf of the contract. This can lead to a loss of control over critical contract operations and potential security risks.

## Proof of Concept
https://github.com/code-423n4/2023-06-lukso/contracts/LSP14Ownable2Step/LSP14Ownable2Step.sol (line 176)

## Tools Used
Manual analysis
## Recommended Mitigation Steps
To mitigate these risks, it is generally recommended to set the ownership to a valid and trusted address by reverting to the previous owner rather than zero address.


## Assessed type

Error
Lack of check for zero address in the function _transferOwnership before transferring ownership
Audit: 2023-06-lukso-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-06-lukso/contracts/LSP14Ownable2Step/LSP14Ownable2Step.sol#L126


# Vulnerability details

## Impact
The absence of a check for the zero address (address(0)) when transferring ownership can lead to unintended consequences and potential fund loss.  If the contract allows transferring ownership to the zero address (address(0)), it effectively means relinquishing ownership of the contract. This can result in a loss of control over the contract and its associated functions and data.

## Proof of Concept
https://github.com/code-423n4/2023-06-lukso/contracts/LSP14Ownable2Step/LSP14Ownable2Step.sol#L145-L168 (starting from line 126)

## Tools Used
Manual analysis

## Recommended Mitigation Steps
To mitigate these risks, it is crucial to include a check to prevent transferring ownership to the zero address.








## Assessed type

Error
Incorrect Bitwise Shift Operation in _validateCall Function
Audit: 2023-06-lukso-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-06-lukso/blob/9dbc96410b3052fc0fd9d423249d1fa42958cae8/contracts/LSP20CallVerification/LSP20CallVerification.sol#L80


# Vulnerability details

## Impact

Let's break down this part of the function:

```
if (
    returnedData.length < 32 ||
    bytes28(bytes32(returnedData) << 32) != bytes28(0)
) revert LSP20InvalidMagicValue(postCall, returnedData);

```

This if statement is intended to do two things, as indicated by the two conditions separated by || (OR):

1) Check if returnedData.length is less than 32. If it is, the function reverts because the returned data should contain at least 32 bytes.

2)
bytes32(returnedData): This casts returnedData to a bytes32 type. If returnedData is less than 32 bytes, it's right-padded with zeros to reach 32 bytes. If it's more than 32 bytes, only the first 32 bytes are taken.
bytes32(returnedData) << 32: This shifts the bytes32 value 32 bits to the left, which effectively discards the leftmost 4 bytes (32 bits) of the bytes32 value and shifts the remaining bytes to the left, filling in zeros from the right.
bytes28(bytes32(returnedData) << 32): This casts the result to bytes28, effectively taking the leftmost 28 bytes of the bytes32 value.
bytes28(bytes32(returnedData) << 32) != bytes28(0): This checks if the bytes28 value is not all zeros.
Now, let's consider the comments above the if statement, which suggest that the purpose of this condition is to check if the first 4 bytes of returnedData (when interpreted as a bytes32 value) contain a non-zero bytes4 value.

The current code does not fulfill this purpose because the left shift operation discards these 4 bytes, so they are not part of the bytes28 value that is being checked. In other words, the condition is not checking the right part of the data.

The correct approach would be to right-shift the bytes32 value by 224 bits (which is equivalent to 28 bytes), so that the leftmost 4 bytes (which contain the potential bytes4 value) are moved to the rightmost part of the bytes32 value. Then, you can cast the result to bytes4 and check if it's not equal to bytes4(0), like so:


```
if (
    returnedData.length < 32 ||
    bytes4(bytes32(returnedData) >> 224) != bytes4(0)
) revert LSP20InvalidMagicValue(postCall, returnedData);

```

This code correctly checks if the first 4 bytes of returnedData contain a non-zero bytes4 value. If returnedData is less than 32 bytes, or its first 4 bytes are all zeros when interpreted as a bytes4 value, the function will revert.




## Assessed type

Math
Code Execution on the ERC725Account in ILSP6KeyManager.sol 
Audit: 2023-06-lukso-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2023-06-lukso/blob/main/contracts/LSP6KeyManager/ILSP6KeyManager.sol#L74
https://github.com/code-423n4/2023-06-lukso/blob/main/contracts/LSP6KeyManager/ILSP6KeyManager.sol#L84


# Vulnerability details

## Impact
The ILSP6KeyManager interface has a few potential security vulnerabilities. These vulnerabilities allow an attacker to execute malicious code on the ERC725Account, bypass nonce checking, and bypass timestamp checking.

These vulnerabilities could be exploited by an attacker to gain unauthorized access to the ERC725Account. This could allow the attacker to steal funds, execute arbitrary code, or take other malicious actions.


## Proof of Concept
pragma solidity ^0.8.4;

import {IERC1271, ILSP6KeyManager} from "@openzeppelin/contracts/interfaces/IERC1271.sol";

contract PoC {

    address public immutable keyManager;

    constructor(address _keyManager) {
        keyManager = _keyManager;
    }

    function executeRelayCall() public {
        bytes memory payload = abi.encodePacked("call this function");
        uint256 nonce = 1;
        uint256 validityTimestamps = 0;

        keyManager.executeRelayCall(
            "",
            nonce,
            validityTimestamps,
            payload
        );
    }

}


This PoC contract simply calls the executeRelayCall function on the ILSP6KeyManager interface. The executeRelayCall function allows anyone to execute code on the ERC725Account, as long as they have a signed message from an executor. In this case, the PoC contract does not have a signed message from an executor, but the executeRelayCall function will still execute the code in the payload.

To run the PoC, you will need to deploy it to a testnet and then call the executeRelayCall function. Once the function is called, the code in the payload will be executed on the ERC725Account.

This PoC demonstrates that the ILSP6KeyManager interface is vulnerable to an attacker who can execute malicious code on the ERC725Account. This vulnerability could be exploited by an attacker to steal funds, execute arbitrary code, or take other malicious actions.



## Tools Used

## Recommended Mitigation Steps
The executeRelayCall function should only allow executors to execute code on the ERC725Account. This could be done by checking the signature against a list of authorized executors.
The executeRelayCallBatch function should check the nonce for each call in the batch. This could be done by storing the nonce for each address in a mapping.
The executeRelayCall function should not allow the caller to specify the validity timestamps for the payload. Instead, the validity timestamps should be generated by the KeyManager and stored in the payload.


## Assessed type

Other