c0mpos3r

[Secureum] Audit Findings 101 본문

Web3/Hacking

[Secureum] Audit Findings 101

음대생 2025. 7. 12. 01:06

101 Finding from Audits

1. transfer와 transferFrom의 반환 값을 처리하지 않음

취약점: 모든 ERC-20 토큰이 표준을 동일하게 따르지는 않습니다. 일부 토큰의 transfer나 transferFrom 함수는 실패 시 revert 되는 대신 false를 반환합니다. 만약 이 반환 값을 확인하지 않으면, 컨트랙트는 전송이 실패했음에도 성공한 것으로 착각하고 다음 로직을 실행하여 심각한 문제를 일으킬 수 있습니다.

  • 권장 사항: 호출 결과를 require()로 감싸서 실패 여부를 확인하거나, OpenZeppelin의 SafeERC20 라이브러리를 사용하여 안전하게 호출해야 합니다.
  • 심각도: Medium (Aave Protocol V2의 Consensys Diligence 감사)

2. 임의의 작업 실행 (재진입 공격)

취약점: 플래시 론을 실행하는 복잡한 트랜잭션 과정에서, 사용자의 대리인(DSProxy)에게 부여된 실행 권한이 트랜잭션이 완전히 끝날 때까지 회수되지 않았습니다. 이로 인해 레시피 실행 중 악의적인 외부 컨트랙트 호출이 포함될 경우, 이 컨트랙트가 다시 사용자의 프록시로 재진입(Re-entrancy)하여 허가된 권한을 이용해 자금을 탈취하는 등의 임의의 작업을 실행할 수 있었습니다.

  • 권장 사항: 재진입 방지 가드(mutex), 즉 OpenZeppelin의 nonReentrant와 같은 수정자를 사용하여 이러한 공격을 막아야 합니다.
  • 심각도: Critical (DeFi Saver의 Consensys Diligence 감사)

3. 18보다 많은 소수점을 가진 토큰 처리 문제

취약점: 코드에서 모든 토큰의 소수점(decimals)이 최대 18자리일 것이라고 가정했습니다. 하지만 YAMv2(24자리)처럼 드물게 18자리보다 많은 소수점을 가진 토큰이 존재합니다. 이러한 가정은 잘못된 계산 결과와 예측 불가능한 코드 흐름을 초래할 수 있습니다.

  • 권장 사항: 토큰의 소수점 자릿수를 18로 고정하여 가정하지 말고, 각 토큰의 decimals() 함수를 호출하여 동적으로 처리해야 합니다.
  • 심각도: Major (DeFi Saver의 Consensys Diligence 감사)

4. Compound 에러 코드를 확인하지 않음

취약점: Compound 프로토콜의 enterMarket, exitMarket 같은 함수들은 실패 시 revert 되는 대신 에러 코드를 반환합니다. 하지만 이 함수를 호출하는 컨트랙트가 반환된 에러 코드를 전혀 확인하지 않아, 작업이 실패했음을 인지하지 못했습니다.

  • 권장 사항: 함수 호출 후 반환된 에러 코드가 0(성공)이 아닐 경우, 호출한 컨트랙트가 revert 되도록 처리해야 합니다.
  • 심각도: Major (DeFi Saver의 Consensys Diligence 감사)

5. allowance 함수 호출 시 파라미터 순서가 뒤바뀜

취약점: allowance(A, B)로 특정 계정의 승인 수량을 확인한 후, safeTransferFrom(B, A, ...)처럼 뒤바뀐 순서의 파라미터로 토큰을 전송했습니다. 이는 잘못된 승인 정보를 확인하는 결과를 낳습니다.

  • 권장 사항: allowance 확인과 safeTransferFrom 호출에 사용되는 파라미터의 순서를 일관되게 맞춰야 합니다.
  • 심각도: Medium (DeFi Saver의 Consensys Diligence 감사)

6. addLiquidity 함수에서 토큰 승인 탈취 가능

취약점: 유동성을 추가하는 함수가 msg.sender로부터 토큰을 가져오는 대신, 호출자가 지정한 임의의 주소로부터 토큰을 가져오도록 구현되었습니다.

  • 공격 시나리오: 공격자는 해당 라우터 컨트랙트에 토큰 사용을 승인해 둔 다른 피해자의 주소를 파라미터로 넘겨, 피해자의 자금으로 유동성을 공급하고 그 유동성 토큰을 자신이 가로챌 수 있습니다.
  • 권장 사항: 토큰 전송은 항상 msg.sender로부터 이루어져야 합니다.
  • 심각도: Critical (DAO의 Consensys Diligence 감사)

7. swapExactTokensForETH가 잘못된 반환 값을 확인

취약점: 스왑 후 최소 수량의 토큰을 받았는지 검증하는 로직에서, 토큰을 받은 계정의 잔액 변화를 확인하는 대신, 엉뚱하게도 라우터 컨트랙트의 잔액과 비교하는 등 의미 없는 값을 검증하고 있었습니다.

  • 권장 사항: 스왑 전후의 올바른 대상(수신자)의 잔액을 비교하여, 실제로 받은 토큰이 최소 기대 수량 이상인지 정확하게 확인해야 합니다.
  • 심각도: Major (DAO의 Consensys Diligence 감사)

8. 0 값 예치를 허용하여 유동성 풀을 막아버림

취약점: 유동성 풀의 최초 예치 함수(deposit)는 단 한 번만 호출될 수 있는데, 0 값 예치를 막는 확인 로직이 없었습니다.

  • 공격 시나리오: 악의적인 사용자가 0개의 토큰으로 deposit 함수를 호출하면, 예치는 성공한 것으로 처리되어 deposited 플래그가 true로 설정됩니다. 하지만 실제 유동성은 전혀 공급되지 않은 채로, 이후 아무도 해당 풀에 유동성을 공급할 수 없게 영원히 막혀버립니다.
  • 권장 사항: 예치 수량이 0이 아닌지 확인하는 요구사항을 추가해야 합니다.
  • 심각도: Medium (DAO의 Consensys Diligence 감사)

9. commit 함수가 이전 약정 수량을 덮어씀

취약점: 사용자의 약정 수량을 기록하는 함수가 기존 값에 더하는(+=) 대신, 새로운 값으로 덮어쓰는(=) 방식을 사용했습니다. 이로 인해 사용자의 이전 약정 기록이 사라지거나, 심지어 다른 사람이 특정 사용자를 대신해 0을 약정하여 기록을 완전히 삭제할 수도 있었습니다.

  • 권장 사항: 기존 약정 수량에 새로운 수량을 누적(덧셈)하도록 로직을 수정해야 합니다.
  • 심각도: Critical (Fei Protocol의 Consensys Diligence 감사)

10. 런치 이후에도 구매 및 약정 가능

취약점: 프로토콜이 공식적으로 런치된 후에는 비활성화되어야 할 purchase 및 commit과 같은 제네시스 기간 전용 함수들이, 런치 이후에도 계속 호출 가능한 상태로 남아있었습니다.

  • 권장 사항: 해당 함수들에 런치가 되지 않았을 때만 실행되도록 하는 검증 로직(예: require(!launched))을 추가해야 합니다.
  • 심각도: Critical (Fei Protocol의 Consensys Diligence 감사)

11. 토큰 전송 전 훅(hook)에서의 오버플로우

취약점: 토큰 전송 직전에 인센티브를 계산하고 민팅/소각하는 로직에서, 인센티브 계산에 사용된 수학 연산이 오버플로우에 취약했습니다. 이로 인해 공격자는 의도치 않은 수량의 토큰을 민팅하거나, 상대방의 토큰을 소각시키는 등의 악의적인 행위를 할 수 있었습니다.

  • 권장 사항: 인센티브를 계산하는 로직에서 형 변환(casting) 시 오버플로우가 발생하지 않도록 보장해야 합니다. (예: SafeMath 사용)
  • 심각도: Major (Fei Protocol의 Consensys Diligence 감사)

12. 런치 전에 토큰을 획득할 수 있는 문제

취약점: 정식 런치 전에 호출되면 안 되는 토큰 할당 함수(allocate)가, 컨트랙트에 단 1 wei라도 이더가 송금되면 대부분의 체크 로직을 우회하여 호출될 수 있었습니다. 이로 인해 일부 사용자들이 런치 전에 토큰을 미리 획득할 수 있었습니다.

  • 권장 사항: allocate 함수에 제네시스 런치가 시작된 후에만 호출될 수 있도록 하는 검증 로직을 추가해야 합니다.
  • 심각도: Medium (Fei Protocol의 Consensys Diligence 감사)

13. 초기화되지 않은 타이머가 종료된 것으로 간주됨

취약점: 타이머의 초기화가 2단계로 진행되는데, startTime이 설정되는 2단계가 완료되기 전에는 startTime이 0으로 간주되었습니다. 이 때문에 타이머 종료 여부를 확인하는 isTimeEnded() 함수가, 타이머가 시작되지도 않았음에도 불구하고 종료되었다(true)고 잘못된 값을 반환했습니다.

  • 권장 사항: 타이머가 아직 초기화되지 않았다면, isTimeEnded() 함수는 false를 반환하거나 revert 되어야 합니다.
  • 심각도: Medium (Fei Protocol의 Consensys Diligence 감사)

14. 오버플로우/언더플로우 보호 부재

취약점: 코드 전반에 걸쳐 SafeMath나 솔리디티 0.8.0+ 버전의 기본 보호 기능 없이 산술 연산이 사용되었습니다. 개발팀은 모든 값이 실제 이더(ETH) 값에서 파생되므로 오버플로우가 발생할 수 없다고 판단했지만, 이러한 가정은 위험할 수 있습니다.

  • 권장 사항: 특정 가정에 의존하기보다는, 안전 모드로 연산하는 것이 항상 더 안전합니다. SafeMath를 사용하거나 솔리디티 0.8.0 이상의 컴파일러를 사용할 것을 권장합니다.
  • 심각도: Medium (Fei Protocol의 Consensys Diligence 감사)

