Back to Blog

Cakepie 컨트랙트 보안 감사 보고서

Code Auditing
November 30, 2023
9 min read

보고서 매니페스트

항목 설명
클라이언트 Magpie XYZ
대상 CakePie 컨트랙트

버전 이력

버전 날짜 설명
1.0 2023년 11월 30일 최초 배포

1. 소개

1.1 대상 컨트랙트 정보

정보 설명
유형 스마트 컨트랙트
언어 Solidity
접근 방식 반자동 및 수동 검증

이번 감사의 대상은 Magpie XYZ의 CakePie 컨트랙트^1 코드 저장소입니다. CakePie 컨트랙트는 CakeRush 캠페인을 운영하며, 사용자는 PancakeSwap에서 보유한 CAKE 토큰 또는 잠긴 CAKE 포지션을 CakePie로 전환할 수 있습니다. 감사 범위에는 CakeRush.sol과 PancakeStakingBNBChain.sol만 포함되며, 그 외 파일은 이번 감사 범위에 포함되지 않습니다.

감사 프로세스는 반복적으로 진행됩니다. 구체적으로, 발견된 이슈를 수정한 커밋을 감사합니다. 새로운 이슈가 발생할 경우 이 과정을 계속합니다. 감사 중 사용된 커밋 SHA 값은 아래 표에 나타나 있습니다. 본 감사 보고서는 초기 버전(버전 1)의 코드와 감사 보고서의 이슈를 수정하기 위한 새 코드(이후 버전)에 대해 책임집니다.

1.2 보안 모델

위험을 평가하기 위해, OWASP 위험 등급 방법론^2 및 공통 취약점 목록(CWE)^3을 포함하여 업계와 학계에서 널리 채택된 표준 또는 권고사항을 따릅니다. 위험의 전반적인 심각도가능성영향에 의해 결정됩니다. 구체적으로, 가능성은 특정 취약점이 공격자에 의해 발견되고 악용될 가능성을 추정하는 데 사용되며, 영향은 성공적인 악용의 결과를 측정하는 데 사용됩니다.

본 보고서에서 가능성과 영향은 각각 높음낮음 두 가지 등급으로 분류되며, 그 조합은 표 1.1에 나타나 있습니다.

이에 따라 본 보고서에서 측정된 심각도는 높음, 중간, 낮음의 세 가지 범주로 분류됩니다. 완전성을 위해, 위험을 명확히 판단할 수 없는 경우에는 미확정도 사용됩니다.

또한, 발견된 항목의 상태는 다음 네 가지 범주 중 하나에 해당합니다:

  • 미확정 아직 응답 없음.

  • 확인됨 항목이 클라이언트에 접수되었으나 아직 승인되지 않음.

  • 승인됨 항목이 클라이언트에 의해 인식되었으나 아직 수정되지 않음.

  • 수정됨 항목이 클라이언트에 의해 승인 및 수정됨.

2. 발견 사항

개의 잠재적 이슈를 발견했습니다. 또한 개의 권고사항과 하나의 참고사항이 있습니다.

  • 높은 위험: 1

  • 낮은 위험: 1

  • 권고사항: 3

  • 참고사항: 1

ID 심각도 설명 카테고리 상태
1 낮음 매개변수 재설정 후 잠재적 불일치 상태 소프트웨어 보안 수정됨
2 높음 mCake 보상의 반복 청구 소프트웨어 보안 수정됨
3 - 초기화 함수의 매개변수 확인 권고사항 확인됨
4 - CakeRush 컨트랙트의 매개변수 확인 권고사항 수정됨
5 - 수정자의 추가 조건 권고사항 확인됨
6 - 잠재적 중앙화 위험 참고사항 -

세부 사항은 다음 섹션에서 제공됩니다.

2.1 소프트웨어 보안

2.1.1 매개변수 재설정 후 잠재적 불일치 상태

항목 설명
심각도 낮음
상태 버전 2에서 수정됨
도입 버전 버전 1

설명 CakeRush 컨트랙트는 여러 매개변수에 따라 보상을 분배합니다. 다음 함수들은 프로젝트 관리자가 일부 매개변수를 재설정할 수 있도록 합니다:

function resetMultiplier() external onlyOwner {
        uint256 len = rewardMultiplier.length;
        for (uint8 i = 0; i < len; ++i) {
            rewardMultiplier.pop();
            rewardTier.pop();
        }

        tierLength = 0;
    }

    function resetTimeWeighting() external onlyOwner {
        uint256 len = weightedTime.length;
        for (uint8 i = 0; i < len; ++i) {
            weightedTime.pop();
            weighting.pop();
        }

        weightLength = 0;
    }

