c0mpos3r

[Secureum] Audit Findings 201 본문

Web3/Hacking

[Secureum] Audit Findings 201

음대생 2025. 7. 12. 02:18

100 more Audit Findings

102. 훅(Hook) 수신 컨트랙트의 잠재적 엣지 케이스 문서화 필요

취약점: 프로토콜의 인출 함수는 사용자가 지정한 임의의 "훅" 컨트랙트를 호출할 수 있습니다. 그런데 누구나 소량의 토큰을 자신이 제어하는 주소로 보낸 뒤 인출하는 방식으로 이 훅을 트리거할 수 있습니다. 이는 사실상 누구나, 어떤 컨트랙트든 훅으로 지정하여 강제로 호출할 수 있음을 의미합니다.

  • 권장 사항: 훅을 수신하는 컨트랙트를 개발하는 개발자들은, 이 훅 함수가 예상치 못한 주체(msg.sender)에 의해 호출될 수 있음을 인지하고, 호출자와 전달된 파라미터를 반드시 검증해야 한다는 내용을 명확히 문서화해야 합니다.
  • 감사 출처: Umbra의 ConsenSys 감사

103. 지원 토큰의 동작 제한 문서화 필요

취약점: 프로토콜이 임의의 ERC-20 토큰과 상호작용하지만, 어떤 종류의 비표준 토큰을 지원하지 않는지 명확하게 문서화하지 않았습니다.

  • 지원되지 않는 토큰 종류 및 문제점:
    • 수수료 부과/디플레이션 토큰: 보낸 양보다 적은 양이 수신되어, 프로토콜 내부 회계가 맞지 않아 자금 손실로 이어집니다.
    • 인플레이션/리베이싱 토큰: 예기치 않게 잔액이 늘어나는 경우를 처리할 메커니즘이 없어 자금 손실로 이어질 수 있습니다.
  • 권장 사항: 위와 같이 지원하지 않는 토큰의 종류와 그 이유를 명시적으로 문서화하여, 사용자들이 해당 토큰을 사용하지 않도록 해야 합니다.
  • 감사 출처: Umbra의 ConsenSys 감사

104. 완전한 테스트 스위트 권장

취약점: 프로젝트의 테스트 스위트가 불완전하고, 일부 테스트는 실행조차 실패했습니다. 여러 프로토콜과 상호작용하는 복잡한 시스템에서 불충분한 테스트 커버리지는, 수동 검토로는 찾기 힘든 버그를 놓치게 만들고 향후 개발의 안정성을 크게 저해합니다.

  • 권장 사항: 엣지 케이스와 실패 시나리오를 포함한 완전한 커버리지의 테스트 스위트를 구축해야 합니다.
  • 감사 출처: DeFi Saver의 ConsenSys 감사

105. Kyber getRates 코드의 가독성 문제

취약점: 코드가 이해하기 어려웠습니다. 함수 이름은 실제 기능을 제대로 반영하지 못했고, 코드에는 문서화되지 않은 가정(예: 슬리피지 값)들이 사용되었습니다. 이는 코드를 유지보수하고 검토하기 어렵게 만들어 버그 발생 가능성을 높입니다.

  • 권장 사항: 실제 기능에 맞게 getSellRate, getBuyRate 등으로 함수를 분리하여 코드를 리팩토링하고, 코드 내의 모든 가정을 명시적으로 문서화해야 합니다.
  • 감사 출처: DeFi Saver의 ConsenSys 감사

106. TokenUtils.withdrawTokens의 반환 값 미사용

취약점: withdrawTokens 함수는 실제로 인출된 토큰의 양을 반환하지만, 이 반환 값이 코드 전체에서 한 번도 사용되거나 확인되지 않았습니다. 만약 요청한 양과 실제 인출된 양이 다른 엣지 케이스가 발생하면, 시스템은 이를 인지하지 못하고 불일치가 발생합니다.

  • 권장 사항: 반환 값을 사용하여 인출이 제대로 되었는지 검증하거나, 발생시키는 이벤트에 포함시켜야 합니다.
  • 감사 출처: DeFi Saver의 ConsenSys 감사

107. DeSaverLogger.Log에 대한 접근 제어 부재

취약점: 시스템 전체에서 사용되는 로깅 컨트랙트의 로그 생성 함수에 아무런 접근 제어가 없었습니다. 이는 누구나 이 함수를 호출하여 가짜 로그를 남겨 오프체인 모니터링 시스템과 사용자들에게 혼란을 줄 수 있음을 의미합니다.

  • 권장 사항: 모든 함수에 적절한 접근 제어를 추가해야 합니다.
  • 감사 출처: DeFi Saver의 ConsenSys 감사

108. 오래된 주석 제거 필요

취약점: 코드에 오래되고 부정확한 주석이 남아있었습니다. 다른 컨트랙트(Uniswap V2)에서 코드를 복사해 온 후, 주석은 수정하지 않아 실제 코드와 주석의 내용이 다른 상태였습니다. 이는 개발자가 코드를 오해하게 만들 수 있습니다.

  • 권장 사항: 오래되거나 실제 코드와 맞지 않는 주석은 제거해야 합니다.
  • 감사 출처: DAO의 ConsenSys 감사

109. 코드와 주석의 불일치

취약점: 코드가 구현하는 내용과 해당 코드를 설명하는 주석의 내용이 일치하지 않았습니다. 이는 코드의 가독성을 해치고 개발자와 감사자에게 혼란을 주어 실수 가능성을 높입니다.

  • 권장 사항: 코드나 주석 중 하나를 업데이트하여 항상 일관성을 유지해야 합니다.
  • 감사 출처: mstable-1.1의 ConsenSys 감사

110. 불필요한 DAOV1Factory.formula() 호출 제거 필요

취약점: 여러 함수에서, 팩토리 컨트랙트의 생성자에서 한 번만 설정되고 절대 변하지 않는 주소값을 얻기 위해 매번 불필요한 외부 호출을 하고 있었습니다. 이는 매번 가스를 낭비하는 비효율적인 패턴입니다.

  • 권장 사항: 불변하는 값은 컨트랙트의 immutable 상태 변수로 저장하여, 생성자에서 한 번만 설정하고 그 이후에는 가스 소모 없이 읽어오도록 해야 합니다.
  • 감사 출처: DAO의 ConsenSys 감사

111. 커브(Curve) 수학에 대한 심층 검증 부족

취약점: 복잡한 수학적 연산, 특히 본딩 커브와 관련된 로직에 대한 엣지 케이스 테스트가 부족했습니다. 이는 예상치 못한 그리고 잠재적으로 위험한 방식으로 실패할 수 있습니다.

  • 권장 사항: 단위 테스트를 추가하고, 퍼징(Fuzzing) 또는 속성 기반 테스트를 도입하여 커브 관련 연산의 견고성을 심층적으로 검증해야 합니다.
  • 감사 출처: DAO의 ConsenSys 감사

112. 제안자가 수락/대기 중인 제안도 취소할 수 있음

취약점: GovernorAlpha 컨트랙트에서 제안자가 자신의 제안을 투표에서 통과되어 실행 대기(Queued) 상태에 있는 제안마저도 취소할 수 있었습니다. 이는 전체 거버넌스 프로세스의 무결성을 훼손하는 심각한 문제입니다.

  • 권장 사항: 제안은 "보류(Pending)" 또는 "활성(Active)" 상태일 때만 취소할 수 있도록 제한해야 합니다.
  • 감사 출처: Fei Protocol의 ConsenSys 감사

113. KYC 관리자 역할 부여 전 지연 기간 요구

취약점: 언제든지 사용자의 자금을 동결시킬 수 있는 강력한 KYC_ADMIN_ROLE을 새로운 주소에 즉시 부여할 수 있었습니다. 만약 관리자 개인키가 탈취될 경우, 공격자는 즉시 이 권한을 획득하여 시스템에 큰 피해를 줄 수 있습니다.

  • 권장 사항: 이 역할을 부여하는 프로세스에 타임락(Timelock)을 도입해야 합니다. 이는 관리자 키가 탈취되더라도 사용자와 커뮤니티가 대응할 수 있는 시간을 벌어줍니다.
  • 감사 출처: eRLC의 ConsenSys 감사

114. 인라인 문서 및 테스트 커버리지 개선 필요

취약점: 코드에 인라인 문서(주석)가 거의 없고, 테스트 커버리지도 제한적이었습니다. 이는 코드를 이해하고, 유지보수하고, 감사하기 어렵게 만들어 버그 발생 가능성을 높입니다.

  • 권장 사항: Natspec 형식에 맞는 인라인 코드 문서를 추가하고, 모든 함수와 잠재적인 엣지 케이스를 포함하도록 테스트 커버리지를 대폭 늘려야 합니다.
  • 감사 출처: 1inch Liquidity Protocol의 ConsenSys 감사