15. IWETH.transfer 호출의 반환 값 미확인

취약점: WETH 컨트랙트의 transfer 함수를 호출한 후, 성공 여부를 나타내는 반환 값을 확인하지 않았습니다. 만약 WETH 전송이 실패하더라도 컨트랙트는 이를 인지하지 못하고 다음 로직을 계속 진행하게 됩니다.

  • 권장 사항: require 구문을 추가하여 반환 값을 확인하거나, safeTransfer와 같은 안전한 래퍼(wrapper) 함수를 사용해야 합니다.
  • 심각도: Medium (Fei Protocol의 Consensys Diligence 감사)

16. 런치 이후에도 비상 탈출 기능이 활성화됨

취약점: 정상적인 launch 함수와 비상 상황을 위한 emergencyExit 함수는 상호 배타적으로 작동해야 하지만, 둘 중 하나가 성공적으로 호출된 후에도 다른 하나가 비활성화되지 않았습니다. 이는 회계 처리 등에서 예기치 않은 엣지 케이스를 유발할 수 있습니다.

  • 권장 사항: launch가 호출되면 emergencyExit를 비활성화하고, emergencyExit가 호출되면 launch를 비활성화하는 로직을 추가해야 합니다.
  • 심각도: Medium (Fei Protocol의 Consensys Diligence 감사)

17. 반환 값이 없는 ERC-20 토큰 전송 실패

취약점: ERC-20 표준은 전송 성공 시 true를 반환하도록 제안하지만, USDT 등 일부 주요 토큰들은 반환 값이 아예 없습니다(void). 코드가 true 반환을 강제로 확인하도록 구현되어 있어, 실제 토큰 전송은 성공했음에도 불구하고 반환 데이터 크기가 맞지 않아 트랜잭션이 revert 되는 문제가 발생했습니다.

  • 권장 사항: 반환 값이 있는 토큰과 없는 토큰을 모두 유연하게 처리해주는 OpenZeppelin의 SafeERC20 라이브러리를 사용할 것을 권장합니다.
  • 심각도: Major (bitbank의 Consensys Diligence 감사)

18. MetaSwap.swap() 함수의 재진입 취약점

취약점: swap() 함수에 재진입 취약점이 존재하여, 공격자가 스왑 과정 중에 다시 swap() 함수로 재진입하여 거래 상태를 조작하고 모든 토큰을 탈취할 수 있었습니다.

  • 권장 사항: OpenZeppelin의 ReentrancyGuard와 같은 간단한 재진입 방지 장치를 사용하여 swap() 함수를 보호해야 합니다.
  • 심각도: Major (MetaSwap의 Consensys Diligence 감사)

19. 새로운 악의적인 어댑터가 사용자 토큰에 접근 가능

취약점: 여러 DEX 애그리게이터를 지원하는 MetaSwap 컨트랙트는 사용자들이 한 번만 토큰 사용을 승인(approve)하면 모든 어댑터를 통해 거래할 수 있도록 설계되었습니다. 하지만 이 구조는 새롭게 추가되는 악의적인 어댑터가 기존 사용자들이 부여한 승인 권한을 그대로 사용하여 자금을 탈취할 수 있는 위험을 내포합니다.

  • 권장 사항: 사용자는 메인 컨트랙트에만 승인하고, 메인 컨트랙트는 실제 거래에 필요한 만큼의 토큰만 별도의 Spender 컨트랙트로 옮긴 후, 이 Spender가 어댑터를 DELEGATECALL 하도록 구조를 변경하여 어댑터의 접근 권한을 최소화해야 합니다.
  • 심각도: Medium (MetaSwap의 Consensys Diligence 감사)

20. 소유자가 어댑터를 업데이트하여 거래자를 프론트러닝 가능

취약점: 컨트랙트 소유자가 언제든지 어댑터의 구현 코드를 교체할 수 있었습니다. 악의적인 소유자는 사용자의 거래 트랜잭션을 보고 프론트러닝(front-run)하여, 거래 직전에 어댑터를 악성 코드로 교체하여 사용자의 자금을 훔칠 수 있습니다. 특히 어댑터가 DELEGATECALL로 호출되기 때문에, 악성 어댑터 하나가 다른 모든 어댑터의 로직까지 덮어쓸 수 있는 심각한 위험이 있었습니다.

  • 권장 사항: 최소한 기존 어댑터의 수정을 금지하고, 새로운 어댑터를 추가하고 기존 것을 비활성화하는 방식으로만 변경해야 합니다. 더 나아가 타임락(Timelock)을 도입하는 것이 좋습니다.
  • 심각도: Medium (MetaSwap의 Consensys Diligence 감사)

21. 아주 잠깐만 스테이킹하여 이자를 수집할 수 있음

취약점: 이자율(교환 비율)이 30분마다 한 번씩만 업데이트되는 점을 악용한 사례입니다. 공격자는 30분 주기가 끝나기 직전에 오래된(stale) 이자율로 자산을 예치한 후, 주기가 끝나자마자 즉시 이자율 업데이트를 유발하고 새롭게 업데이트된 유리한 이자율로 자산을 인출할 수 있었습니다. 결과적으로 자산을 장기간 예치하지 않고도 이자 수익만 챙길 수 있었습니다.

  • 권장 사항: 30분이라는 시간 창을 제거하여, 모든 예치가 발생할 때마다 이자율이 업데이트되도록 해야 합니다.
  • 심각도: Medium (mstable-1.1의 Consensys Diligence 감사)

22. 오라클 업데이트를 조작한 아토믹 프론트러닝 공격

취약점: 오라클 가격 업데이트 트랜잭션을 샌드위치처럼 감싸는 아토믹 프론트러닝 공격이 가능했습니다. 공격자는 멤풀(mempool)에 있는 오라클 업데이트 트랜잭션을 보고, 더 높은 가스비와 더 낮은 가스비를 사용한 두 개의 트랜잭션을 동시에 보내 다음과 같이 차익 거래를 실행했습니다.

  1. (가스비 높게) 소량의 토큰을 교환하여 해당 블록의 교환 비율을 오래된 오라클 가격으로 고정시킵니다.
  2. (가스비 약간 낮게) 플래시 론으로 빌린 대량의 자금을 1번에서 고정된 오래된 가격으로 교환한 후, 가격 업데이트를 유발하고 새로운 가격으로 다시 교환하여 차익을 남깁니다.
  • 권장 사항: 사용자가 오래된 오라클 가격으로 거래하는 것과 오라클 가격 업데이트를 유발하는 것을 동일한 트랜잭션 내에서 수행할 수 없도록 막아야 합니다.
  • 심각도: Critical (Bancor v2 AMM의 Consensys Diligence 감사)

23. 특정 함수에 입력값 검증 루틴 부재

취약점: 함수들이 전달받은 인자(argument)가 유효한지 먼저 확인하지 않았습니다. 다음과 같은 기본적인 검증이 누락되었습니다.

  • uint 값이 0보다 커야 하는 경우
  • 주소값이 address(0)이 아니어야 하는 경우
  • 배열들의 길이가 서로 일치해야 하는 경우 등
  • 권장 사항: 코드 작성 시 입력값 검증을 시스템 개발의 중요한 부분으로 간주하고, 모든 인자가 제대로 검증되었는지 확인하는 테스트를 추가해야 합니다.
  • 심각도: Major (Shell Protocol의 Consensys Diligence 감사)

24. 관리자가 백도어로 사용할 수 있는 메서드 제거 필요

취약점: 관리자에게 과도한 권한을 부여하는 여러 함수가 존재했습니다. 특히 새로운 '어시밀레이터(assimilator)'를 추가하는 기능은, 관리자가 악의적이거나 결함이 있는 코드를 배포하여 풀의 자금을 모두 빼가거나 사용자 자산을 동결시킬 수 있는 치명적인 백도어로 작용할 수 있었습니다. 또한 safeApprove 함수는 관리자가 컨트랙트가 보유한 모든 토큰을 임의로 옮길 수 있게 했습니다.

  • 권장 사항: safeApprove와 같은 위험한 함수를 제거하고, 신뢰가 필요 없는(trustless) 비상 탈출 메커니즘으로 대체해야 합니다. 어시밀레이터 추가 기능은 배포 시에만 호출 가능하도록 internal로 변경하여, 배포 이후에는 코드가 불변(immutable)하고 감사 가능하도록 만들어야 합니다.
  • 심각도: Major (Shell Protocol의 Consensys Diligence 감사)

25. Revert하는 폴백 함수가 모든 지불을 막아버림

취약점: 여러 수신자에게 순차적으로 이더(ETH)를 전송하는 로직에서, 만약 수신자 중 단 한 명이라도 이더 수신 시 revert하는 컨트랙트일 경우, 전체 전송 로직이 실패하고 되돌려져 모든 사람에 대한 지불이 막히고 복구 불가능하게 됩니다.

  • 권장 사항: "풀-오버-푸시 패턴(pull-over-push pattern)"을 구현하여, 수령인이 직접 자금을 인출해가도록 해야 합니다. 또는, 실패한 전송은 무시하여 다른 사람들의 지불은 정상적으로 진행되도록 할 수 있습니다.
  • 심각도: Critical (Lien Protocol의 Consensys Diligence 감사)

26. safeRagequit이 자금 손실을 유발함