목록 2.1: CakeRush.sol

그러나 이 함수들은 매개변수만 재설정할 뿐, userInfos 상태 변수에 저장된 사용자 정보는 재설정하지 않습니다. 결과적으로 CakeRush 컨트랙트의 계산이 불일치 상태로 인해 실패할 수 있습니다. 예를 들어, 매개변수가 재설정되어 잘못된 값으로 설정되면 155번 줄의 뺄셈이 정수 언더플로우로 인해 실패할 수 있습니다.

function quoteConvert(
        uint256 _amountToConvert,
        address _account
    )
        external
        view
        returns (
            uint256 newUserFactor,
            uint256 newTotalFactor,
            uint256 newUserWeightedFactor,
            uint256 newWeightedTotalFactor
        )
    {
        if (_amountToConvert == 0 || rewardMultiplier.length == 0 || weighting.length == 0)
            return (0, 0, 0, 0);

        UserInfo storage userInfo = userInfos[_account];
        uint256 accumulated = _amountToConvert + userInfo.converted;

        uint256 factorAccuNoWeighting = 0;
        uint256 i = 1;
        while (i < rewardTier.length && accumulated > rewardTier[i]) {
            factorAccuNoWeighting += (rewardTier[i] - rewardTier[i - 1]) * rewardMultiplier[i - 1];
            i++;
        }
        factorAccuNoWeighting += (accumulated - rewardTier[i - 1]) * rewardMultiplier[i - 1];

        uint256 factorToEarnNoWeighting = (factorAccuNoWeighting / DENOMINATOR) - userInfo.factor;

목록 2.2: CakeRush.sol

더욱 심각한 것은, 매개변수가 재설정된 직후(새 매개변수가 설정되기 전에, 예를 들어 백런닝을 통해) 사용자가 convert 또는 convertWithCakePool을 호출하면 141-142번 줄의 로직으로 인해 컨트랙트 내부에 기록된 총 및 가중 팩터가 재설정될 수 있습니다.

영향 매개변수 재설정은 불일치하고 잘못된 상태를 초래할 수 있습니다.

제안 이전 매개변수를 초기화한 후 새 매개변수를 설정하십시오.

프로젝트 피드백 CakeRush 캠페인이 시작된 이후에는 승수를 재설정하지 않을 것입니다.

2.1.2 mCake 보상의 반복 청구

항목 설명
심각도 높음
상태 버전 3에서 수정됨
도입 버전 버전 2

설명 컨트랙트에 CAKE 토큰을 잠근 후, 사용자는 해당 함수를 통해 mCake 토큰을 보상으로 청구할 수 있습니다. 그러나 이 함수에는 사용자가 보상을 여러 번 청구할 수 있는 문제가 포함되어 있습니다. 다음 코드 세그먼트에서, 금액이 사용자의 금액보다 클 경우 사용자에게 총 금액을 전송하거나 예치합니다. 올바른 구현은 해당 금액만 반환해야 하므로, 현재 구현은 사용자가 mCake 보상을 반복적으로 청구할 수 있도록 허용합니다.

function claim(bool _isStake) external nonReentrant {
        UserInfo storage userInfo = userInfos[msg.sender];
        if (claimedMCake[msg.sender] >= userInfo.converted) revert AlreadyClaimed();
        if (_isStake && userInfo.converted > 0) {
            if (masterCakepie == address(0)) revert MasterCakepieNotSet();
            IERC20(mCakeOFT).safeApprove(address(masterCakepie), userInfo.converted);
            IMasterCakepie(masterCakepie).depositFor(
                address(mCakeOFT),
                address(msg.sender),
                userInfo.converted
            );
        } else if (userInfo.converted > 0) {
            IERC20(mCakeOFT).transfer(msg.sender, userInfo.converted);
            emit Claim(msg.sender, userInfo.converted);
        }

        claimedMCake[msg.sender] = userInfo.converted;
    }

목록 2.3: CakeRush.sol

영향 사용자가 mCake 보상을 반복적으로 청구할 수 있습니다.

제안 보상 청구 로직을 수정하십시오.

2.2 추가 권고사항

2.2.1 초기화 함수의 매개변수 확인

항목 설명
상태 확인됨
도입 버전 버전 1

설명 CakeRush 및 PancakeStakingBNBChain 컨트랙트의 초기화 함수에는 초기화 후 변경할 수 없는 매개변수가 있습니다. 이러한 매개변수는 초기화 함수에서 확인되어야 합니다.

function __CakeRush_init(
        address _cake,
        address _mCakeOFT,
        address _masterCakepie
    ) public initializer {
        __Ownable_init();
        __ReentrancyGuard_init();
        __Pausable_init();
        cake = _cake;
        mCakeOFT = _mCakeOFT;
        masterCakepie = _masterCakepie;
    }

목록 2.4: CakeRush.sol

영향 해당 없음

제안 초기화 함수에서 매개변수를 확인하십시오.

2.2.2 CakeRush 컨트랙트의 매개변수 확인

항목 설명
상태 버전 2에서 수정됨
도입 버전 버전 1

설명 CakeRush 컨트랙트에서 보상 분배와 관련된 여러 매개변수를 추가할 수 있습니다. 그러나 이러한 매개변수가 컨트랙트의 가정에 따라 올바르게 설정되었는지 확인하는 검사가 없습니다. 구체적으로, setMultipler 및 setTimeWeighting 함수에서 추가 조건(즉, rewardTier 및 weightedTime 배열의 단조 증가 속성)을 확인해야 합니다.

function setMultiplier(
        uint256[] calldata _multiplier,
        uint256[] calldata _tier
    ) external onlyOwner {
        if (_multiplier.length == 0 || (_multiplier.length != _tier.length)) revert LengthInvalid();

        for (uint8 i = 0; i < _multiplier.length; ++i) {
            if (_multiplier[i] == 0) revert InvalidAmount();
            rewardMultiplier.push(_multiplier[i]);
            rewardTier.push(_tier[i]);
            tierLength += 1;
        }
    }

목록 2.5: CakeRush.sol

영향 해당 없음

제안 매개변수를 설정하는 함수에서 매개변수를 확인하십시오.

2.2.3 수정자의 추가 조건

항목 설명
상태 확인됨
도입 버전 버전 1

설명 CakeRush 컨트랙트에서 _onlyPancakeStaking 수정자에는 불필요한 조건이 있습니다. 이 수정자의 의미에 따르면 msg.sender != pancakeStaking을 확인하는 것으로 충분합니다.

modifier _onlyPancakeStaking() {
        if (pancakeStaking == address(0) || msg.sender != pancakeStaking)
            revert OnlyPancakeStaking();
        _;
    }

목록 2.6: CakeRush.sol

영향 해당 없음

제안 수정자에서 불필요한 조건을 제거하십시오.

2.3 참고사항

2.3.1 잠재적 중앙화 위험

설명 CakeRush의 소유자는 중요한 설정을 수정할 수 있는 상당한 권한을 보유합니다. 이는 단일 실패 지점을 만듭니다. 공격자가 소유자 계정을 탈취하면 전체 시스템을 무력화할 수 있습니다.

또한, 컨트랙트 내의 CAKE 토큰은 VECake 컨트랙트에 잠그도록 명시적으로 처리되지 않습니다. 대신 CakeRush는 소유자가 모든 CAKE를 출금할 수 있도록 허용하며, 이는 소유자가 출금 후 CAKE 토큰을 잠가야 함을 의미합니다. 그러나 이 로직은 코드 수준에서 보장되지 않으며, 이 또한 중앙화 우려를 가져옵니다.

프로젝트 피드백 팀은 위험을 완화하기 위해 소유자를 멀티시그로 설정했습니다.

3. 공지 및 비고

3.1 면책 조항

본 감사 보고서는 투자 조언이나 개인 추천을 구성하지 않습니다. 토큰, 토큰 판매 또는 기타 제품, 서비스 또는 자산의 잠재적 경제성을 고려하지 않으며, 이를 고려하거나 관련된 것으로 해석되어서는 안 됩니다. 어떠한 주체도 토큰, 제품, 서비스 또는 기타 자산의 매수 또는 매도 결정을 포함하여 어떠한 방식으로도 본 보고서에 의존해서는 안 됩니다.

본 감사 보고서는 특정 프로젝트나 팀에 대한 보증이 아니며, 보고서는 특정 프로젝트의 보안을 보장하지 않습니다. 본 감사는 스마트 컨트랙트의 모든 보안 이슈를 발견한다는 보증을 제공하지 않습니다. 즉, 평가 결과가 추가적인 보안 이슈의 부재를 보장하지 않습니다. 하나의 감사가 포괄적이라고 볼 수 없으므로, 스마트 컨트랙트의 보안을 보장하기 위해 독립적인 감사와 공개 버그 바운티 프로그램을 진행할 것을 항상 권장합니다.

본 감사의 범위는 섹션 1.1에서 언급된 코드로 제한됩니다. 명시적으로 지정되지 않는 한, 언어 자체의 보안(예: Solidity 언어), 기반 컴파일 툴체인 및 컴퓨팅 인프라는 범위에 포함되지 않습니다.

3.2 감사 절차

다음 절차에 따라 감사를 수행합니다.

  • 취약점 탐지 먼저 자동 코드 분석기로 스마트 컨트랙트를 스캔한 후, 보고된 이슈를 수동으로 검증(거부 또는 확인)합니다.

  • 의미 분석 스마트 컨트랙트의 비즈니스 로직을 연구하고, 자동 퍼징 도구(연구팀이 개발)를 사용하여 가능한 취약점에 대한 추가 조사를 수행합니다. 또한 독립적인 감사자와 함께 가능한 공격 시나리오를 수동으로 분석하여 결과를 교차 확인합니다.

  • 권고사항 가스 최적화, 코드 스타일 등 좋은 프로그래밍 관행의 관점에서 개발자에게 유용한 조언을 제공합니다.

주요 구체적인 점검 항목은 다음과 같습니다.

3.2.1 소프트웨어 보안

  • 재진입

  • 서비스 거부(DoS)

  • 접근 제어

  • 데이터 처리 및 데이터 흐름

  • 예외 처리

  • 신뢰할 수 없는 외부 호출 및 제어 흐름

  • 초기화 일관성

  • 이벤트 운영

  • 오류 발생 가능한 무작위성

  • 프록시 시스템의 부적절한 사용

3.2.2 DeFi 보안

  • 의미적 일관성

  • 기능적 일관성

  • 권한 관리

  • 비즈니스 로직

  • 토큰 운영

  • 비상 메커니즘

  • 오라클 보안

  • 화이트리스트 및 블랙리스트

  • 경제적 영향

  • 일괄 전송

3.2.3 NFT 보안

  • 중복 항목

  • 토큰 수신자 검증

  • 오프체인 메타데이터 보안

3.2.4 추가 권고사항

  • 가스 최적화

  • 코드 품질 및 스타일

참고 이전 점검 항목은 주요 항목입니다. 프로젝트의 기능에 따라 감사 과정에서 더 많은 점검 항목을 사용할 수 있습니다.

Sign up for the latest updates
~$160만 손실: Moke 토큰, LpdFi 익스플로잇 | BlockSec 위클리
Security Insights

~$160만 손실: Moke 토큰, LpdFi 익스플로잇 | BlockSec 위클리

2026년 8월 3~9일, BNB 체인에서 2건의 보안 사고가 발생해 총 약 160만 달러의 손실이 발생했으며, 모두 가격 조작이 원인이었습니다. LpdFi(약 69.7만 달러)는 PancakeSwap 유동성 풀을 주문 평가와 이자 정산에 동시 사용해 공격자가 원금을 부풀리고 과도한 이자를 탈취했습니다. Moke Token(약 90.6만 달러)은 조작 가능한 현물 가격과 중복 LP 배당 회계를 결합해 MOKE를 부풀려 BNB 배당을 반복 수령했습니다.

COLDCARD 사건: 지갑의 "무작위" 시드가 무작위가 아니었을 때
Security Insights

COLDCARD 사건: 지갑의 "무작위" 시드가 무작위가 아니었을 때

COLDCARD 펌웨어의 빌드 통합 버그로 비트코인 시드 생성이 취약한 소프트웨어 RNG로 라우팅되어 지갑 시드가 오프라인 복구 가능해졌습니다. 시드 자체의 취약점이므로 펌웨어 업데이트로 해결 불가하며, 2026년 8월 7일 기준 확인된 피해는 1,405 BTC(~9,100만 달러), 비공개 추정치는 최대 2,055 BTC입니다.

~$88M 손실: COLDCARD 및 LULA 익스플로잇 | BlockSec 위클리
Security Insights

~$88M 손실: COLDCARD 및 LULA 익스플로잇 | BlockSec 위클리

2026년 7월 27일~8월 2일, 비트코인과 BNB 체인에서 약 8,800만 달러 손실을 유발한 두 건의 보안 사고가 발생했습니다. COLDCARD 사고는 하드웨어 지갑 펌웨어의 엔트로피 오류로, RNG 매크로 활성화 여부 미확인으로 결정론적 폴백이 실행되어 약 1,370 BTC(~8,800만 달러)가 탈취됐습니다. BNB 체인의 LULA 토큰은 비즈니스 로직 취약점으로 `recycle()` 함수가 악용되어 PancakeSwap V2 유동성에서 약 57만 8천 달러가 유출됐습니다.

Best Security Auditor for Web3

Validate design, code, and business logic before launch. Aligned with the highest industry security standards.

BlockSec Audit