115. 불명확한 컴파일러 버전 프라그마

취약점: 대부분의 컨트랙트에서 ^0.6.0과 같이 플로팅 프라그마(floating pragma)를 사용했습니다. 이는 알려진 취약점이 있는 컴파일러 버전이 실수로 사용될 위험을 내포하며, 보안 도구가 배포된 버전과 다른 버전으로 코드를 분석하여 부정확한 결과를 낼 수도 있습니다.

  • 권장 사항: 배포되는 최상위 컨트랙트에는 항상 특정 컴파일러 버전을 고정(pinning)해야 합니다. (예: pragma solidity 0.6.12;)
  • 감사 출처: 1inch Liquidity Protocol의 ConsenSys 감사

116. 하드코딩된 가스 한도 사용의 문제점

취약점: 코드에 가스 한도가 하드코딩되어 있었습니다. 이더리움의 옵코드별 가스 비용은 향후 네트워크 업그레이드를 통해 변경될 수 있으며, 만약 가스 비용이 증가하면 하드코딩된 한도가 부족해져 컨트랙트가 사용 불가능하게 될 수 있습니다.

  • 권장 사항: 이러한 잠재적 한계를 인지하고, 가스 가격이 시스템에 부정적인 영향을 미치는 방식으로 변경될 경우에 대비해야 합니다.
  • 감사 출처: 1inch Liquidity Protocol의 ConsenSys 감사

117. 누구나 ReferralFeeReceiver의 모든 자금을 훔칠 수 있음

취약점: ReferralFeeReceiver 컨트랙트는 사용자로부터 mooniswap 풀 주소를 입력받는데, 이 주소가 실제로 공식 팩토리에서 배포한 것인지 검증하지 않았습니다.

  • 공격 시나리오: 공격자는 악의적인 풀 컨트랙트를 만든 후, 이 주소를 파라미터로 전달하여 ReferralFeeReceiver가 보유한 모든 토큰과 이더를 자신의 악성 컨트랙트로 옮겨 탈취할 수 있었습니다.
  • 권장 사항: 사용자가 제공한 풀 주소가 신뢰할 수 있는 팩토리에 의해 배포되었는지 반드시 확인해야 합니다.
  • 감사 출처: 1inch Liquidity Protocol의 ConsenSys 감사 (Critical 등급)

118. 관리자 프론트러닝 또는 나쁜 타이밍으로 인한 예측 불가능한 동작

취약점: 관리자가 사용자에게 아무런 경고 없이 시스템의 중요 파라미터를 즉시 업데이트하거나 업그레이드할 수 있었습니다. 악의적인 관리자는 사용자의 트랜잭션을 보고 프론트러닝하여 바로 직전에 시스템을 변경할 수 있으며, 선의의 관리자라도 타이밍이 좋지 않으면 사용자에게 손해를 끼칠 수 있습니다.

  • 권장 사항: 타임락(Time-lock)을 도입하여, 모든 중요한 변경은 '변경 예고'와 '실제 적용'의 2단계로 나누고 그 사이에 의무적인 시간 지연을 두어야 합니다. 이는 사용자들이 변경에 동의하지 않을 경우 자금을 인출할 시간을 줍니다.
  • 감사 출처: 1inch Liquidity Protocol의 ConsenSys 감사

119. 시스템 문서 및 완전한 기술 명세서 개선 필요

취약점: 시스템의 설계 의도와 동작 방식을 이해하는 데 필수적인 문서와 기술 명세서가 매우 부족했습니다. 이는 사용자, 개발자, 감사자 모두에게 시스템을 이해하는 데 큰 장벽이 되며, 결과적으로 시스템의 보안성과 유지보수성을 저해합니다.

  • 권장 사항:  코드 구현만큼이나 중요한 자산으로 간주하고, 사용자와 개발자를 위한 완전한 시스템 문서와 기술 명세서를 작성하고 유지해야 합니다.
  • 감사 출처: Growth DeFi의 ConsenSys 감사

120. 시스템 상태, 역할, 권한이 충분히 제한적이지 않음

취약점: 스마트 컨트랙트 코드는 가능한 한 엄격해야 하지만, 해당 시스템의 상태, 역할, 권한이 느슨하게 정의되어 있었습니다. 이는 예측 불가능한 동작을 유발하고 시스템을 덜 안전하게 만듭니다.

  • 권장 사항: 관리자 권한의 사용처를 명확히 문서화하고 모니터링해야 합니다. 각 컨트랙트의 운영 요구사항을 엄격하게 명시하여 최소 권한 원칙을 지켜야 합니다.
  • 감사 출처: Growth DeFi의 ConsenSys 감사

121. 시스템에 포함시키기 전 모든 토큰을 평가해야 함

취약점: 시스템에 새로운 토큰을 추가할 때, 비표준적인 동작을 하는 토큰을 사전에 평가하지 않았습니다. 특히 다음과 같은 기능이 있는 토큰은 위험할 수 있습니다.

  • 콜백 함수 (예: ERC-777): 트랜잭션 도중 공격자가 임의의 코드를 실행하게 할 수 있습니다. (재진입 공격)
  • 전송 수수료 부과 토큰: 프로토콜의 내부 회계를 망가뜨릴 수 있습니다.
  • 인플레이션/디플레이션 토큰: 예기치 않은 잔액 변화를 유발할 수 있습니다.
  • 권장 사항: 시스템에 새로운 토큰을 포함시키기 전, 해당 토큰의 동작을 반드시 사전에 평가하고 검증해야 합니다.
  • 감사 출처: Growth DeFi의 ConsenSys 감사

122. 컨트랙트와 라이브러리에 서술적인 이름 사용

취약점: 코드베이스에 수많은 컨트랙트와 라이브러리가 있지만, 서술적이지 않은 이름 규칙 때문에 어떤 파일에 어떤 로직이 있는지 파악하기가 매우 어려웠습니다. 이는 코드의 가독성과 탐색 효율을 크게 저해합니다.

  • 권장 사항: 컨트랙트와 라이브러리에 그 기능을 명확히 설명하는 서술적인 이름을 사용해야 합니다.
  • 감사 출처: Growth DeFi의 ConsenSys 감사

123. 완전히 초기화되기 전에 컨트랙트 사용 방지

취약점: 많은 컨트랙트들이 완전히 초기화되거나 구성이 완료되지 않은 불안정한 상태에서도 사용자의 자금 예치/인출을 허용했습니다. 이는 너무나 많은 상태 조합을 만들어내어, 모든 시나리오에서 컨트랙트가 예상대로 동작할지 판단하는 것을 거의 불가능하게 만듭니다.

  • 권장 사항: 컨트랙트가 완전히 초기화되기 전까지는 사용자의 상호작용을 막아야 합니다.
  • 감사 출처: Growth DeFi의 ConsenSys 감사

124. 경계 없는 루프 내 외부 호출로 인한 리소스 고갈 가능성

취약점: 잠재적으로 경계가 없는 루프 안에서 외부 프로토콜(DyDx)을 호출했습니다. 만약 외부 프로토콜의 가스 비용 정책이 변경되면, 이 루프를 실행하는 데 드는 비용이 감당할 수 없을 정도로 비싸지거나, 심지어 블록 가스 한도 때문에 실행이 불가능해질 수 있습니다.

  • 권장 사항: 해당 루프를 재고하거나, 반복 횟수에 합리적인 상한선을 설정해야 합니다.
  • 감사 출처: Growth DeFi의 ConsenSys 감사

125. 소유자가 절대 제거되지 않음

취약점: setOwners() 함수는 기존 소유자들을 새로운 소유자들로 교체하기 위한 것이지만, 새로운 소유자를 추가만 할 뿐 기존 소유자들을 isOwner 매핑에서 제거하지 않았습니다. 이는 한 번 소유자였던 주소는 영원히 소유자로 남아 서명 권한을 갖게 되는 심각한 접근 제어 문제입니다.

  • 권장 사항: setOwners() 함수에서 새로운 소유자를 추가하기 전에, 먼저 루프를 통해 기존 소유자들의 isOwner 상태를 false로 초기화해야 합니다.
  • 감사 출처: Paxos의 ConsenSys 감사 (Critical 등급)

126. 플래시 론을 이용한 안정 이자율 조작 가능성

