This function is used to construct the metadata and returns the metadata URI for a given set of characteristics, under which the SVGs are being generated via generateSVGInfo & generateSVGArt(), issue however is that there is no sanitzation of input data done in anywhere while generating these SVGs, considering both generateSVGInfo() &generateSVGArt(), just ingest whatever data is available from querying even the symbols of the token via which an injection attack could be placed, see https://github.com/code-423n4/2024-06-panoptic/blob/153f0d82440b7e63075d55b0659706531431145f/contracts/base/FactoryNFT.sol#L124-L177
function generateSVGArt(
uint256 lastCharVal,
uint256 rarity
) internal view returns (string memory svgOut) {
svgOut = metadata[bytes32("frames")][
rarity < 18 ? rarity / 3 : rarity < 23 ? 23 - rarity : 0
].decompressedDataStr();
svgOut = svgOut.replace(
"<!-- LABEL -->",
write(
metadata[bytes32("strategies")][lastCharVal].dataStr(),
maxStrategyLabelWidth(rarity)
)
);
svgOut = svgOut
.replace(
"<!-- TEXT -->",
metadata[bytes32("descriptions")][lastCharVal + 16 * (rarity / 8)]
.decompressedDataStr()
)
.replace("<!-- ART -->", metadata[bytes32("art")][lastCharVal].decompressedDataStr())
.replace("<!-- FILTER -->", metadata[bytes32("filters")][rarity].decompressedDataStr());
}
/// @notice Fill in the pool/rarity specific text fields on the SVG artwork.
/// @param svgIn The SVG artwork to complete
/// @param panopticPool The address of the Panoptic Pool
/// @param rarity The rarity of the NFT
/// @param symbol0 The symbol of `token0` in the Uniswap pool
/// @param symbol1 The symbol of `token1` in the Uniswap pool
/// @return The final SVG artwork with the pool/rarity specific text fields filled in
function generateSVGInfo(
string memory svgIn,
address panopticPool,
uint256 rarity,
string memory symbol0,
string memory symbol1
) internal view returns (string memory) {
svgIn = svgIn
.replace("<!-- POOLADDRESS -->", LibString.toHexString(uint160(panopticPool), 20))
.replace("<!-- CHAINID -->", getChainName());
svgIn = svgIn.replace(
"<!-- RARITY_NAME -->",
write(metadata[bytes32("rarities")][rarity].dataStr(), maxRarityLabelWidth(rarity))
);
return
svgIn
.replace("<!-- RARITY -->", write(LibString.toString(rarity)))
.replace("<!-- SYMBOL0 -->", write(symbol0, maxSymbolWidth(rarity)))
.replace("<!-- SYMBOL1 -->", write(symbol1, maxSymbolWidth(rarity)));
}
Impact
The process of generating the SVGs is vulnerable to the popular JSON injection attack, considering no validation is being done on the data to be attached to the SVGs and external data re queried to set it up like the token's symobl() which are all windows as to how this attack would be processed.
Lines of code
https://github.com/code-423n4/2024-06-panoptic/blob/153f0d82440b7e63075d55b0659706531431145f/contracts/base/FactoryNFT.sol#L58-L118
Vulnerability details
Proof of Concept
Take a look at https://github.com/code-423n4/2024-06-panoptic/blob/153f0d82440b7e63075d55b0659706531431145f/contracts/base/FactoryNFT.sol#L58-L118
This function is used to construct the metadata and returns the metadata URI for a given set of characteristics, under which the SVGs are being generated via
generateSVGInfo
&generateSVGArt()
, issue however is that there is no sanitzation of input data done in anywhere while generating these SVGs, considering bothgenerateSVGInfo()
&generateSVGArt()
, just ingest whatever data is available from querying even the symbols of the token via which an injection attack could be placed, see https://github.com/code-423n4/2024-06-panoptic/blob/153f0d82440b7e63075d55b0659706531431145f/contracts/base/FactoryNFT.sol#L124-L177Impact
The process of generating the SVGs is vulnerable to the popular JSON injection attack, considering no validation is being done on the data to be attached to the SVGs and external data re queried to set it up like the token's
symobl()
which are all windows as to how this attack would be processed.Recommended Mitigation Steps
Always sanitize the input data
Assessed type
Context