DatingDapp

First Flight #33
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: low
Invalid

Malicious Profile Image URL Injection

Summary

The SoulboundProfileNFT contract in this dating platform allows any arbitrary URL for profile images, enabling attackers to inject malicious scripts and conduct XSS attacks through profile metadata.

Vulnerability Details

contract SoulboundProfileNFT {
struct Profile {
string name;
uint8 age;
- string profileImage; // No URL validation
}
function mintProfile(
string memory name,
uint8 age,
- string memory profileImage // Accepts any URL
) external {
require(profileToToken[msg.sender] == 0, "Profile already exists");
uint256 tokenId = ++_nextTokenId;
_safeMint(msg.sender, tokenId);
_profiles[tokenId] = Profile(name, age, profileImage);
}
}

POC

All malicious URLS are accepted

function testMaliciousURLs() public {
// Test malicious URLs
string[] memory attacks = new string[](3);
attacks[0] = "javascript:alert('xss')";
attacks[1] = "<script>alert('hack')</script>";
attacks[2] = "data:text/html;base64,PHNjcmlwdD5hbGVydCgnaGFjaycpPC9zY3JpcHQ+";
for(uint i = 0; i < attacks.length; i++) {
vm.startPrank(address(uint160(i + 1)));
// All these malicious URLs are accepted
soulboundNFT.mintProfile("Attack", 25, attacks[i]);
vm.stopPrank();
}
}

Impact

  • XSS attacks through profile images

  • Malicious script injection

  • Display of malicious content

Recommendations

Adding a util function that validates URLS from the user.

string public constant IPFS_PREFIX = "ipfs://";
function isValidIPFSUrl(string memory url) internal pure returns (bool) {
bytes memory urlBytes = bytes(url);
bytes memory prefix = bytes(IPFS_PREFIX);
if (urlBytes.length < prefix.length) return false;
// Check IPFS prefix
for (uint i = 0; i < prefix.length; i++) {
if (urlBytes[i] != prefix[i]) return false;
}
return true;
}
contract SoulboundProfileNFT {
struct Profile {
string name;
uint8 age;
+ string profileImage; // Should be IPFS only
}
function mintProfile(
string memory name,
uint8 age,
+ string memory profileImage // Should validate IPFS format
) external {
require(profileToToken[msg.sender] == 0, "Profile already exists");
+ require(isValidIPFSUrl(profileImage), "Invalid image URL");
uint256 tokenId = ++_nextTokenId;
_safeMint(msg.sender, tokenId);
_profiles[tokenId] = Profile(name, age, profileImage);
}
}
Updates

Appeal created

n0kto Lead Judge 3 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Informational or Gas

Please read the CodeHawks documentation to know which submissions are valid. If you disagree, provide a coded PoC and explain the real likelyhood and the detailed impact on the mainnet without any supposition (if, it could, etc) to prove your point.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.