취약점: 플래시 론을 이용해 대량의 유동성을 순간적으로 예치하거나 인출함으로써, 프로토콜의 안정 이자율을 인위적으로 올리거나 내리는 조작이 가능했습니다.

  • 권장 사항: 플래시 론을 이용한 이런 종류의 조작은 막기 매우 어렵습니다. 프로토콜은 이자율이 정상적인 값으로 재조정되는지 항상 모니터링해야 합니다.
  • 감사 출처: Aave Protocol V2의 ConsenSys 감사

127. 검증된 자산만 화이트리스트에 추가해야 함

취약점: 일부 기능이 토큰의 정상적인 동작에 의존하기 때문에, 만약 악의적인 토큰이 화이트리스트에 추가되면 시스템에 문제가 발생할 수 있습니다. 예를 들어, 특정 토큰으로 투표하는 것을 막거나, 잔액을 조작하여 불공정한 이점을 얻을 수 있습니다.

  • 권장 사항: 화이트리스트에 새로운 자산을 추가할 때는, 반드시 해당 시스템의 컨텍스트 내에서 자산을 감사하고 검증해야 합니다.
  • 감사 출처: Aave Governance DAO의 ConsenSys 감사

128. 토큰 소수점이 18보다 크면 언더플로우 발생

취약점: 코드에서 토큰의 소수점(TOKEN_DECIMALS)이 18 이하일 것이라고 가정했습니다. 만약 18보다 큰 소수점을 가진 토큰이 추가되면, 계산 과정에서 언더플로우(underflow)가 발생합니다.

  • 권장 사항: 생성자(constructor)에 추가된 토큰의 소수점이 18 이하인지 확인하는 간단한 검증 로직을 추가해야 합니다.
  • 감사 출처: Aave CPM Price Provider의 ConsenSys 감사

129. 가격 변동성이 큰 시기의 체인링크 성능 고려

취약점/리스크: 프로토콜이 체인링크 오라클에 의존하지만, 시장의 가격 변동성이 극심할 때 오라클 가격이 실제 시장 가격과 얼마나 크게 벗어날 수 있는지에 대한 리스크 분석이 부족했습니다.

  • 권장 사항: 가격 변동성이 컸던 과거 시점의 체인링크 가격 데이터를 검토하여, 실제 시장 가격과의 최대 편차(delta)를 분석하고 잠재적 리스크를 평가해야 합니다.
  • 감사 출처: Aave CPM Price Provider의 ConsenSys 감사

130. 점진적인 출시 접근법 고려 및 최악 시나리오 대비

취약점/리스크: 시스템이 수많은 복잡한 구성요소를 가지고 있으면서도, 명확한 업그레이드 경로가 없었습니다. 모든 것을 한 번에 출시하는 것은 매우 위험합니다.

권장 사항:

  1. 최소 기능 제품(Minimum Viable System)에 필수적인 구성요소를 식별하고, 먼저 그것들의 보안을 확보하는 데 집중해야 합니다.
  2. 그 후, 다른 구성요소들을 점진적으로 출시하는 접근법을 취해야 합니다.
  3. 시스템의 초기 단계에는 시스템을 일시 중지하고 업그레이드할 수 있는 방법을 마련해 두어야 합니다.
  • 감사 출처: Lien Protocol의 ConsenSys 감사

131. 반복되는 확인 로직에 수정자(modifier) 사용

개선점: 여러 다른 함수 내에서 공통적으로 반복되는 확인 로직(예: require(isInitialized))이 있었습니다. 코드 중복은 가독성을 해치고 버그 발생 가능성을 높입니다.

  • 권장 사항: 반복되는 확인 로직은 수정자(modifier)로 만들어 코드 중복을 줄이고 가독성을 향상시켜야 합니다.
  • 감사 출처: Balancer Finance의 ConsenSys 감사

132. 수정자(modifier) 순서 변경

취약점: 함수에서 수정자가 _logs_, _lock_ 순서로 사용되었습니다. _lock_은 재진입을 방지하는 가드이므로, 다른 어떤 로직보다도 가장 먼저 실행되어야 합니다.

  • 권장 사항: 재진입 방지 수정자(_lock_)는 항상 다른 수정자들보다 앞에 위치시켜, 함수가 호출될 때 가장 먼저 실행되고 가장 마지막에 종료되도록 보장해야 합니다.
  • 감사 출처: Balancer Finance의 ConsenSys 감사

133. 코드베이스의 취약성(fragility) 해결

취약점: 시스템이 "취약(fragile)"하게 설계되어, 한 부분의 변경이 개념적으로 관련 없는 다른 부분에 예기치 않은 부수 효과를 일으킬 수 있었습니다. 이런 코드는 유지보수가 어렵고 쉽게 망가지는 경향이 있습니다.

  • 권장 사항: 견고한 시스템을 만들기 위해 다음 개념을 우선시해야 합니다.
    1. 단일 책임 원칙: 함수는 하나의 기능만 잘 수행하도록 만듭니다.
    2. 외부 시스템 의존도 줄이기: 외부 요인에 의해 시스템이 영향을 받는 것을 최소화합니다.
  • 감사 출처: MCDEX Mai Protocol V2의 ConsenSys 감사

134. 재진입으로 인한 부정확한 이벤트 발생 순서

취약점: Checks-Effects-Interactions 패턴을 위반하여, 외부 호출(Interaction)이 이벤트 발생(Effect)보다 먼저 일어났습니다.

  • 공격 시나리오: 재진입 공격을 통해, 두 번째(재진입) 호출의 이벤트가 첫 번째 호출의 이벤트보다 먼저 발생하는 등 이벤트 순서가 뒤섞일 수 있습니다. 이는 오프체인 모니터링 도구에 시스템 상태에 대한 잘못된 정보를 제공합니다.
  • 권장 사항: Checks-Effects-Interactions 패턴을 적용하여, 이벤트 발생을 외부 호출보다 먼저 하도록 순서를 변경해야 합니다.
  • 감사 출처: Liquidity의 ToB 감사

135. OUSD와 ERC20 간의 변수 섀도잉

취약점: OUSD 컨트랙트가 ERC20을 상속받으면서, 부모에 이미 존재하는 _allowances와 _totalSupply 상태 변수를 재정의했습니다. 이러한 변수 섀도잉은 해당 변수에 접근할 때 어떤 값이 반환될지 예측할 수 없게 만들어 혼란과 버그를 유발합니다.

  • 권장 사항: OUSD 컨트랙트에서 섀도잉된 변수들을 제거해야 합니다.
  • 감사 출처: Origin Dollar의 ToB 감사

136. rebase 함수에 return문 누락

취약점: 함수 시그니처에는 uint를 반환하도록 명시되어 있지만, 실제 함수 코드에는 return문이 누락되거나 일부 경로에만 존재했습니다. 이로 인해 함수는 항상 기본값인 0만 반환하게 되어, 이 반환 값에 의존하는 다른 외부 코드가 오작동할 수 있습니다.

  • 권장 사항: 누락된 return문을 추가하거나, 반환 값이 필요 없다면 함수 시그니처에서 반환 타입을 제거해야 합니다.
  • 감사 출처: Origin Dollar의 ToB 감사

137. 다수의 컨트랙트에 상속 누락

취약점: 여러 컨트랙트가 특정 인터페이스의 구현체임에도 불구하고, 해당 인터페이스로부터 명시적으로 상속(is IMyInterface)받지 않았습니다. 이는 컴파일러가 해당 컨트랙트가 인터페이스를 올바르게 준수하는지 확인해주지 않아, 향후 코드 업데이트 시 실수를 유발할 수 있습니다.

  • 권장 사항: 컨트랙트가 구현하는 인터페이스로부터 명시적으로 상속받도록 해야 합니다.
  • 감사 출처: Origin Dollar의 ToB 감사

18. 솔리디티 컴파일러 최적화의 위험성

취약점/리스크: 프로젝트에서 선택적 컴파일러 최적화를 활성화했습니다. 하지만 이 최적화 기능은 기본 설정만큼 충분히 테스트되지 않았으며, 과거에 여러 차례 심각한 보안 버그가 발견된 이력이 있습니다. 최적화 관련 버그는 예기치 않은 결과를 초래할 수 있습니다.

  • 권장 사항: 최적화를 통해 얻는 가스 절감 효과와, 최적화 관련 버그가 발생할 가능성의 위험을 신중하게 비교 평가해야 합니다. 프로덕션 환경에서 사용하기 전에는 기술의 성숙도를 꾸준히 모니터링해야 합니다.
  • 감사 출처: Yield Protocol의 ToB 감사

139. 지나치게 단순하고 유연하지 못한 권한 부여 시스템