취약점: LAO(탈중앙화 자율 조직)에서 자금을 인출하는 safeRagequit 함수는, 특정 토큰이 블랙리스트에 올라 전송이 막히는 경우를 대비해 사용자가 일부 토큰만 선택적으로 인출할 수 있게 합니다. 하지만 문제는, 이때 인출 목록에서 제외된 토큰들이 사용자에게 반환되지 않고 LAO의 소유가 되어버린다는 점입니다. 이 자금을 되찾으려면 엄청난 신뢰와 조율이 필요합니다.

  • 권장 사항: 토큰 인출에 풀 패턴(pull pattern)을 구현해야 합니다. 사용자는 지분을 소각하여 LAO를 탈퇴하되, 당장 인출할 수 없는 토큰은 LAO 컨트랙트에 보관해두었다가 나중에 인출할 수 있어야 합니다.
  • 심각도: Critical (The Lao의 Consensys Diligence 감사)

27. 제안 생성이 신뢰가 필요 없는(trustless) 방식이 아님

취약점: 사용자가 공물(tribute) 토큰과 함께 제안을 제출했을 때, 만약 제안이 처리되지 않고 비상 처리 기간이 지나면 공물 토큰이 제안자에게 반환되지 않고 LAO의 소유가 되었습니다. 이는 제안이 처리될 것이라는 신뢰를 강요하는 구조입니다.

  • 권장 사항: 토큰 전송에 풀 패턴(pull pattern)을 적용하여, 제안이 처리되지 않으면 사용자가 직접 공물 토큰을 회수할 수 있도록 해야 합니다.
  • 심각도: Critical (The Lao의 Consensys Diligence 감사)

28. 비상 처리가 중단될 수 있음

취약점: 비상 처리 메커니즘은 공물 토큰 전송이 막히는 경우를 대비해 해당 토큰을 반환하지 않도록 설계되었습니다. 하지만 예치금(deposit) 토큰은 여전히 스폰서에게 반환하려고 시도하는데, 만약 이 예치금 토큰 전송마저 막히면 비상 처리 자체가 실패하여 LAO 전체가 중단되는 문제가 있었습니다.

  • 권장 사항: 모든 토큰 전송에 풀 패턴(pull pattern)을 적용하여 단일 실패 지점을 제거해야 합니다.
  • 심각도: Critical (The Lao의 Consensys Diligence 감사)

29. 토큰 오버플로우가 시스템 중단 또는 자금 손실을 유발

취약점: 시스템이 SafeMath를 사용하여 오버플로우 시 revert 되도록 설계되었는데, 만약 악의적이거나 깨진 토큰의 공급량이 비정상적으로 팽창하여 오버플로우가 발생하면, SafeMath의 revert 때문에 제안 처리와 같은 핵심 기능들이 중단되는 문제가 발생했습니다.

  • 권장 사항: 시스템 전체의 중단을 막기 위해, 문제가 있는 특정 토큰에 한해서는 오버플로우를 허용하는 것을 고려해야 합니다. 이 경우 해당 토큰의 잔액은 부정확해지겠지만, 전체 시스템의 생존성(liveness)을 우선시하는 것입니다.
  • 심각도: Major (The Lao의 Consensys Diligence 감사)

30. 화이트리스트된 토큰 수 제한 문제

취약점: _ragequit 함수가 자금 인출 계산을 위해 화이트리스트에 있는 모든 토큰을 순회하도록 설계되었습니다. 만약 화이트리스트에 등록된 토큰의 수가 너무 많아지면, 트랜잭션이 가스 한도를 초과하여 가스 소진(run out of gas)으로 실패하게 됩니다. 결과적으로 아무도 자금을 인출할 수 없게 되어 모든 자금이 동결될 수 있습니다.

  • 권장 사항: 화이트리스트에 등록할 수 있는 토큰의 수를 제한하거나, 잔액이 0이 된 토큰을 투표를 통해 화이트리스트에서 제거하는 기능을 추가해야 합니다.
  • 심각도: Major (The Lao의 Consensys Diligence 감사)

31. bailout 함수를 통해 소환사(Summoner)가 자금을 탈취할 수 있음

취약점: bailout 함수는 추방된(kicked) 사용자가 직접 자금을 회수하지 않을 경우, '소환사'(특권 관리자)가 대신 자금을 옮길 수 있게 합니다. 이는 소환사가 나중에 수동으로 자금을 전달해 줄 것이라는 완전한 신뢰에 기반하는 위험한 방식입니다.

  • 권장 사항: bailout 함수를 제거하고, 토큰 전송에 풀 패턴(pull pattern)을 구현해야 합니다. 이를 통해 프로세스가 신뢰가 필요 없는(trustless) 방식으로 변경되고, 구성원을 더 빠르게 추방할 수 있습니다.
  • 심각도: Major (The Lao의 Consensys Diligence 감사)

32. 제안 스폰서십 프론트러닝

취약점: 제안 제출과 스폰서십이 별개의 트랜잭션으로 이루어질 경우, 공격자가 정상적인 스폰서보다 먼저 프론트러닝(front-run)하여 스폰서십을 가로챌 수 있었습니다. 공격자는 이렇게 스폰서가 된 후, 나중에 해당 제안을 막는 등의 악의적인 행위를 할 동기를 가질 수 있습니다.

  • 권장 사항: 토큰 전송에 풀 패턴(pull pattern)을 적용하면, 프론트러닝이 가능하더라도 실질적인 위협이 되지 않으므로 이 문제를 해결할 수 있습니다.
  • 심각도: Major (The Lao의 Consensys Diligence 감사)

33. 대리인(Delegate) 지정 프론트러닝

취약점: 어떤 멤버가 자신의 대리인 주소(delegateKey)를 지정하려고 할 때, 다른 멤버가 이 트랜잭션을 프론트러닝하여 해당 대리인 주소를 자신의 대리인으로 먼저 지정할 수 있습니다. 이는 특정 주소가 영원히 다른 사람의 대리인이 되지 못하도록 막는 데 사용될 수 있습니다.

  • 권장 사항: 대리인으로 지정될 주소가 이 지정을 승인하거나 취소할 수 있는 기능을 만들거나, 커밋-리빌(commit-reveal) 방식을 사용하여 프론트러닝 공격을 완화해야 합니다.
  • 심각도: Medium (The Lao의 Consensys Diligence 감사)

34. 대기열에 추가된 트랜잭션을 취소할 수 없음

취약점: Governor 컨트랙트가 Timelock 컨트랙트에 트랜잭션을 대기시킬 수는 있지만, 정작 Governor 컨트랙트 내에 대기 중인 트랜잭션을 취소(Timelock.cancelTransaction)하는 기능이 없었습니다. 이로 인해 한 번 대기열에 올라간 트랜잭션은 절대 취소할 수 없었습니다.

  • 권장 사항: 단기적으로 Governor에 트랜잭션을 취소하는 함수를 추가해야 합니다. 장기적으로는 Governor가 Timelock을 상속받도록 하여 두 컨트랙트의 복잡성을 크게 낮추는 것을 고려해야 합니다.
  • 심각도: High Risk (Origin Dollar의 ToB 감사)

35. 제안 트랜잭션이 별도로 실행되어 거버넌스를 우회할 수 있음

취약점: Timelock.executeTransaction 함수에 접근 제어가 누락되어, 누구나 이 함수를 직접 호출하여 대기 중인 제안을 실행할 수 있었습니다. 이는 정상적인 Governor.execute 함수의 검증 절차를 완전히 우회하는 심각한 문제입니다.

  • 권장 사항: Timelock.executeTransaction 함수는 오직 관리자(admin), 즉 Governor 컨트랙트만 호출할 수 있도록 접근을 제한해야 합니다.
  • 심각도: High Risk (Origin Dollar의 ToB 감사)

36. 제안을 통해 타임락 관리자 권한을 탈취할 수 있음

취약점: 일반적인 거버넌스 제안에 Timelock 컨트랙트의 관리자를 변경하는 강력한 작업이 포함될 수 있었습니다. 이는 공격자가 관리자 변경을 내용으로 하는 악의적인 제안을 통과시켜 시스템 전체를 장악할 수 있는 불필요한 위험을 초래합니다.

  • 권장 사항: 일반 제안에는 관리자 변경(setPendingAdmin)과 같은 민감한 작업이 포함될 수 없도록 확인하는 로직을 추가해야 합니다.
  • 심각도: High Risk (Origin Dollar의 ToB 감사)

37. mintMultiple 함수의 재진입 및 신뢰할 수 없는 컨트랙트 호출

취약점: mintMultiple 함수에 재진입 방지 장치가 없고, 지원되는 자산인지에 대한 검증이 누락된 채 신뢰할 수 없는 컨트랙트를 호출했습니다. 공격자는 악의적인 자산 컨트랙트를 등록하여 재진입 공격을 통해 컨트랙트의 자금을 탈취할 수 있었습니다.

  • 권장 사항: 입력값(자산 지원 여부, 0 값 등)을 철저히 검증하고, mint, redeem 등 상태를 변경하는 모든 함수에 재진입 방지 가드를 추가해야 합니다. 또한 신뢰할 수 없는 컨트랙트 호출을 금지해야 합니다.
  • 심각도: High Risk (Origin Dollar의 ToB 감사)

38. 반환 값 체크 누락으로 인한 예기치 않은 결과

취약점: 여러 외부 함수 호출에서 반환 값을 확인하지 않았습니다. 반환 값 확인 없이는 코드가 오류에 취약해지며, 함수 호출이 실패했음에도 성공한 것처럼 동작하여 예기치 않은 결과를 초래할 수 있습니다.

  • 권장 사항: 모든 외부 호출의 반환 값을 확인해야 합니다. Slither나 Crytic.io와 같은 정적 분석 도구를 사용하여 이런 유형의 버그를 자동으로 찾아내는 것이 좋습니다.
  • 심각도: High Risk (Origin Dollar의 ToB 감사)

39. 루프 내 외부 호출로 인한 서비스 거부(DoS) 가능성

