Submitted by juancito, also found by Emmanuel
Follows in Lens v2 can be checked via isFollowing(), which returns the internal storage variable _followTokenIdByFollowerProfileId[followerProfileId] and cant be manipulated by an unauthorized party via any of the follow/unfollow functions, as they have proper access control checks.
This is also prevented on token transfers in Lens v2. If user A wraps their follow token and transfer it to user B, it doesnt mean that user B is following user A.
But using the tryMigrate() it is possible to force someone to follow another user without their consent.
Users can make any other user follow them.
For a social network this could even be considered a high severity issue, as follow actions are a core component of them, and migrations were marked as an Area of specific concern by the devs.
Unauthorized follow actions not only harm the user, by performing a crutial action without their consent, but may also affect other users.
It could be used for example to make prestigious profiles follow scam accounts, unwillingly ligitimating them.
Extra note: An adversary can execute this attack at any time. They can prevent having their follow NFT being migrated by frontrunning the migrate tx, and moving their token to another wallet. The migration will run silently with no error, and the attack can be performed later.
Follows can be checked by the isFollowing() function, which is dependant on the _followTokenIdByFollowerProfileId[followerProfileId] mapping. _followTokenIdByFollowerProfileId is unset for Lens v1:
The expected way to update _followTokenIdByFollowerProfileId is via the _baseFollow() internal function, which can only be called via other external functions protected with access control, only authorizing the profile owner who will follow or a delegate:
FollowNFT.sol#L386-L391
However the tryMigrate() function also updates _followDataByFollowTokenId to help with migrations from V1, and can be called by anyone (via the hub):
FollowNFT.sol#L514
The only caveat is that the ProfileNFT and FollowNFT should be in the same account:
FollowNFT.sol#L501-L504
But this can bypassed by simply transfering a V1 follow NFT from anyone to the victim, who will end up following the adversary unwillingly after the execution of tryMigrate().
Also, as noted on the Impact section, an adversary could prevent that someone else tries to migrate their profile, by frontrunning the tx and moving their token to some other address. It will fail silently because of the return 0; // Not holding both Profile & Follow NFTs together on the previous code snippet.
Add this test to test/migrations/Migrations.t.sol and run TESTING_FORK=mainnet POLYGON_RPC_URL="https://polygon.llamarpc.com" forge test --mt "testFakeFollowMigration".
Note: In case of a memory allocation error during the Forge test, please comment these lines. They are not used for the current test.
The follow migration should be reworked to account for the case of fake follows. Some ideas are to allow the bulk process to be run by whitelisted accounts, or by the specific token owners. A combination of both may also work, by only migrating tokens that have been minted but not transfered, for example. Or letting users opt-in for an automatic migration to give some ideas.
Additionally log an event with the reason the migration was not executed for a specific profile.
Invalid Validation
vicnaum (Lens) confirmed