취약점: 권한 시스템이 너무 단순하여, 권한을 부여받은 모든 주소가 모든 제한된 함수를 호출할 수 있었습니다. 세분화된 제어가 불가능했고, 권한을 부여받은 주소를 제거할 수도 없었습니다. 이는 최소 권한 원칙을 위반합니다.

  • 권장 사항: 특정 주소는 특정 함수에만 접근할 수 있도록 허용하는 세분화된 권한 시스템으로 재작성해야 합니다.
  • 감사 출처: Yield Protocol의 ToB 감사

140. 만기일 설정 시 유효성 검사 부재

취약점: 컨트랙트 배포 시 파라미터로 받는 만기일(maturity) 타임스탬프에 대해 아무런 유효성 검사를 수행하지 않았습니다. 이로 인해 실수로 과거의 날짜나 아주 먼 미래의 날짜를 만기일로 설정하여 컨트랙트가 쓸모없게 될 수 있었습니다.

  • 권장 사항: 생성자(constructor)에 만기일 타임스탬프가 합리적인 범위 내에 있는지 확인하는 검증 로직을 추가해야 합니다.
  • 감사 출처: Yield Protocol의 ToB 감사

141. 위임(delegate)이 반복적으로 추가/제거되어 로그를 부풀림

취약점: 사용자가 이미 추가된 대리인을 반복적으로 추가하거나, 이미 제거된 대리인을 반복적으로 제거하는 것을 막는 확인 절차가 없었습니다. 이로 인해 상태 변경이 없음에도 불구하고 중복된 이벤트가 계속 발생하여 로그를 부풀리는(bloat) 문제가 있었습니다.

  • 권장 사항: 대리인을 추가/제거하기 전에, 먼저 현재 위임 상태를 확인하는 require 구문을 추가하여 상태가 실제로 변경될 때만 이벤트가 발생하도록 해야 합니다.
  • 감사 출처: Yield Protocol의 ToB 감사

142. 중요 작업에 대한 이벤트 부재

취약점: 여러 중요한 작업들이 이벤트를 발생시키지 않아, 컨트랙트가 배포된 후 올바른 동작을 검토하기가 매우 어려웠습니다. 이벤트가 없으면 사용자와 블록체인 모니터링 시스템이 의심스러운 행동을 쉽게 감지할 수 없습니다.

  • 권장 사항: 모든 중요 작업에는 적절한 이벤트를 추가해야 합니다. 장기적으로는 블록체인 모니터링 시스템을 사용하여 의심스러운 활동을 추적하는 것을 고려해야 합니다.
  • 감사 출처: 0x Protocol의 ToB 감사

143. _assertStakingPoolExists가 절대 true를 반환하지 않음

취약점: 스테이킹 풀이 존재하는지 확인하는 _assertStakingPoolExists 함수는 bool을 반환하도록 선언되었지만, 실제 코드에는 return true 구문이 누락되어 있었습니다. 이 함수는 항상 false를 반환하거나 revert 되므로, 의도된 대로 사용할 수 없었습니다.

  • 권장 사항: 누락된 return true 구문을 추가하거나, 함수 시그니처에서 반환 타입을 제거해야 합니다.
  • 감사 출처: 0x Protocol의 ToB 감사

144. _min*, _max*의 비정상적인 의미 사용

취약점: 코드에서 _minTargetAmount(최소 목표량)와 같은 변수 이름을 사용하면서, 실제 로직은 해당 값을 포함하지 않는 열린 범위(예: > _minTargetAmount)로 구현했습니다. 이는 일반적으로 "최소"라는 용어가 해당 값을 포함하는 닫힌 범위(>=)를 의미하는 것과 반대되어 매우 혼란스럽습니다.

  • 권장 사항: 의도된 것이 아니라면, 부등호를 >에서 >=로 변경해야 합니다. 또는, 변수 이름 자체를 exclusiveMinTargetAmount처럼 그 의미를 명확히 알 수 있도록 변경하는 것을 고려해야 합니다.
  • 감사 출처: DFX Finance의 ToB 감사

145. newCurve가 기존 커브를 반환함

취약점: newCurve 함수는 새로운 커브를 생성해야 하지만, 만약 해당 토큰 쌍에 대한 커브가 이미 존재할 경우, revert 시키는 대신 기존에 있던 커브를 조용히 반환했습니다. 사용자는 자신이 제공한 파라미터로 새로운 커브가 생성되었다고 착각할 수 있지만, 실제로는 전혀 다른 파라미터를 가진 기존 커브를 받게 되어 자금 손실로 이어질 수 있습니다.

  • 권장 사항: newCurve 함수는 해당 쌍이 이미 존재할 경우 revert 시켜야 합니다. 사용자는 view 함수를 통해 가스비 없이 커브의 존재 여부를 미리 확인할 수 있어야 합니다.
  • 감사 출처: DFX Finance의 ToB 감사

146. transferOwnership 및 생성자의 0번 주소 체크 누락

취약점: Router 컨트랙트의 생성자와 Curve 컨트랙트의 transferOwnership 함수에서 0번 주소(address(0))를 확인하지 않았습니다. Router가 0번 주소로 초기화되면 사용할 수 없게 되고, 소유권이 0번 주소로 이전되면 관리자 기능이 영원히 잠길 수 있습니다.

  • 권장 사항: 운영자의 실수를 방지하기 위해 Router 생성자와 transferOwnership 함수에 0번 주소 확인 로직을 추가하는 것을 고려해야 합니다.
  • 감사 출처: DFX Finance의 ToB 감사

147. safeApprove가 approve 호출의 반환 값을 확인하지 않음

취약점: 프로젝트가 OpenZeppelin의 SafeERC20을 사용하는 대신, 자체적으로 safeApprove 함수를 구현했습니다. 하지만 이 자체 구현 함수는 approve 호출이 성공했는지 여부는 확인하면서도, true를 반환했는지는 확인하지 않았습니다. 이는 OpenZeppelin 라이브러리가 해결하려 했던 바로 그 문제를 다시 도입하는 것입니다.

  • 권장 사항: 자체적으로 재구현하는 대신, 가능한 한 널리 검증된 OpenZeppelin의 safeApprove 함수를 활용해야 합니다.
  • 감사 출처: DFX Finance의 ToB 감사

148. ERC-20 토큰이 symbol, name, decimals를 구현하지 않음

취약점: Curve.sol은 ERC-20 토큰의 필수 함수는 모두 구현했지만, 선택적이지만 사실상 표준인 symbol, name, decimals 함수를 구현하지 않았습니다. 대부분의 지갑, 블록 탐색기, DApp 프론트엔드 등 외부 생태계는 이 함수들이 존재할 것으로 기대하기 때문에, 이들이 없으면 통합이 매우 어렵습니다.

  • 권장 사항: symbol, name, decimals 함수를 구현하여 업계 표준을 준수해야 합니다.
  • 감사 출처: DFX Finance의 ToB 감사

149. SafeMath의 불충분한 사용

취약점: 코드베이스 다른 곳에서는 SafeMath를 사용하면서도, 정작 중요한 거래량 계산 로직(CurveMath.calculateTrade)에서는 SafeMath를 사용하지 않았습니다. 비록 실제로 오버플로우가 발생할 수 있음을 증명하지는 못했지만, 중요한 산술 연산을 보호하지 않은 채로 두는 것은 위험하고 일관성이 없습니다.

  • 권장 사항: 모든 중요한 산술 연산을 검토하고, SafeMath를 일관되게 사용하여 오버플로우/언더플로우를 방지해야 합니다.
  • 감사 출처: DFX Finance의 ToB 감사

150. setFrozen 함수가 프론트러닝에 악용될 수 있음

취약점: 컨트랙트 소유자는 setFrozen 함수를 사용하여 스왑과 예금을 막을 수 있습니다. 악의적인 소유자는 멤풀에서 사용자의 대규모 예치/스왑 트랜잭션을 보고, 이를 프론트러닝하여 먼저 setFrozen을 호출해 사용자의 거래를 막은 후, 나중에 동결을 풀어 시장 정보로부터 부당 이득을 취할 수 있습니다.

  • 권장 사항: 이러한 단기적인 조작을 막기 위해, 동결(freeze)이 최소한의 기간 동안 지속되도록 하거나, 혹은 영구적으로 만들어서 악용 인센티브를 줄이는 것을 고려해야 합니다.
  • 감사 출처: DFX Finance의 ToB 감사

151. 계정 생성 스팸