취약점: 경계가 없는 루프(unbounded loop) 안에서 외부 함수를 호출하고 있었습니다. 이 패턴은 루프가 너무 길어져 가스 한도를 초과하거나, 루프 중간의 외부 호출이 실패할 경우, 트랜잭션이 항상 실패하여 컨트랙트가 영원히 멈추는 서비스 거부(DoS) 공격에 매우 취약합니다.

  • 권장 사항: 루프의 일부만 순회하도록 하거나(페이징 처리), 루프 내에서 요소를 제거하는 방식을 고려하는 등, 루프 내 외부 호출 패턴을 피해야 합니다.
  • 심각도: High Risk (Origin Dollar의 ToB 감사)

40. OUSD에서 사용자가 가진 것보다 더 많은 토큰을 전송할 수 있음

취약점: 특정 상황에서 잔액을 계산하고 차감하는 로직의 반올림 또는 계산 오류로 인해, 사용자가 실제로 소유한 것보다 더 많은 OUSD 토큰을 전송할 수 있는 심각한 버그가 있었습니다.

  • 권장 사항: 모든 산술 연산을 수행하기 전에 잔액을 정확하게 확인해야 합니다. 또한 Echidna와 같은 퍼징(fuzzing) 도구를 사용하여 ERC-20 전송이 항상 예상된 금액만큼만 이루어지는지 검증하는 속성 기반 테스트를 작성해야 합니다.
  • 심각도: High Risk (Origin Dollar의 ToB 감사)

41. OUSD의 총 공급량이 사용자 잔액보다 작아질 수 있음

취약점: OUSD 토큰은 자산 가치에 따라 잔액이 자동으로 조정되는 리베이싱(rebasing) 메커니즘을 가지고 있지만, 사용자는 이 기능에서 '옵트아웃'할 수 있었습니다. 사용자가 옵트아웃하면 그들의 잔액은 고정되지만, 다른 사용자들의 잔액과 총 공급량은 계속 변합니다. 이는 "모든 사용자 잔액의 합은 총 공급량과 같다"는 기본적인 불변성(invariant)을 깨뜨려, 이 토큰과 상호작용하는 다른 스마트 컨트랙트에 혼란과 예측 불가능한 오류를 유발할 수 있습니다.

  • 권장 사항: 단기적으로는 이러한 불변성 위반 가능성을 사용자들에게 명확히 알려야 합니다. 장기적으로는 가능한 한 일반적인 불변성을 유지하는 방향으로 시스템을 설계해야 합니다.
  • 심각도: High Risk (Origin Dollar의 ToB 감사)

42. 플래시 민팅을 이용한 자금 상환 악용

취약점: 플래시 민팅(하나의 트랜잭션 내에서 새로 발행된 토큰을 담보 없이 빌리는 기능) 기능을 악용하여, 만기가 된 토큰에서 임의의 금액을 상환(redeem)할 수 있었습니다. 공격자는 플래시 민팅으로 얻은 막대한 레버리지를 이용해 시장을 조작하고 내부 불변성을 깨뜨릴 수 있었습니다.

  • 권장 사항: 플래시 민팅이 진행 중일 때는 redeem과 같은 민감한 함수 호출을 금지해야 합니다.
  • 심각도: Medium Risk (Yield Protocol의 ToB 감사)

43. chainID 검증 부재로 인한 서명 재사용 공격

취약점: ERC-2612의 permit 함수에서 사용하는 서명 데이터에 chainID가 포함되지 않았습니다. 만약 컨트랙트 배포 후 블록체인이 하드포크될 경우, 하나의 체인에서 사용된 서명이 다른 체인에서 재사용(replay)되어 사용자의 승인(allowance)을 무단으로 변경하는 리플레이 공격이 가능했습니다.

  • 권장 사항: 서명 스키마에 chainID를 포함하여, 서명이 특정 체인에서만 유효하도록 만들어야 합니다.
  • 심각도: High Risk (Yield Protocol의 ToB 감사)

44. 컨트랙트 존재 여부 미확인으로 인한 토큰 절도

취약점: 외부 토큰과 상호작용할 때, 해당 토큰 컨트랙트가 실제로 블록체인에 배포되었는지 확인하지 않았습니다. 로우레벨 call은 대상 주소에 코드가 없어도 성공(true)을 반환하기 때문입니다.

  • 공격 시나리오: 공격자는 앞으로 배포될 토큰의 주소(미리 계산 가능)를 시스템에 등록합니다. 실제 토큰이 배포되고 자금이 예치되면, 공격자는 이전에 등록한 기록을 이용해 진짜 토큰을 훔쳐갈 수 있습니다.
  • 권장 사항: 로우레벨 call을 사용하기 전에는 항상 address.code.length > 0과 같은 방법으로 컨트랙트 존재 여부를 확인해야 합니다.
  • 심각도: High Risk (Hermez의 ToB 감사)

45. 입찰자들이 일찍 투표할 인센티브 부재

취약점: 입찰 기반의 투표 시스템에서 모든 입찰이 공개되고, 일찍 입찰할 인센티브가 전혀 없었습니다. 이는 자금이 많은 참여자가 투표 마감 직전에 거액을 입찰하여 결과를 조작하는 "스나이핑(sniping)"을 조장합니다. 먼저 입찰한 참여자는 자신의 전략이 노출되어 불리해집니다.

  • 권장 사항: 시간이 지남에 따라 가중치가 감소하는 '가중 입찰' 등을 도입하여 사용자들이 더 일찍 투표하도록 장려해야 합니다. 이는 공격 비용을 높여 투표 조작 가능성을 줄입니다.
  • 심각도: Medium Risk (Hermez의 ToB 감사)

46. 위험한 접근 제어 분리 부재

취약점: 자주 변경되는 파라미터(예: 토큰/USD 비율)와 거의 변경되지 않는 중요한 파라미터를 동일한 관리자 계정으로 변경하도록 설계되었습니다. 이는 단일 계정이 탈취될 경우 시스템 전체가 위험에 빠지는 등, 단일 실패 지점(Single Point of Failure)을 만듭니다.

  • 권장 사항: 권한의 중요도와 사용 빈도에 따라 접근 제어를 분리해야 합니다. 자주 사용하는 저위험 작업은 핫 월렛으로, 중요한 고위험 작업은 콜드 월렛이나 다중서명 지갑으로 관리하는 것이 좋습니다.
  • 심각도: High Risk (Hermez의 ToB 감사)

47. 중요 작업에 대한 2단계 절차 부재

취약점: 관리자 주소 변경과 같이 되돌릴 수 없는 중요한 작업들이 단일 트랜잭션으로 처리되었습니다. 만약 실수로 잘못된 주소를 입력하면, 변경사항이 즉시 적용되어 복구가 불가능한 치명적인 실수를 유발할 수 있습니다.

  • 권장 사항: 되돌릴 수 없는 모든 중요 작업에는 2단계 절차를 도입해야 합니다. 예를 들어, 현재 소유자가 새로운 소유자를 '제안'하고, 새로운 소유자가 이를 '수락'해야만 최종적으로 소유권이 변경되는 방식입니다.
  • 심각도: High Risk (Hermez의 ToB 감사)

48. 초기화 함수 프론트러닝 가능

취약점: 프록시 패턴을 사용하는 컨트랙트는 생성자 대신 공개된 initializer 함수를 사용하는데, 이 함수가 프론트러닝 공격에 노출되어 있었습니다. 공격자는 컨트랙트 배포 트랜잭션을 보고, 정상적인 초기화가 실행되기 전에 먼저 initializer 함수를 호출하여 악의적인 값으로 컨트랙트를 초기화하고 탈취할 수 있습니다.

  • 권장 사항: 팩토리 패턴을 사용하여 컨트랙트 생성과 초기화를 하나의 트랜잭션으로 묶어 프론트러닝을 방지하거나, 배포 스크립트를 견고하게 작성해야 합니다.
  • 심각도: High Risk (Hermez의 ToB 감사)

49. _owner 인자 검증 누락으로 인한 소유권 영구 잠금 가능

취약점: 생성자와 setOwner 함수에서 새로운 소유자 주소에 대한 입력값 검증이 누락되었습니다. 만약 address(0)이나 잘못된 주소를 입력하면, 소유자 전용 기능이 영원히 잠겨 컨트랙트를 재배포해야 하는 상황이 발생할 수 있습니다.

  • 권장 사항: 초기 소유자는 msg.sender로 지정하고, 배포 후 소유권을 이전하거나, 새로운 소유자가 소유권을 수락해야 하는 2단계 절차를 구현하는 것이 좋습니다.
  • 심각도: Medium Risk (Uniswap V3의 ToB 감사)

50. 잘못된 비교 연산자로 무료 스왑 및 토큰 탈취 가능

취약점: swap 함수의 require 문에서 비교 연산자를 <= 대신 >=로 잘못 사용했습니다. 이로 인해 require(지불한_토큰 >= 내야할_토큰) 구문은 사용자가 토큰을 전혀 지불하지 않아도(0 >= 내야할_토큰은 항상 참) 통과되었습니다. 이 버그는 아무 비용 없이 풀의 모든 토큰을 탈취할 수 있는 치명적인 결과를 낳았습니다.

  • 권장 사항: require 문에서 비교 연산자를 >=에서 <=로 수정해야 합니다.
  • 심각도: High Risk (Uniswap V3의 ToB 감사)

51. 경계 없는 루프로 인한 서비스 거부(DoS)

취약점: swap 함수가 반복 횟수에 상한선이 없는, 즉 경계 없는 루프(unbounded loop)에 의존하고 있었습니다. 공격자는 이 루프가 매우 많이 반복되도록 유도하여 트랜잭션의 가스를 모두 소진시킬 수 있으며, 이로 인해 swap 기능이 영원히 멈추는 서비스 거부(DoS)를 유발할 수 있습니다.

  • 권장 사항: 루프에 합리적인 상한선을 설정하고, 그 한계치를 문서화해야 합니다.
  • 심각도: Medium Risk (Uniswap V3의 ToB 감사)

52. 유동성 풀 초기화 프론트러닝으로 인한 예치금 탈취