취약점: 계정 생성에 수수료가 없고, 시스템이 허용하는 총 계정 수에 한계가 있었습니다. 공격자는 이 점을 악용하여 계정 생성 트랜잭션을 스팸처럼 보내 시스템을 가득 채워, 정상적인 신규 사용자들이 가입하지 못하도록 막는 서비스 거부(DoS) 공격을 할 수 있습니다. 특히 이더리움 채굴자는 L1 가스비를 내지 않으므로 이 공격에 더 유리합니다.

  • 권장 사항: 계정 생성에 수수료를 추가하거나, 총 계정 한도를 충분히 높게 설정해야 합니다. 또한, 악의적인 스팸 활동을 모니터링하고 커뮤니티에 알려야 합니다.
  • 감사 출처: Hermez Network의 ToB 감사

152. 인터페이스 대신 빈 함수를 사용하여 오류에 취약한 컨트랙트

취약점: 인터페이스로 사용되어야 할 컨트랙트(WithdrawalDelayerInterface)가, 함수 시그니처만 선언하는 interface가 아닌 빈 함수 몸체를 가진 contract로 정의되었습니다. 이 경우, 이 컨트랙트를 상속받는 자식 컨트랙트는 컴파일러로부터 함수를 반드시 구현해야 한다는 강제를 받지 않게 되어, 구현을 누락하는 등 예기치 않은 오류를 유발할 수 있습니다.

  • 권장 사항: contract 대신 interface 키워드를 사용하여, 이를 상속받는 컨트랙트들이 인터페이스를 올바르게 따르도록 강제해야 합니다.
  • 감사 출처: Hermez Network의 ToB 감사

153. 존재하지 않는 트랜잭션에 대해 cancelTransaction 호출 가능

취약점: cancelTransaction 함수가, 취소하려는 트랜잭션이 실제로 대기열에 존재하는지 확인하지 않고 취소 이벤트를 발생시켰습니다. 악의적인 관리자는 이 점을 악용하여 존재하지 않는 트랜잭션에 대한 가짜 취소 이벤트를 무수히 발생시켜, 오프체인 모니터링 시스템과 사용자들에게 혼란을 줄 수 있습니다.

  • 권장 사항: 트랜잭션을 취소하기 전에, 반드시 해당 트랜잭션이 존재하는지 확인하는 로직을 추가해야 합니다.
  • 감사 출처: Hermez Network의 ToB 감사

154. 의존성 컨트랙트의 업스트림 변경 사항 미추적

취약점: 제3자 라이브러리 코드를 npm이나 git submodule과 같은 의존성 관리 도구를 사용하지 않고, 소스 코드를 그대로 복사-붙여넣기하여 사용했습니다. 또한, 사용된 코드의 정확한 버전이나 수정 여부도 기록하지 않았습니다. 이는 해당 라이브러리에서 발견된 치명적인 보안 취약점이나 업데이트를 놓치게 만들어 시스템을 위험에 빠뜨립니다.

  • 권장 사항: 외부 라이브러리는 NPM이나 Git 서브모듈과 같은 의존성 관리 도구를 사용하여 체계적으로 관리하고, 각 의존성의 출처와 버전을 명확히 문서화해야 합니다.
  • 감사 출처: Hermez Network의 ToB 감사

155. 토큰 추가 권한에 대한 불분명한 동작

취약점: 온라인 문서에는 오직 거버넌스만이 새로운 토큰을 등록할 수 있다고 되어 있지만, 실제 코드 구현은 누구나 새로운 토큰을 등록할 수 있도록 허용했습니다. 이처럼 문서와 코드의 내용이 불일치하는 것은, 시스템의 의도된 동작이 무엇인지 불분명하게 만들어 혼란을 야기합니다.

  • 권장 사항: 구현이나 문서 중 하나를 수정하여, 토큰 추가 권한에 대한 명세를 일관되게 표준화해야 합니다.
  • 감사 출처: Hermez Network의 ToB 감사

156. 컨트랙트 이름 중복으로 인한 오류 발생

취약점: 코드베이스 내에 동일한 이름을 가진 여러 컨트랙트가 존재했습니다. 이는 buidler-waffle과 같은 컴파일 프레임워크가 잘못된 아티팩트(artifact)를 생성하게 만들며, Slither와 같은 제3자 보안 분석 도구의 사용을 방해하는 등 개발 및 분석 과정에 문제를 일으킵니다.

  • 권장 사항: 중복된 컨트랙트 이름의 사용을 피하거나, 컴파일 프레임워크를 변경해야 합니다.
  • 감사 출처: Hermez Network의 ToB 감사

157. 하드코딩된 주소 사용으로 인한 오류

취약점: 다른 컨트랙트의 주소를 배포 시 파라미터로 받는 대신, 소스 코드에 직접 하드코딩했습니다. 이는 코드를 테스트하거나 다른 네트워크에 재사용하는 것을 극도로 어렵게 만들며, 만약 주소가 잘못 하드코딩될 경우 치명적인 오류를 유발합니다.

  • 권장 사항: 주소는 하드코딩하는 대신, 컨트랙트 생성자(constructor)를 통해 배포 시 설정해야 합니다.
  • 감사 출처: Advanced Blockchains의 ToB 감사

158. 연간 블록 수 근사값에 의존하는 대출 이자율

취약점: 대출 이자율 공식에 연간 블록 생성 수의 근사값이 하드코딩되어 있었습니다. 이 값은 블록 생성 시간(예: 이더리움 메인넷은 약 13초)에 따라 변하며, 다른 블록체인에서는 완전히 다를 수 있습니다. 부정확한 추정치에 의존하는 것은 이자율 계산의 정확성을 떨어뜨립니다.

  • 권장 사항: 실제 연간 블록 수와의 편차로 인해 발생하는 영향을 분석하고, 관련된 위험을 문서화해야 합니다.
  • 감사 출처: Advanced Blockchains의 ToB 감사

159. 플래시 론 이자율에 상한/하한 부재

취약점: 플래시 론 이자율을 설정하는 함수에 상한이나 하한과 같은 경계값 검사가 없었습니다. 악의적인 팀이나 관리자는 이자율을 비정상적으로 높게 설정하여 사용자들의 예금을 탈취하는 데 악용할 수 있습니다.

  • 권장 사항: 시스템의 모든 설정 가능한 파라미터에는 합리적인 상한과 하한을 도입하여, 권한 있는 사용자의 능력을 제한해야 합니다.
  • 감사 출처: Advanced Blockchains의 ToB 감사

160. 코드 전반에 중복된 로직

취약점: 시스템 전반에 걸쳐 상당한 양의 코드가 중복(복사-붙여넣기)되어 있었습니다. 이러한 개발 관행은 버그가 발견되었을 때 모든 복사본을 일일이 수정해야 하므로, 실수를 유발하고 새로운 버그가 도입될 위험을 증가시킵니다.

  • 권장 사항: 상속(inheritance)을 사용하여 공통 로직을 재사용해야 합니다. 이를 통해 코드 변경 시 한 곳만 수정하면 모든 자식 컨트랙트에 적용되도록 할 수 있습니다.
  • 감사 출처: Advanced Blockchains의 ToB 감사

161. 불충분한 테스트

취약점: 검토 중인 리포지토리에 적절한 테스트가 부족했습니다. 이는 개발 과정에서 오류 발생 가능성을 높이고 코드 검토를 더 어렵게 만듭니다.

  • 권장 사항: 단기적으로는 모든 public 함수와 알려진 모든 엣지 케이스를 최소 한 번 이상 다루는 단위 테스트를 보장해야 합니다. 장기적으로는 테스트 커버리지 분석 도구를 개발 프로세스에 통합하고 정기적으로 커버리지를 검토해야 합니다.
  • 감사 출처: Advanced Blockchains의 ToB 감사

162. 프로젝트 의존성에 취약점 포함

취약점: yarn audit을 통해 프로젝트의 의존성(dependencies)에서 알려진 취약점이 발견되었습니다. JavaScript 커뮤니티의 의존성 문제는 배포 코드와 환경의 민감성 때문에 심각한 영향을 미칠 수 있습니다.

  • 권장 사항: 의존성을 최신 상태로 유지하고, 설치 후 무결성을 확인해야 합니다. 자동화된 의존성 감사 도구를 개발 워크플로우에 통합하는 것을 고려해야 합니다.
  • 감사 출처: Advanced Blockchains의 ToB 감사

163. 컨트랙트 문서 부족으로 인한 코드 이해의 어려움

취약점: 코드에 문서, 상위 수준의 설명, 예제가 부족하여 컨트랙트를 검토하기 어렵고 사용자 실수의 가능성을 높입니다.

  • 권장 사항: 코드베이스의 여러 측면을 검토하고 적절히 문서화해야 합니다. 장기적으로는 프로토콜의 공식적인 명세서를 작성하는 것을 고려해야 합니다.
  • 감사 출처: Advanced Blockchains의 ToB 감사

164. 프로덕션에 부적합한 ABIEncoderV2

취약점: 컨트랙트가 새로운 솔리디티 ABI 인코더인 ABIEncoderV2를 사용했습니다. 하지만 당시 이 실험적인 인코더는 프로덕션 환경에 사용할 준비가 되어 있지 않았으며, 심각한 버그들과 연관되어 있었습니다.

  • 권장 사항: ABIEncoderV2나 다른 어떤 실험적인 솔리디티 기능도 프로덕션 환경에서 사용해서는 안 됩니다. 구조체를 함수의 인자로 전달하거나 반환할 필요가 없도록 코드를 리팩토링해야 합니다.
  • 감사 출처: Advanced Blockchains의 ToB 감사

165. 컨트랙트 소유자의 과도한 권한

취약점: 컨트랙트 소유자가 일반 사용자에 비해 너무 많은 권한을 가지고 있었습니다. 이는 단일 실패 지점(single point of failure)을 만들며, 소유자의 개인키가 탈취될 경우 사용자는 모든 자산을 잃을 수 있습니다.

  • 소유자는 시스템 구현을 업그레이드하여 자금을 훔치거나, 보상 분배량을 조작하는 등 막강한 권한을 가졌습니다.
  • 권장 사항
    1. 소유자가 변경할 수 있는 기능과 구현을 명확히 문서화해야 합니다.
    2. 어떤 단일 주소도 시스템에 대한 과도한 소유권을 갖지 않도록 권한을 분리해야 합니다.
  • 감사 출처: dForce Lending의 ToB 감사

166. 테스트 스위트의 부실한 에러 처리 관행

취약점: 테스트 스위트가 예상되는 동작을 제대로 테스트하지 않았습니다. 특히, 특정 에러 메시지를 확인하는 대신 try-catch 문으로 에러를 조용히 무시하는 경우가 있었습니다. 이 경우, 트랜잭션이 revert 되더라도 올바른 이유로 revert 되었는지 보장할 수 없어 테스트의 신뢰도를 떨어뜨립니다.

  • 권장 사항: 특정 에러 메시지를 대상으로 테스트하여, 트랜잭션이 올바른 이유로 revert 되었는지 확인해야 합니다.
  • 감사 출처: dForce Lending의 ToB 감사

167. 중복되거나 사용되지 않는 코드

취약점: _recordLoanClosure() 함수는 boolean 값을 반환하지만, 이 함수를 호출하는 곳에서는 이 반환 값을 전혀 사용하지 않았습니다. 또한 이로 인해 항상 false가 되는 불필요한 if 문이 존재하는 등 중복되고 사용되지 않는 코드가 있었습니다.

  • 권장 사항: 반환 값을 사용하거나, 함수 정의에서 반환 타입을 제거해야 합니다. 또한 불필요한 if 문을 제거해야 합니다.
  • 감사 출처: Synthetix EtherCollateral의 Sigma Prime 감사

168. 단일 계정이 모든 공급량을 차지할 수 있음

취약점: 대출 가능한 최대 금액(maxLoanSize)에 대한 제한이 없었습니다. 이로 인해 단일 계정이 총 발행 공급량에 달하는 대출을 일으켜, 사실상 자산을 독점하고 다른 사용자의 참여를 막을 수 있었습니다.

  • 권장 사항: 이 동작이 의도된 것인지 확인하고, 대출 가능한 최대 금액에 대한 한도(maxLoanSize)를 도입하고 시행하는 것을 고려해야 합니다.
  • 감사 출처: Synthetix EtherCollateral의 Sigma Prime 감사

169. 불충분한 입력값 검증

취약점: EtherCollateral 컨트랙트의 생성자가 입력 파라미터로 제공된 주소들의 유효성을 확인하지 않았습니다. 이로 인해 synthProxy, sUSDProxy 등의 주소가 0번 주소로 설정된 채 컨트랙트가 배포될 수 있었습니다.

  • 권장 사항: 적절한 입력값 검증을 수행하기 위해 require 문을 도입하는 것을 고려해야 합니다.
  • 감사 출처: Synthetix EtherCollateral의 Sigma Prime 감사

170. 사용되지 않는 이벤트 로그

취약점: log 이벤트들이 선언되었지만, 코드 내에서 한 번도 발생(emit)되지 않았습니다.

  • 권장 사항: 사용되지 않는 이벤트들을 컨트랙트에서 제거해야 합니다.
  • 감사 출처: Synthetix EtherCollateral의 Sigma Prime 감사

171. transferFrom() 함수를 통한 의도치 않은 토큰 소각

취약점: 사용자는 PMGT 토큰을 특정 소각 주소(burn address)로 보내고 "골드 증서"를 받아야 합니다. 하지만 transferFrom() 함수는 to 주소가 이 소각 주소인지 확인하지 않았습니다. 이로 인해 사용자가 transferFrom()을 사용해 토큰을 소각 주소로 보낼 경우, 골드 증서 발행을 유발하는 Burn 이벤트가 발생하지 않아 토큰은 소각되지만 증서는 받지 못하는 자산 손실이 발생할 수 있었습니다.

  • 권장 사항: transferFrom() 함수 내에 require 문을 추가하여, to 주소가 소각 주소가 아니도록 막아야 합니다.
  • 감사 출처: InniGold의 Sigma Prime 감사

172. 경계 없는 리스트로 인한 서비스 거부(DoS) 벡터

취약점: 역할(role)에 속한 모든 요소를 삭제하는 reset() 함수가 연결 리스트 전체를 순회하도록 설계되었습니다. 만약 리스트의 요소 수가 너무 많아지면(예: 371개 이상), 이 함수를 호출하는 트랜잭션은 블록 가스 한도를 초과하여 항상 실패하게 됩니다. 이는 특정 역할 목록이 너무 커지면 아무도 그 목록을 초기화할 수 없게 되는 서비스 거부(DoS)를 유발합니다.

  • 권장 사항: add() 함수에 리스트의 최대 크기를 제한하는 조건을 추가하거나, gasleft() 함수를 사용하여 남은 가스를 확인하거나, 또는 한 번에 특정 수의 노드만 제거하도록 reset() 함수를 수정하는 것을 고려해야 합니다.
  • 감사 출처: InniGold의 Sigma Prime 감사

173. approve() 함수의 프론트러닝 취약점

취약점: 잘 알려진 ERC-20 approve() 함수의 프론트러닝(front-running) 취약점입니다. 사용자가 승인 수량을 100에서 50으로 변경하려는 트랜잭션을 보낼 때, 공격자는 이 트랜잭션을 보고 먼저 100개의 토큰을 사용한 후, 뒤따르는 50개 승인 트랜잭션이 처리되게 하여 총 150개의 토큰을 탈취할 수 있습니다.

  • 권장 사항: approve() 함수의 프론트러닝 문제를 인지하고, OpenZeppelin에서 제공하는 increaseAllowance 및 decreaseAllowance와 같이 이 취약점이 해결된 확장 함수를 사용하는 것을 고려해야 합니다.
  • 감사 출처: InniGold의 Sigma Prime 감사

174. 불필요한 require 구문

개선점: Blacklistable.sol에 있는 require(to != address(0)); 확인 구문은, 이 컨트랙트가 상속받는 부모 컨트랙트인 ERC20.sol의 _transfer() 함수에 이미 구현되어 있어 중복됩니다.

  • 권장 사항: 가스 절약을 위해 중복되는 require 구문을 제거하는 것을 고려해야 합니다.
  • 감사 출처: InniGold의 Sigma Prime 감사

175. 보상이 기간보다 작을 경우 0으로 반올림되는 문제

취약점: 보상률(rewardRate)이 보상/기간의 정수 나눗셈으로 계산되었습니다. 만약 기간이 보상보다 크면, 계산 결과가 0으로 버림되어 스테이커들이 아무런 보상을 받지 못하는 문제가 발생합니다. 또한, 정수 나눗셈으로 인해 매번 약간의 보상이 남게 되어 컨트랙트에 자산이 누적됩니다.

  • 권장 사항: notifyRewardAmount() 함수 호출 시 이러한 반올림 문제를 인지해야 합니다. 또한, 반올림으로 인해 남는 잉여 보상을 회수할 수 있는 메커니즘을 고려해야 합니다.
  • 감사 출처: Synthetix Unipool의 Sigma Prime 감사

176. Withdrawn 이벤트 로그 포이즈닝