취약점: 유니스왑 V3 풀의 initialize 함수에 접근 제어가 없어 누구나 호출할 수 있었습니다. 공격자는 정상적인 유동성 공급자(LP)의 풀 생성 트랜잭션을 프론트러닝(front-run)하여, 먼저 initialize를 호출하고 불공정한 가격을 설정할 수 있습니다. 그 후, 정상 LP가 이 잘못된 가격으로 유동성을 예치하면, 공격자는 차익 거래를 통해 최초 예치금을 탈취할 수 있습니다.

  • 권장 사항: initialize 함수에 접근 제어를 추가하거나, 가격 설정을 생성자(constructor)로 옮기거나, 혹은 사용자에게 초기화의 위험성을 명확히 경고해야 합니다.
  • 심각도: Medium Risk (Uniswap V3의 ToB 감사)

53. 유동성 0인 상태에서의 스왑으로 인한 가격 조작

취약점: 유동성이 전혀 없는 풀이나 특정 가격 구간(tick)에서, 사용자는 아주 적은 양의 토큰(예: 1 wei)만으로 스왑을 일으켜 거래 가격을 마음대로 설정할 수 있습니다. 공격자는 풀이 막 생성되었을 때나 LP들이 일시적으로 유동성을 모두 회수했을 때 이 점을 악용하여 가격을 조작할 수 있습니다.

  • 권장 사항: 이 문제를 막을 명확한 방법은 없습니다. 풀이 예기치 않은 상태에 빠지지 않도록 보장하고, 사용자에게 잠재적 위험을 경고해야 합니다.
  • 심각도: Medium Risk (Uniswap V3의 ToB 감사)

54. 컨트랙트 존재 여부 미확인으로 인한 전송 실패 간과

취약점: safeTransfer 헬퍼 함수가 로우레벨 call을 사용하면서 토큰 컨트랙트가 실제로 존재하는지 확인하지 않았습니다. 만약 토큰 컨트랙트가 아직 배포되지 않았거나, selfdestruct로 파괴된 경우, 실제 토큰 전송은 일어나지 않았음에도 call은 성공(true)을 반환합니다. 이로 인해 프로토콜은 실패한 전송을 성공으로 간주하게 됩니다.

  • 권장 사항: 로우레벨 call을 사용하기 전에는 항상 컨트랙트의 존재 여부(address.code.length > 0)를 확인해야 합니다. 장기적으로는 로우레벨 call 사용 자체를 피하는 것이 좋습니다.
  • 심각도: High Risk (Uniswap V3의 ToB 감사)

55. 동등성 검사에서 정의되지 않은 동작 사용

취약점: 코드에 if ((outputAmt_ = 계산식) == 함수(outputAmt_))와 같이, 하나의 등호(==) 검사문에서 같은 변수에 값을 할당하고 동시에 사용하는 코드가 있었습니다. 솔리디티 문서는 등호 양쪽의 평가 순서를 보장하지 않으므로, 이는 "정의되지 않은 동작(undefined behavior)"에 해당합니다. 이런 코드는 컴파일러 버전이 바뀌면 동작이 달라져 코드가 깨질 수 있습니다.

  • 권장 사항: if 문을 두 줄로 나누어, 변수 할당과 비교를 명확히 분리해야 합니다.
  • 심각도: High Risk (DFX Finance의 ToB 감사)

56. 어시밀레이터의 잔액 함수가 원시 값을 반환

취약점: 시스템 내부 계산에는 정규화된(numeraire) 값을 사용해야 하지만, 일부 어시밀레이터의 잔액 함수가 정규화되지 않은 원시 값(raw value)을 반환했습니다. 이 두 종류의 값을 혼용하여 계산하면 잘못된 결과가 발생하고 유동성 공급자의 자금 손실로 이어질 수 있습니다.

  • 권장 사항: 모든 관련 함수가 일관되게 정규화된 값을 반환하도록 수정해야 합니다.
  • 심각도: High Risk (DFX Finance의 ToB 감사)

57. 시스템이 항상 USDC를 USD와 동일하다고 가정

취약점: USDC 스테이블코인을 처리하는 어시밀레이터가 체인링크 오라클을 사용하지 않고, 1 USDC가 항상 1 USD와 같다고 하드코딩되어 있었습니다. 만약 USDC의 가치가 1달러에서 벗어나는 디페깅(de-pegging)이 발생하면, 시스템은 USDC 가치를 잘못 계산하여 막대한 손실을 유발할 수 있습니다.

  • 권장 사항: 하드코딩된 값을 제거하고, 다른 스테이블코인처럼 체인링크와 같은 신뢰할 수 있는 오라클을 통해 실시간 가격을 가져와야 합니다.
  • 심각도: Medium Risk (DFX Finance의 ToB 감사)

58. 어시밀레이터가 폐지된 체인링크 API를 사용

취약점: 컨트랙트가 체인링크 가격 피드의 오래되고 폐지된(deprecated) 버전의 API(latestAnswer 함수 등)를 사용하고 있었습니다. 만약 체인링크가 이 폐지된 API 지원을 중단하면, 프로토콜은 최신 가격을 가져오지 못해 멈추거나 자금 손실을 유발할 수 있습니다.

  • 권장 사항: 외부 라이브러리나 컨트랙트를 사용할 때는 항상 최신 안정화 버전을 사용해야 합니다.
  • 심각도: Undetermined Risk (DFX Finance의 ToB 감사)

59. cancelOrdersUpTo 함수로 미래의 주문을 영구적으로 막을 수 있음

취약점: cancelOrdersUpTo(N) 함수는 salt 값이 N보다 작은 모든 주문을 취소합니다. 만약 사용자가 이 함수를 매우 큰 값(예: MAX_UINT256 - 1)으로 호출하면, 거의 모든 미래의 주문까지 영구적으로 취소시켜 버리는 효과를 낳습니다. 이 작업은 되돌릴 수 없습니다.

  • 권장 사항: 이 함수의 영구적인 효과에 대해 사용자에게 명확히 경고하거나, 미래 주문의 취소를 아예 금지하는 것을 고려해야 합니다.
  • 심각도: High Risk (0x Protocol의 ToB 감사)

60. 타임락 기간에 대한 명세와 코드의 불일치

취약점: 프로젝트 명세서에는 관리자 작업에 2주의 타임락 기간이 강제된다고 명시되어 있지만, 실제 스마트 컨트랙트 코드에는 이 기간이 소유자가 임의로 변경할 수 있는 변수로 구현되어 있었고, 범위 검사도 없었습니다. 소유자는 이 값을 0으로 설정하여 타임락을 즉시 우회할 수 있었습니다.

  • 권장 사항: 명세에 맞게 2주의 타임락을 강제하도록 코드를 수정하거나, 코드의 동작에 맞게 명세를 수정해야 합니다. 명세와 구현은 항상 동기화되어야 합니다.
  • 심각도: High Risk (0x Protocol의 ToB 감사)

61. 주문 체결 가능 여부에 대한 불분명한 문서

취약점: 어떤 주문이 체결 가능한지, 그리고 완전히 체결될 수 있는지 판단하는 방법에 대한 0x 프로토콜의 문서가 불분명했습니다. 이러한 모호함은 개발자들이 프로토콜 위에 신뢰할 수 있는 애플리케이션을 구축하는 것을 어렵게 만듭니다.

  • 권장 사항: 주문 체결 가능 여부를 판단하는 명확한 절차를 정의하고, 이를 프로토콜 명세서에 제대로 문서화해야 합니다. 필요한 경우, 사용자에게 주문의 잠재적 제약 조건에 대해 경고해야 합니다.
  • 심각도: High Risk (0x Protocol의 ToB 감사)

62. 마켓 메이커의 프론트러닝 공격 비용이 절감되는 문제

취약점: 마켓 메이커(MM)는 체결된 각 주문에 대해 프로토콜 수수료의 일부를 환급받는데, 이 수수료는 트랜잭션의 가스 가격(tx.gasprice)에 기반합니다. 이 구조 때문에 MM은 다른 사용자들을 프론트러닝하기 위해 매우 높은 가스비를 지불하더라도, 나중에 수수료 풀에서 환급을 받아 실질적으로는 더 저렴한 비용으로 프론트러닝 공격을 할 수 있는 불공정한 이점을 가집니다.

  • 권장 사항: 단기적으로는 이 위험을 사용자에게 명확히 알리고, 프로토콜 수수료 승수에 합리적인 상한선을 설정해야 합니다. 장기적으로는 tx.gasprice에 의존하지 않는 수수료 모델을 고려해야 합니다.
  • 심각도: Medium Risk (0x Protocol의 ToB 감사)

63. 서명 검증자 승인 로직의 레이스 컨디션 악용 가능성

취약점: 서명 검증자를 위임하는 setSignatureValidatorApproval 함수에 레이스 컨디션(race condition)이 존재했습니다. 만약 위임된 서명 검증자 컨트랙트가 해킹당할 경우, 공격자는 이 레이스 컨디션을 악용하여 수많은 악의적인 트랜잭션을 유효한 것처럼 통과시킬 수 있습니다.

  • 권장 사항: 검증자 컨트랙트가 해킹될 경우의 내재된 위험에 대해 사용자에게 명확히 문서화해야 합니다. 장기적으로는 SignatureValidatorApproval 이벤트를 모니터링하여 프론트러닝 공격을 탐지하는 것을 고려해야 합니다.
  • 심각도: Medium Risk (0x Protocol의 ToB 감사)

64. 일괄 처리 시 그리핑(griefing) 공격 가능성

취약점: 여러 트랜잭션과 주문을 일괄 처리(batch processing)할 때, 그중 단 하나의 거래라도 자산의 allowance 부족 등으로 실패하면, 배치 전체가 revert 되는 문제가 있었습니다. 실패를 건너뛰는 "NoThrow" 버전이 다른 기능에는 있었지만, 이 기능에는 없었습니다.

  • 공격 시나리오: 공격자는 의도적으로 실패하는 트랜잭션을 배치에 포함시켜, 전체 배치를 계속해서 실패하게 만드는 그리핑(griefing) 또는 서비스 거부(DoS) 공격을 할 수 있습니다.
  • 권장 사항: 트랜잭션 실행 및 주문 매칭의 일괄 처리에도 실패를 건너뛸 수 있는 "NoThrow" 버전을 구현해야 합니다.
  • 심각도: Medium Risk (0x Protocol의 ToB 감사)

65. 가스 가격 0으로 수수료 없는 주문 가능

취약점: 프로토콜 수수료가 사용자가 설정한 tx.gasprice에 기반하여 계산되었습니다. 이는 사용자가 (만약 채굴자가 포함시켜준다면) 가스 가격을 0으로 설정하여 프로토콜 수수료를 전혀 내지 않고 유효한 주문을 제출할 수 있게 합니다.

  • 권장 사항: 각 주문이나 트랜잭션에 대해 합리적인 최소 프로토콜 수수료를 설정해야 합니다. 장기적으로는 가스 가격에 의존하지 않는 수수료 모델을 고려해야 합니다.
  • 심각도: Medium Risk (0x Protocol의 ToB 감사)

66. setParams 함수가 유효하지 않은 값을 설정할 수 있음

취약점: 소유자가 setParams 함수를 통해 컨트랙트의 중요한 파라미터를 변경할 수 있지만, 입력된 값에 대한 유효성 검사(sanity/threshold/limit checks)가 전혀 없었습니다. 유효하지 않은 파라미터 값은 컨트랙트를 망가뜨리거나 예기치 않은 동작을 유발할 수 있습니다.

  • 권장 사항: setParams 함수 내 모든 파라미터에 대해 적절한 유효성 검사를 추가해야 합니다.
  • 심각도: Medium Risk (0x Protocol의 ToB 감사)

67. 부적절한 공급 한도 제한 적용

취약점: openLoan() 함수가 대출을 발행하기 전에 총 공급량이 한도에 도달했는지 확인했지만, 새로 발행될 대출로 인해 한도를 초과하게 될 것인지는 확인하지 않았습니다. 이로 인해 총 공급량이 의도된 한도를 훨씬 초과하여 발행될 수 있었습니다.

  • 권장 사항: openLoan() 함수에 "새로운 대출 금액을 더했을 때 총 공급량이 한도를 초과하지 않는지"를 확인하는 require 구문을 추가해야 합니다.
  • 심각도: High Risk (Synthetix EtherCollateral의 Sigma Prime 감사)

68. 대출 계정의 부적절한 스토리지 관리

취약점: 대출이 발생하면 accountsWithOpenLoans 배열에 계정 주소가 추가되는데, 이미 주소가 배열에 있는지 확인하지 않아 중복 저장이 가능했습니다. 또한, 악의적인 행위자가 이 경계 없는 배열을 악용하여 가스 소진을 유발하는 서비스 거부(DoS) 상태를 만들 수 있었습니다.

  • 권장 사항: 해당 계정의 첫 대출일 경우에만 배열에 주소를 추가하도록 변경하고, 계정당 최대 대출 수를 제한하는 것을 고려해야 합니다.
  • 심각도: High Risk (Synthetix EtherCollateral의 Sigma Prime 감사)

69. 소유자가 발행 수수료와 이자율을 임의로 변경 가능

취약점: 컨트랙트 소유자가 이미 대출이 실행된 후에도 발행 수수료(issueFeeRate)와 이자율(interestRate)을 언제든지 변경할 수 있었습니다. 악의적인 소유자는 수수료를 담보보다 높게 설정하여 사실상 사용자의 담보를 탈취할 수 있습니다.

  • 권장 사항: 동적 이자율은 일반적일 수 있지만, 발행 수수료는 배포 후 변경할 수 없는 constant로 만드는 것을 고려해야 합니다.
  • 심각도: Medium Risk (Synthetix EtherCollateral의 Sigma Prime 감사)

70. 부적절한 프록시 구현으로 인한 컨트랙트 업그레이드 불가

취약점: 프록시 패턴의 고질적인 초기화 문제입니다. 구현 컨트랙트(TokenImpl)는 자신의 constructor에서 owner, name과 같은 상태 변수를 설정합니다. 하지만 프록시 컨트랙트가 이 로직을 delegatecall로 실행하면, 상태는 프록시의 스토리지에 기록되어야 합니다. 문제는, 프록시가 이 초기화 로직을 직접 실행한 적이 없으므로 프록시의 해당 스토리지 슬롯은 초기화되지 않은 0값으로 남아있게 됩니다. 결과적으로 owner는 address(0)이 되고, 프록시 컨트랙트는 사용할 수 없게 됩니다.

  • 권장 사항: 생성자 대신, 배포 후 한 번만 호출할 수 있는 initializer 함수를 만들어 프록시가 직접 호출하도록 해야 합니다. 또는, 고정된 파라미터는 constant로 선언하거나, 소유자만 호출할 수 있는 setter 함수를 만드는 방법도 있습니다.
  • 심각도: Critical Risk (InniGold의 Sigma Prime 감사)

71. transferFrom() 함수를 통한 블랙리스트 우회

취약점: transferFrom(from, to, amount) 함수에서, 토큰을 실제로 보내는 주체인 from 주소가 블랙리스트에 있는지 확인하지 않았습니다. 이 때문에 블랙리스트에 오른 사용자가 승인(approve) 기능과 제3자를 이용하여 자신의 토큰을 옮기는 것이 가능했습니다.

  • 권장 사항: msg.sender와 to 주소뿐만 아니라, from 주소에 대해서도 블랙리스트 확인 로직을 추가해야 합니다.
  • 심각도: High Risk (InniGold의 Sigma Prime 감사)

72. 잘못된 연산 순서로 인한 보상 지수적 증가

취약점: 보상 계산 공식에서, rewardPerTokenStored 값이 분수에 더해져야 하는데 실수로 분자에 포함되어 곱해졌습니다. 이로 인해 보상이 선형적으로 증가하지 않고 지수적으로 폭증하여, 사용자들에게 과도한 보상이 지급되거나 컨트랙트의 잔고 부족으로 아무도 보상을 받지 못하게 되는 등 시스템을 완전히 망가뜨렸습니다.

  • 권장 사항: 원래 의도된 기능에 맞게 수학 공식을 정확하게 수정해야 합니다.
  • 심각도: Critical Risk (Synthetix Unipool의 Sigma Prime 감사)

73. 최초 보상 공지 전 스테이킹으로 인한 불공정한 보상 분배

취약점: 첫 번째 보상 기간이 공지(notifyRewardAmount() 호출)되기도 전에 사용자가 토큰을 스테이킹할 수 있었습니다. 이 경우, 해당 사용자의 보상 정산 기록(userRewardPerTokenPaid)이 0으로 초기화되어, 첫 보상 분배 시 자신의 지분보다 훨씬 많은 보상을 불공정하게 수령하는 문제가 발생했습니다.

  • 권장 사항: 최초로 notifyRewardAmount()가 호출되기 전까지는 stake() 함수 호출을 막아야 합니다.
  • 심각도: High Risk (Synthetix Unipool의 Sigma Prime 감사)

74. 보상 기간 미경과 시 외부 호출이 revert되는 문제

취약점: notifyRewardAmount() 함수는 보상 기간이 아직 끝나지 않았을 때 호출되면 revert 되도록 설계되었습니다. 그런데 이 함수는 더 중요한 외부 함수인 Synthetix.mint()에 의해 간접적으로 호출됩니다. 이 때문에 보상 기간이 끝나기 전까지는 Synthetix.mint() 함수 자체가 계속 실패하여 핵심 프로세스가 중단되는 문제가 발생했습니다.

  • 권장 사항: 보상 기간이 아직 경과하지 않은 경우, 트랜잭션 전체를 revert 시키지 않고 정상적으로 처리하도록 로직을 수정해야 합니다.
  • 심각도: High Risk (Synthetix Unipool의 Sigma Prime 감사)

75. 보상 기간 사이의 공백으로 인한 잘못된 보상 계산

취약점: 보상 기간이 끝난 후 다음 보상 기간이 시작되기까지 시간적 공백이 발생할 수 있었습니다. 이 공백 기간 동안 컨트랙트는 새로운 보상 유입 없이 기존 보상률에 따라 계속해서 보상을 지급한다고 계산하여, 실제 보유한 자산보다 더 많은 보상을 지급해야 하는 부채가 쌓였습니다. 결국 모든 스테이커가 보상을 인출하려고 할 때 컨트랙트의 잔고가 부족해지는 사태로 이어질 수 있습니다.

  • 권장 사항: 이전 기간이 끝나는 시점에 다음 기간이 정확히 시작되도록 강제해야 합니다.
  • 심각도: Medium Risk (Synthetix Unipool의 Sigma Prime 감사)

76. 악의적인 사용자에 의한 체인링크 요청 하이재킹/서비스 거부(DoS)

취약점: 체인링크 요청 시 콜백 주소를 임의로 지정할 수 있다는 점을 악용한 공격입니다. 공격자는 자신의 악의적인 요청에 대한 콜백 주소를 피해자 컨트랙트 주소로 지정한 후, 정상적인 요청보다 먼저 처리되도록 프론트러닝할 수 있습니다. 그러면 오라클은 피해자 컨트랙트에 악의적인 데이터를 전달하고, 이로 인해 피해자의 정상적인 요청은 처리되지 못하고 실패하게 됩니다.

  • 권장 사항: 요청자가 자기 자신 외에 다른 컨트랙트를 콜백 주소로 지정할 수 없도록 제한하는 것이 근본적인 해결책입니다.
  • 심각도: High Risk (Chainlink의 Sigma Prime 감사)