취약점: withdraw() 함수를 0개의 토큰으로도 호출할 수 있으며, 이때도 Withdrawn 이벤트가 정상적으로 발생했습니다. 악의적인 사용자는 이 함수를 계속해서 호출하여 수많은 가짜 이벤트를 발생시켜 이벤트 로그를 오염(poisoning)시킬 수 있으며, 이는 오프체인 모니터링 시스템에 혼란을 줍니다.

  • 권장 사항: 인출 금액이 0일 때는 Withdrawn 이벤트가 발생하지 않도록 확인 구문을 추가해야 합니다.
  • 감사 출처: Synthetix Unipool의 Sigma Prime 감사

177. 청산인에 대한 불충분한 인센티브

취약점: 프로토콜은 시스템의 부실을 막기 위해 제3자의 청산에 의존하지만, 정작 청산인에게 아무런 경제적 인센티브를 제공하지 않았습니다. 청산인은 비싼 가스비를 지불하면서 아무런 이득 없이 청산 프로세스를 실행할 동기가 없습니다.

  • 권장 사항: 청산인이 담보 자산을 할인된 가격에 구매할 수 있게 하는 등, 청산 프로세스를 실행할 더 높은 인센티브를 제공하도록 설계를 개선해야 합니다.
  • 감사 출처: HoldeFi의 OpenZeppelin 감사

178. 시장이 지급 불능 상태가 될 수 있음

취약점/리스크: 모든 담보 대출 프로토콜과 마찬가지로, 담보 자산의 가치가 빌린 자산의 가치보다 낮아지면 시장이 지급 불능(insolvent) 상태가 될 위험이 내재되어 있습니다.

  • 권장 사항: 이 리스크는 모든 담보 대출 프로젝트에 고유합니다. 하지만 이 리스크의 존재를 인지하고, 신중한 담보 비율 설정, 강력한 청산 인센티브, 상장 토큰의 신중한 선택 등으로 리스크를 줄여야 합니다. 또한, 이러한 시나리오에 대한 테스트를 추가하고 잠재적 위험을 사용자에게 알려야 합니다.
  • 감사 출처: HoldeFi의 OpenZeppelin 감사

179. OpenZeppelin 컨트랙트를 사용하지 않음

취약점: 표준적이고, 감사받았으며, 커뮤니티에서 검토된 OpenZeppelin 라이브러리를 가져와 사용하는 대신, 직접 재구현하거나 코드를 복사-붙여넣기하여 사용했습니다. 이는 유지보수해야 할 코드의 양을 늘리고, OpenZeppelin 팀이 지속적으로 적용하는 개선 사항과 버그 수정을 놓치게 만듭니다.

  • 권장 사항: 코드를 재구현하거나 복사하는 대신, OpenZeppelin 컨트랙트를 import하여 사용하고, 필요한 추가 기능은 상속을 통해 확장해야 합니다.
  • 감사 출처: HoldeFi의 OpenZeppelin 감사

180. 이벤트에 인덱싱된 파라미터 부재

취약점: 코드베이스 전체에 걸쳐, 정의된 이벤트의 파라미터 중 어느 것도 indexed로 지정되지 않았습니다.

  • 권장 사항: 오프체인 서비스가 특정 이벤트를 검색하고 필터링하는 작업을 용이하게 하기 위해, 이벤트 파라미터(예: 주소, ID 등)를 인덱싱(indexed)하는 것을 고려해야 합니다.
  • 감사 출처: HoldeFi의 OpenZeppelin 감사

181. 명명된 반환 변수의 비일관적 사용

개선점: 코드베이스 전체에 걸쳐 명명된 반환 변수(named return variables)의 사용이 일관되지 않았습니다. 어떤 함수는 사용하고 어떤 함수는 사용하지 않아, 코드 스타일이 통일되지 않고 가독성을 해쳤습니다.

  • 권장 사항: 모든 명명된 반환 변수를 제거하고, 함수 본문에서 지역 변수를 명시적으로 선언한 후 return 문을 사용하여 값을 반환하는 방식으로 통일하는 것을 고려해야 합니다. 이는 코드의 명확성과 가독성을 높입니다.
  • 감사 출처: HoldeFi의 OpenZeppelin 감사

182. 신뢰할 수 없는 block.timestamp

취약점/리스크: 코드가 계산 및 시간 확인에 block.timestamp를 사용합니다. 하지만 블록 타임스탬프는 채굴자에 의해 약간 변경될 수 있으며, 시간에 민감하게 의존하는 로직을 가진 컨트랙트에서 악용될 수 있습니다.

  • 권장 사항: 이 문제를 고려하고, 이러한 시나리오가 발생할 수 있음을 사용자에게 경고해야 합니다. 만약 타임스탬프 변경이 프로토콜에 영향을 미치지 않는다면, 그 이유를 문서화하고 이를 보장하는 테스트를 작성하는 것이 좋습니다.
  • 감사 출처: HoldeFi의 OpenZeppelin 감사

183. require 구문 내에서의 할당

취약점: require 구문 안에서 변수에 값을 할당하는 코드가 있었습니다. (예: require((isValid = check()) == true);) 이는 require 구문의 표준적인 사용법(조건 확인)에서 벗어나며, 코드를 읽는 사람에게 큰 혼란을 줄 수 있습니다.

  • 권장 사항: 할당은 require 구문 앞의 별도 라인으로 옮기고, require는 순수하게 조건 확인 용도로만 사용해야 합니다.
  • 감사 출처: BarnBridge Smart Yield Bonds의 OpenZeppelin 감사

184. 주석 처리된 코드

개선점: 코드베이스 전체에 걸쳐 //로 주석 처리된 코드 라인들이 있었습니다. 이는 혼란을 야기할 수 있으며 전반적인 코드 가독성에 해가 됩니다.

  • 권장 사항: 더 이상 필요하지 않은 주석 처리된 코드 라인은 제거하는 것을 고려해야 합니다.
  • 감사 출처: BarnBridge Smart Yield Bonds의 OpenZeppelin 감사

185. 오해의 소지가 있는 revert 메시지

취약점: 에러 메시지는 사용자가 실패 조건을 알리고 적절한 수정을 할 수 있도록 충분한 정보를 제공해야 합니다. 하지만 정보가 부족한 에러 메시지는 전반적인 사용자 경험을 크게 손상시키고 시스템의 품질을 저하시킵니다.

  • 권장 사항: 언급된 특정 문제를 해결할 뿐만 아니라, 코드베이스 전체를 검토하여 모든 에러 메시지가 충분히 유익하고 사용자 친화적인지 확인해야 합니다.
  • 감사 출처: Compound Governor Bravo의 OpenZeppelin 감사

186. 여러 개의 오래된 솔리디티 버전 사용

취약점: 모든 컨트랙트에서 오래된 버전의 솔리디티가 사용되고 있었습니다. 또한, 코드베이스 전체에 걸쳐 서로 다른 버전의 솔리디티가 혼용되고 있었습니다. 오래된 버전은 알려진 보안 취약점을 가질 수 있으며, 버전 혼용은 예기치 않은 동작을 유발할 수 있습니다.

  • 권장 사항: 더 최신 버전의 컴파일러를 사용하고, 예기치 않은 동작을 피하기 위해 pragma 문에 명시적인 솔리디티 버전을 지정(예: pragma solidity 0.7.6;)하는 것을 고려해야 합니다.
  • 감사 출처: Fei Protocol의 OpenZeppelin 감사

187. 동일한 코드베이스에 테스트 및 프로덕션 상수 혼재

취약점: TEST_MODE라는 boolean 변수를 사용하여, 테스트 환경과 프로덕션 환경의 상수를 동일한 컨트랙트 코드 내에서 전환하도록 했습니다. 이는 프로덕션 코드의 가독성을 떨어뜨리고, 실수로 테스트 모드로 배포하는 등 시스템의 핵심 가치를 오류에 취약하게 만듭니다.

  • 권장 사항: 프로덕션과 테스트를 위한 별도의 환경과 컨트랙트를 갖는 것을 고려해야 합니다.
  • 감사 출처: Fei Protocol의 OpenZeppelin 감사

188. 불필요하게 작은 정수 크기 사용

개선점: 솔리디티에서는 256비트보다 작은 정수(예: uint128)를 사용하면, EVM이 사용되지 않는 비트를 0으로 만드는 추가 작업을 수행해야 하므로 오히려 가스 비용이 증가하는 경향이 있습니다. 스토리지 비용 절약을 위해 여러 변수를 하나의 슬롯에 묶는(packing) 특정 시나리오에서만 정당화될 수 있습니다.

  • 권장 사항: 특별한 스토리지 패킹 시나리오가 아니라면, 가스 효율을 위해 256비트 크기의 정수(uint256, int256)를 사용하는 것을 고려해야 합니다.
  • 감사 출처: Fei Protocol의 OpenZeppelin 감사