77. 민감한 작업 후 이벤트 미발생

취약점: 펀딩 비율을 설정하거나 보상을 전송하는 등 민감하고 중요한 상태 변경이 일어난 후에 관련 이벤트를 발생시키지 않았습니다. 이는 오프체인 클라이언트나 모니터링 서비스가 컨트랙트의 중요한 활동을 추적하는 것을 매우 어렵게 만듭니다.

  • 권장 사항: 민감한 변경이 발생한 후에는 항상 이벤트를 발생시켜, 투명성을 높이고 추적을 용이하게 해야 합니다.
  • 심각도: Medium Risk (UMA Phase 4의 OpenZeppelin 감사)

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

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

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

79. Mooniswap 페어를 재개할 수 없음

취약점: MooniswapFactoryGovernance 컨트랙트는 거래 페어를 중단(shutdown)하는 기능은 있지만, 중단된 페어를 다시 재개(unpause)하는 기능이 없었습니다. 이로 인해 한 번 중단된 페어는 새로운 팩토리 컨트랙트를 배포하지 않는 한 영원히 거래를 재개할 수 없었습니다.

  • 권장 사항: 중단된 Mooniswap 컨트랙트를 다시 재개할 수 있는 방법을 제공해야 합니다.
  • 심각도: Medium Risk (1inch Liquidity Protocol의 OpenZeppelin 감사)

80. 공격자가 정직한 사용자의 즉시 인출을 막을 수 있음

취약점: 그리핑(griefing) 공격의 일종입니다. 공격자는 멤풀에서 정직한 사용자의 즉시 인출(instantWithdraw) 트랜잭션을 보고, 그 안의 서명 데이터를 복사합니다. 그 후, 더 높은 가스비로 자신의 트랜잭션을 먼저 보내면서, 고의적으로 가스 한도를 낮게 설정합니다. 이 공격 트랜잭션은 일회용 상호작용 번호(userInteractionNumber)를 소모한 직후 가스 부족으로 실패합니다. 결과적으로, 뒤따르는 정직한 사용자의 트랜잭션은 이미 사용된 번호를 사용하려 하기 때문에 실패하게 되어 인출이 막힙니다.

  • 권장 사항: 사용자를 대신하여 오라클 메시지를 제출할 수 있는 주체를 제한하는 접근 제어 메커니즘을 추가하는 것을 고려해야 합니다.
  • 심각도: High Risk (Futureswap V2의 OpenZeppelin 감사)

81. 업그레이드 가능한 컨트랙트 상속 오류

취약점: 업그레이드 가능하도록 설계된 FsToken 컨트랙트가, 상속받는 ERC20Snapshot 등의 부모 컨트랙트들을 업그레이드 안전(upgrade-safe) 버전이 아닌 일반 버전으로 가져왔습니다. 일반 버전의 컨트랙트는 생성자(constructor)를 사용하므로, 프록시 패턴에서 필수적인 initializer 로직과 충돌하여 예상치 못한 문제를 일으킬 수 있습니다.

  • 권장 사항: 업그레이드 가능한 컨트랙트를 작성할 때는, 상속받는 모든 부모 컨트랙트 역시 @openzeppelin/contracts-upgradeable과 같은 업그레이드 안전 라이브러리에서 가져와야 합니다.
  • 심각도: Medium Risk (Futureswap V2의 OpenZeppelin 감사)

82. ECDSA.recover 함수의 반환 값 미확인

취약점: ECDSA.recover 함수는 제공된 서명이 유효하지 않을 경우 address(0)을 반환합니다. 하지만 코드에서는 이 반환 값을 확인하지 않고, 유효하지 않은 서명으로부터 복구된 address(0)을 그대로 오라클 주소나 사용자 주소로 설정했습니다. 이는 유효하지 않은 서명이 address(0)으로부터의 정상적인 요청으로 둔갑하여 시스템에 예기치 않은 동작을 유발할 수 있습니다.

  • 권장 사항: ECDSA.recover 함수의 결과가 address(0)일 경우, 트랜잭션을 revert 시키는 확인 절차를 추가해야 합니다.
  • 심각도: Medium Risk (Futureswap V2의 OpenZeppelin 감사)

83. 다중 상속된 업그레이드 가능 컨트랙트에 변수 추가 시 스토리지 레이아웃 손상

취약점: 여러 단계로 상속된 업그레이드 가능 컨트랙트 구조에서, 부모 컨트랙트에 새로운 상태 변수를 추가하면, 이 변수가 자식 컨트랙트가 이미 사용하고 있는 스토리지 슬롯을 덮어쓰는 치명적인 버그가 발생할 수 있습니다. 이는 자식 컨트랙트의 상태를 손상시켜 시스템 전체를 망가뜨립니다.

  • 권장 사항: 이러한 시나리오를 방지하려면, 각 업그레이드 가능 부모 컨트랙트의 마지막에 "스토리지 갭(storage gap)" 변수를 선언해야 합니다. (예: uint256[50] __gap;) 이는 미래의 변수 추가를 위한 빈 슬롯을 예약하는 역할을 하며, 나중에 새로운 변수를 추가할 때 이 갭의 크기를 줄이는 방식으로 스토리지 충돌을 피할 수 있습니다.
  • 심각도: Medium Risk (Notional Protocol의 OpenZeppelin 감사)

84. 나눗셈 함수에서의 안전하지 않은 연산

취약점: 나눗셈을 수행하는 함수(rdivide, wdivide)에서 나누는 값 y가 0인지 확인하는 절차가 없었습니다. 만약 y가 0으로 전달되면, "0으로 나누기" 에러로 인해 트랜잭션이 revert 되어 서비스 거부(DoS)를 유발할 수 있습니다.

  • 권장 사항: 함수 시작 부분에 require(y > 0)과 같은 확인 구문을 추가하거나, OpenZeppelin의 SafeMath 라이브러리(0.8.0 이전 버전의 경우)에 있는 div 함수를 사용해야 합니다.
  • 심각도: Medium Risk (GEB Protocol의 OpenZeppelin 감사)

85. 잘못된 safeApprove 사용

취약점: OpenZeppelin의 safeApprove 함수는 0이 아닌 승인량을 다른 0이 아닌 값으로 변경하는 것을 막아 프론트러닝 공격을 방지합니다. 하지만 코드에서는 이 보호 기능을 우회하기 위해 먼저 승인량을 0으로 설정한 후 새로운 값으로 다시 설정하는 편법을 사용했습니다. 이는 safeApprove가 막으려 했던 바로 그 프론트러닝 공격에 다시 취약해지게 만듭니다.

  • 권장 사항: 이와 같은 편법 대신, safeIncreaseAllowance와 safeDecreaseAllowance 함수를 사용하여 안전하게 승인량을 조절해야 합니다.
  • 심각도: Medium Risk (1inch Exchange의 OpenZeppelin 감사)

86. 프로토콜에 ETH가 갇힐 수 있음

취약점: 컨트랙트가 여러 작업을 일괄 처리하기 위해 사용자로부터 ETH를 받았지만, 만약 사용자가 필요한 양보다 더 많은 ETH를 보냈을 경우, 남은 ETH를 사용자에게 돌려주는 기능이 없었습니다. 이로 인해 남은 ETH는 컨트랙트 안에 영원히 갇히게 됩니다.

  • 권장 사항: 작업이 끝난 후 남은 모든 ETH를 사용자에게 반환하거나, 사용자가 남은 ETH를 직접 인출해갈 수 있는 별도의 함수를 만들어야 합니다.
  • 심각도: High Risk (Opyn Gamma Protocol의 OpenZeppelin 감사)

87.  transfer() 사용으로 인한 ETH 인출 불가 문제

취약점: ETH 예금을 인출할 때, 2300 가스만 전달하는 Solidity의 transfer 함수를 사용했습니다. 만약 인출하는 주체가 스마트 컨트랙트일 경우, 다음과 같은 상황에서 인출이 필연적으로 실패하게 됩니다.

  1. 해당 컨트랙트에 payable fallback 함수가 없는 경우
  2. payable fallback 함수가 2300보다 많은 가스를 소모하는 경우
  • 권장 사항: OpenZeppelin의 Address 라이브러리에 있는 sendValue 함수를 사용해야 합니다. 이 함수는 가스 제한 없이 모든 가스를 전달하므로 위와 같은 문제를 해결할 수 있습니다.
  • 심각도: Medium Risk (Opyn Gamma Protocol의 OpenZeppelin 감사)

88. Checks-Effects-Interactions 패턴을 따르지 않음

취약점: finalizeGrant 함수가 보조금이 완료되었다는 상태 변수(grant.complete)를 변경하는(Effect) 것보다 먼저 토큰을 전송(Interaction)했습니다. 이는 재진입 공격에 매우 취약합니다.

  • 공격 시나리오: 공격자는 토큰 전송을 받는 악의적인 컨트랙트를 통해 finalizeGrant 함수가 완료되기 전에 다시 호출하여, grant.complete가 true로 설정되기 전에 여러 번의 수수료를 빼갈 수 있습니다.
  • 권장 사항: 항상 "Checks-Effects-Interactions" 패턴을 따라야 합니다. 즉, 상태를 먼저 변경(Effects)하고, 그 다음에 외부 호출(Interactions)을 수행해야 합니다.
  • 심각도: High Risk (Endaoment의 OpenZeppelin 감사)

89. 민감한 주소 변경 시 이벤트 미발생

취약점: 거버넌스 레지스트리나 가디언 주소와 같은 매우 민감하고 중요한 주소들이 변경될 때 아무런 이벤트를 발생시키지 않았습니다. 이는 악의적인 주소 변경이 일어나도 사용자들이나 모니터링 시스템이 이를 즉시 알아차리기 어렵게 만들어 투명성을 크게 저해합니다.

  • 권장 사항: 이러한 민감한 주소가 업데이트될 때는 항상 이벤트를 발생시켜, 누구나 변경 사항을 추적하고 시스템 상태를 감시할 수 있도록 해야 합니다.
  • 심각도: High Risk (Audius의 OpenZeppelin 감사)

90. 시빌 계정으로 쿼럼(의결 정족수)을 쉽게 우회 가능

취약점: 제안 투표의 유효성을 결정하는 쿼럼(quorum)이 토큰 가중치가 아닌, 투표에 참여한 고유 계정의 수로 측정되었습니다.

  • 시빌 공격(Sybil Attack): 공격자는 토큰을 여러 개의 새로운 계정으로 분산시킨 후, 각각의 계정으로 투표하여 적은 지분으로도 쉽게 쿼럼 요구사항을 충족시킬 수 있습니다.
  • 권장 사항: 쿼럼을 측정할 때 계정의 수가 아닌, 투표에 참여한 총 토큰의 비율을 기준으로 삼아야 합니다.
  • 심각도: High Risk (Audius의 OpenZeppelin 감사)

91. 일관성 없는 초기화 확인

취약점: 컨트랙트가 초기화되었는지 확인하는 _requireIsInitialized 함수가, 일관성 없이 일부 함수에서는 사용되고 다른 함수에서는 사용되지 않았습니다. 이는 개발자에게 혼란을 줄 수 있으며, 초기화되지 않은 컨트랙트와 상호작용하여 예기치 않은 오류를 발생시킬 수 있습니다.

  • 권장 사항: 모든 함수에서 일관되게 _requireIsInitialized를 호출하거나, 혹은 이 확인 로직을 완전히 제거하고 배포 시점에 초기화가 반드시 이루어지도록 보장하는 견고한 배포 스크립트에 의존하는 것을 고려해야 합니다.
  • 심각도: Medium Risk (Audius의 OpenZeppelin 감사)

92. 투표 기간과 쿼럼이 0으로 설정될 수 있음

취약점: 컨트랙트 초기화 시점에는 votingPeriod(투표 기간)와 votingQuorum(의결 정족수)이 0보다 큰지 확인하지만, 정작 이 값들을 변경하는 setter 함수(setVotingPeriod 등)에는 이 검증이 누락되어 있었습니다. 투표 기간이 0이 되면 제안이 무용지물이 되고, 쿼럼이 0이 되면 0표를 받은 제안도 실행될 수 있는 심각한 거버넌스 문제가 발생합니다.

  • 권장 사항: setter 함수에도 > 0 유효성 검사를 추가해야 합니다.
  • 심각도: Medium Risk (Audius의 OpenZeppelin 감사)

93. initialize 함수에서 일부 상태 변수가 설정되지 않음

취약점: 업그레이드 가능한 컨트랙트에서, 생성자 역할을 하는 initialize 함수가 모든 필수 상태 변수를 초기화하지 않았습니다. 초기화되지 않은 변수를 사용하는 함수가 호출되면, 시스템은 예기치 않게 동작하거나 오류를 일으킬 수 있습니다.

  • 권장 사항: initializer 함수에서 모든 필수 변수를 설정해야 합니다. 만약 의도적으로 초기화하지 않는 변수가 있다면, 그 이유를 문서화하고 해당 변수를 사용하는 함수에 안전장치를 추가해야 합니다.
  • 심각도: Medium Risk (Audius의 OpenZeppelin 감사)

94. 만료되거나 일시정지된 옵션을 여전히 거래 가능

취약점: 옵션 컨트랙트가 만료되거나 일시정지되어 더 이상 효력이 없음에도 불구하고, 해당 옵션 토큰이 자유롭게 전송(거래)될 수 있었습니다. 악의적인 보유자는 이 쓸모 없어진 옵션을, 사전 확인을 제대로 하지 않은 거래소나 사용자에게 판매하여 부당 이득을 취할 수 있습니다.

  • 권장 사항: 만약 이것이 의도된 동작이라면, 사용자들에게 위험성을 명확히 문서화해야 합니다. 의도된 동작이 아니라면, 일시정지 또는 만료 시 토큰 전송을 막는 로직을 구현해야 합니다.
  • 심각도: Medium Risk (Primitive의 OpenZeppelin 감사)

95. ERC-20 토큰 전송의 예기치 않은 동작

취약점: 컨트랙트가 토큰을 받을 때, 보낸 수량과 받은 수량이 항상 같을 것이라고 가정했습니다. 하지만 USDT처럼 전송 시 수수료를 부과하는 토큰(fee-on-transfer tokens)의 경우, 실제로 받는 수량은 보낸 수량보다 적습니다. 이 차이를 인지하지 못하면 컨트랙트의 내부 회계가 맞지 않게 되어, 프로토콜이 지급 불능 상태에 빠질 수 있습니다.

  • 권장 사항: 프로토콜에서 사용되는 모든 토큰을 철저히 검증해야 합니다. 또한, 보낸 수량을 믿지 말고, 전송 전후의 컨트랙트 잔액을 직접 확인하여 실제로 받은 수량을 계산하는 것이 더 안전합니다.
  • 심각도: Medium Risk (ACO Protocol의 OpenZeppelin 감사)

96. 부정확한 이벤트 발생

취약점: UniswapWindowUpdate 이벤트가, 관련된 상태 변수들이 업데이트되기 전에 발생했습니다. 이로 인해 이벤트 로그에는 오래된, 부정확한 데이터가 기록되었으며, 이 이벤트를 구독하는 오프체인 서비스들은 잘못된 정보를 받게 됩니다.

  • 권장 사항: 모든 관련 상태 변경이 적용된 후에 이벤트를 발생시켜, 항상 최신 데이터가 로그에 남도록 해야 합니다.
  • 심각도: Medium Risk (Compound Open Price Feed – Uniswap Integration의 OpenZeppelin 감사)

97. 누구나 다른 계정을 대신하여 청산할 수 있음

취약점: liquidateFrom 함수가 public으로 선언되어 있고, 임의의 from 주소를 지정할 수 있었습니다. 이는 아무나 다른 사용자의 포지션을 강제로 청산시킬 수 있음을 의미합니다. 심지어 프로토콜 자체의 AMM 계정을 대신하여 청산을 실행하여, AMM이 가져서는 안 될 포지션을 갖게 하는 등 시스템의 불변성을 깨뜨릴 수도 있었습니다.

  • 권장 사항: liquidateFrom 함수의 가시성을 internal로 제한하여, 외부에서 임의로 호출할 수 없도록 해야 합니다.
  • 심각도: Critical Risk (MCDEX Mai Protocol의 OpenZeppelin 감사)

98. 주문을 취소할 수 없음

취약점: cancelOrder 함수를 호출하면 cancelled 매핑에 취소 상태가 기록되지만, 정작 주문을 검증하는 validateOrder 함수에서는 이 매핑을 전혀 확인하지 않았습니다. 결과적으로 사용자가 주문을 취소하더라도, 해당 주문은 여전히 활성 상태인 것처럼 취급되어 체결될 수 있었습니다.

  • 권장 사항: 주문 검증 로직에 취소된 주문인지 확인하는 절차를 추가해야 합니다.
  • 심각도: Critical Risk (MCDEX Mai Protocol의 OpenZeppelin 감사)

99. 재진입 가능성

취약점: 여러 함수에서 Checks-Effects-Interactions 패턴을 따르지 않고, 상태를 변경(Effects)하기 전에 외부 호출(Interactions)을 수행했습니다. 비록 이 경우에 직접적인 자금 탈취로 이어지지는 않았지만, 재진입 공격을 통해 이벤트 발생 순서나 내용을 조작하여 오프체인 클라이언트에 혼란을 줄 수 있는 위험이 있었습니다.

  • 권장 사항: 항상 "Checks-Effects-Interactions" 패턴을 따르거나, ReentrancyGuard 컨트랙트를 사용하여 함수를 보호해야 합니다.
  • 심각도: Medium Risk (MCDEX Mai Protocol의 OpenZeppelin 감사)

100. 거버넌스 파라미터 변경이 즉시 적용됨

취약점: 관리자(WhitelistAdmin)가 수수료, 증거금 비율 등 민감한 프로토콜 파라미터를 변경하면 아무런 지연 없이 즉시 적용되었습니다. 예를 들어, 유지 증거금 비율을 갑자기 올리면 사용자들이 대응할 시간도 없이 포지션이 청산될 위험에 처하게 됩니다.

  • 권장 사항: 이러한 중요한 변경에는 타임락(time-lock) 메커니즘을 도입해야 합니다. 변경 의사를 공표하고 실제 변경이 적용되기까지 시간적 여유를 줌으로써, 사용자들이 위험에 대비하여 자금을 옮기거나 포지션을 정리할 시간을 벌 수 있습니다.
  • 심각도: Medium Risk (MCDEX Mai Protocol의 OpenZeppelin 감사)

101. 투표가 복제될 수 있음

취약점: 커밋-리빌(commit-reveal) 투표 방식에서, 투표 내용을 숨기기 위해 제출하는 커밋(commitment) 해시값에 투표자의 주소가 포함되지 않았습니다.

  • 공격 시나리오: 공격자는 자금력이 큰 '고래' 투표자의 커밋 값을 그대로 복사하여 자신의 투표로 제출할 수 있습니다. 나중에 고래가 자신의 투표 내용을 공개하면, 공격자도 동일한 값을 공개하여 고래의 투표를 사실상 복제하고 투표의 공정성을 훼손할 수 있습니다.
  • 권장 사항: 커밋 해시를 생성할 때 투표자의 주소(msg.sender)를 포함하여, 각 투표가 고유하도록 만들어야 합니다.
  • 심각도: High Risk (UMA Phase 1의 OpenZeppelin 감사)

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

 

Audit Findings 101

101 Findings from Audits

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 201  (3) 2025.07.12