189. uint256 대신 uint 사용

개선점: 코드베이스 전체에 걸쳐 uint256 대신, 그 별칭(alias)인 uint가 수백 번 사용되었습니다.

  • 권장 사항: 코드의 명시성(explicitness)을 위해, 모든 uint 인스턴스를 uint256으로 교체하는 것을 고려해야 합니다. 이는 코드를 읽는 사람에게 변수의 크기를 명확하게 알려줍니다.
  • 감사 출처: Fei Protocol의 OpenZeppelin 감사

190. 예기치 않은 부수 효과를 가진 함수

취약점: 함수 이름이 암시하는 것과 다른, 예기치 않은 부수 효과(side-effects)를 가진 함수들이 있었습니다. 예를 들어, getPrice라는 이름의 함수는 단순히 가격을 가져오는 것처럼 보이지만, 실제로는 가격 요청을 정산하는 상태 변경 작업을 수행했습니다. 이는 코드를 처음 보는 개발자에게 혼란을 주어 실수를 유발할 수 있습니다.

  • 권장 사항: 읽기 전용 함수(getter)와 상태 변경 함수(setter)를 명확히 분리하거나, 함수가 수행하는 모든 작업을 설명하는 이름으로 변경해야 합니다. (예: getPriceAndSettleRequest)
  • 감사 출처: Uma Phase 4의 OpenZeppelin 감사

191. 안전하지 않은 형 변환(Casting)

취약점: uint 타입의 값을 int 타입으로 변환한 후 음수화했습니다. uint는 int보다 더 큰 양수를 저장할 수 있으므로, 이 형 변환 과정에서 오버플로우가 발생할 수 있습니다.

  • 권장 사항: 형 변환 전에 값이 int 타입의 범위 내에 있는지 확인하거나, 안전한 형 변환 함수를 제공하는 OpenZeppelin의 SafeCast 라이브러리를 사용하는 것을 고려해야 합니다.
  • 감사 출처: GEB Protocol의 OpenZeppelin 감사

192. require 구문에 에러 메시지 누락

개선점: 코드 여러 곳의 require 구문에 실패 이유를 알려주는 에러 메시지가 누락되었습니다. 만약 이 require 문이 실패하면, 트랜잭션은 아무런 설명 없이 조용히 revert 되어 디버깅을 매우 어렵게 만듭니다.

  • 권장 사항: 모든 require 구문에 구체적이고 유익한 에러 메시지를 포함하는 것을 고려해야 합니다.
  • 감사 출처: GEB Protocol의 OpenZeppelin 감사

193. 주석 없는 어셈블리 블록

취약점: 복잡하고 중요한 시스템의 일부인 인라인 어셈블리 블록에 주석이 전혀 없었습니다. 어셈블리는 가독성이 떨어지는 로우레벨 언어이므로, 문서가 없으면 코드를 신뢰하고, 검토하고, 유지보수하기가 매우 어렵습니다.

  • 권장 사항: 해당 어셈블리 블록을 사용하는 이유와 모든 개별 명령어가 무엇을 하는지 명확히 설명하는 광범위한 문서를 포함하고, 모든 잠재적 사용 사례를 다루는 철저한 테스트를 구현하는 것을 고려해야 합니다.
  • 감사 출처: GEB Protocol의 OpenZeppelin 감사

194. 불필요한 require 구문

개선점: 코드 내에 불필요한 require 구문이나 조건 확인이 여러 번 있었습니다. 예를 들어, 한 함수 내에서 동일한 조건이 두 번 확인되었습니다.

  • 권장 사항: 코드를 단순화하고 가스를 절약하기 위해 불필요한 확인 로직을 제거하는 것을 고려해야 합니다.
  • 감사 출처: GEB Protocol의 OpenZeppelin 감사

195. 불필요한 이벤트 발생

개선점: 특정 함수에서, 이전에 저장된 적 없는 타임스탬프로 호출을 시도하는 등 실패하는 경로에서도 불필요한 이벤트를 발생시켰습니다.

  • 권장 사항: 코드를 단순화하고 가스를 절약하기 위해 불필요한 이벤트 발생을 피해야 합니다.
  • 감사 출처: GEB Protocol의 OpenZeppelin 감사

196. 화이트리스트에 없는 담보 자산으로 oToken 생성 가능

취약점: 새로운 옵션 토큰(oToken)을 생성할 때, 해당 옵션의 담보 자산이 화이트리스트에 등록되어 있는지 확인하지 않았습니다. 이는 검증되지 않은 위험한 자산을 담보로 옵션이 생성될 수 있는 길을 열어줍니다.

  • 권장 사항:  oToken 생성을 허용하기 전에, 관련된 자산이 이미 화이트리스트에 있는지 검증하는 것을 고려해야 합니다.
  • 감사 출처: Opyn Gamma Protocol의 OpenZeppelin 감사

197. 컨트랙트와 인터페이스 간의 불일치

취약점: 인터페이스는 구현된 컨트랙트가 외부에 노출하는 기능을 정의해야 하지만, 여러 인터페이스에 대응하는 컨트랙트의 함수 일부가 정의되지 않았습니다. 이는 인터페이스의 약속과 실제 구현이 다른 것으로, 통합 시 오류를 유발할 수 있습니다.

  • 권장 사항: 정의(인터페이스)와 구현(컨트랙트)이 완전히 일치하도록 필요한 변경을 적용하는 것을 고려해야 합니다.
  • 감사 출처: Opyn Gamma Protocol의 OpenZeppelin 감사

198. 원자적으로 실행되지 않는 작업으로 인한 상태 불일치 가능성

취약점: 서로 밀접하게 관련된 여러 상태 변경 작업(setAssetPricer, setLockingPeriod 등)이 각각 별개의 트랜잭션으로 실행되도록 설계되었습니다. 만약 이 중 일부만 성공하고 일부는 실패하면, 시스템은 일관되지 않은 위험한 상태에 빠질 수 있습니다.

  • 권장 사항: 관련된 작업들을 하나의 트랜잭션으로 원자적(atomically)으로 실행할 수 있는 추가적인 함수를 구현하는 것을 고려해야 합니다.
  • 감사 출처: Opyn Gamma Protocol의 OpenZeppelin 감사

199. 폐지된 체인링크 API 사용

취약점: 체인링크 가격 결정기(Pricer)가 latestAnswer()와 같은 폐지된(deprecated) 체인링크 API의 여러 함수를 사용하고 있었습니다. 만약 체인링크가 폐지된 API 지원을 중단하면 이 기능들은 갑자기 멈출 수 있습니다.

  • 권장 사항: 최신 체인링크 API를 사용하도록 코드를 리팩토링하는 것을 고려해야 합니다.
  • 감사 출처: Opyn Gamma Protocol의 OpenZeppelin 감사

200. 자금 손실 가능성

취약점: 타임락이 해제된 사용자들에게 자금을 분배하는 함수가, 인자로 받은 사용자 목록에 중복된 사용자가 있는지 확인하지 않았습니다. 만약 목록에 중복된 사용자가 있으면, 그들의 잔액이 여러 번 계산되어 인출할 총액이 부풀려지고, 이는 자금 손실로 이어질 수 있습니다.

  • 권장 사항: 인출할 금액을 계산할 때 중복된 사용자가 있는지 확인하는 것을 고려해야 합니다.
  • 감사 출처: PoolTogether V3의 OpenZeppelin 감사

201. 변수 초기화에 delete 사용

개선점: 코드에서 변수를 초기화(clear)하기 위해 0번 주소를 할당하는 방식(variable = address(0))을 사용했습니다.

  • 권장 사항: delete 키워드는 변수를 초기화하고 가스를 환급받는다는 의도를 더 명확하게 전달하며, 더 관용적인(idiomatic) 표현입니다. 0을 할당하는 대신 delete 구문으로 교체하는 것을 고려해야 합니다.
  • 감사 출처: Set Protocol의 OpenZeppelin 감사

https://secureum.substack.com/p/audit-findings-201

 

Audit Findings 201

100 more Audit Findings

secureum.substack.com

'Web3 > Hacking' 카테고리의 다른 글

[Ethernaut] 18. MagicNumber WriteUp  (1) 2025.08.09
[Ethernaut] 17. Recovery WriteUp  (1) 2025.08.08
[Ethernaut] 16. Preservation WriteUp  (1) 2025.08.08
[Ethernaut] 15. Naught Coin WriteUp  (1) 2025.08.07
[Secureum] Audit Findings 101  (0) 2025.07.12