﻿---
title: "Delegatecall 스토리지 위험"
description: "Delegatecall은 호출자 스토리지를 사용해 다른 계약의 코드를 실행합니다. 스토리지 충돌, 업그레이드 권한, 신뢰할 수 없는 대상이 프록시나 스마트 지갑을 침해하는 방식을 설명합니다."
image: "https://wiki.fcontext.com/og.png"
---

> Documentation Index
> Fetch the complete documentation index at: https://wiki.fcontext.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Delegatecall 스토리지 위험

> 교육 참고용이며 투자 조언이 아닙니다. 투자로 인해 손실이 발생할 수 있습니다.

<a id="answer"></a>

## 직접 답변

`delegatecall`은 호출자 계약의 컨텍스트에서 대상 계약의 코드를 실행합니다. 호출자는 자체 스토리지, 잔액, `address(this)`를 유지하며, `msg.sender`와 `msg.value`는 원래 호출의 값을 그대로 유지합니다.

이 동작은 프록시, 라이브러리, 스마트 지갑 모듈을 가능하게 하지만 위임된 코드에 호출자의 실질적인 권한도 부여합니다. 스토리지 쓰기, 자산 전송, 승인, 외부 호출은 코드를 제공한 대상이 아니라 호출자로서 실행됩니다.

접근 가능한 모든 `delegatecall` 대상을 특권 코드로 취급해야 합니다. 안전성은 대상 선택 규칙, 호환되는 스토리지 레이아웃, 초기화 상태, 업그레이드 제어, 그리고 해당 거래에 실제로 사용되는 정확한 구현에 달려 있습니다.

<a id="mechanism"></a>

## 작동 방식

일반 외부 호출에서는 피호출자가 자체 스토리지를 읽고 씁니다. `delegatecall`에서는 대상의 바이트코드가 호출자의 스토리지를 대상으로 실행됩니다. 즉, `SSTORE` 명령은 호출자에게 속한 슬롯을 변경합니다. 대상 코드의 변수 이름은 런타임에 중요하지 않으며, 계산된 슬롯 위치만 중요합니다.

따라서 다음 네 가지 경계를 감사해야 합니다.

- **대상 제어:** 목적지가 고정되어 있는지, 사용자가 선택하는지, 레지스트리를 통해 결정되는지, 관리자가 변경할 수 있는지 확인합니다.
- **스토리지 호환성:** 모든 구현 버전에서 변수 순서, 타입, 상속, 스토리지 갭, 네임스페이스 슬롯 또는 표준화 슬롯을 비교합니다.
- **초기화 및 인가:** 초기화 함수를 다시 실행할 수 없는지 확인하고, 업그레이드 또는 모듈 관리 함수가 의도된 호출자와 거버넌스 지연을 강제하는지 확인합니다.
- **반환값 처리:** 실패가 상위 호출로 전파되고 반환 데이터가 예상한 타입으로 디코딩되는지 검증합니다. 저수준 호출은 Solidity가 일반적으로 제공하는 계약 타입 검사를 수행하지 않습니다.

ERC-1967은 구현, 비콘, 관리자 주소를 컴파일러의 일반적인 할당 범위 밖에 있는 표준화 슬롯에 배치해 프록시의 스토리지 충돌을 줄입니다. 그러나 특정 구현이 안전하거나 정당한 권한으로 수행된 업그레이드가 무해하다는 사실까지 보장하지는 않습니다.

<a id="example"></a>

## 예시

어떤 지갑이 `owner`를 `slot 0`에 저장한다고 가정해 보겠습니다. 플러그인은 컴파일 시 `counter`를 `slot 0`에 배치했으며, 지갑이 `delegatecall`을 통해 이 플러그인을 호출하면 카운터를 증가시킵니다.

스토리지는 지갑에 속하므로 이 쓰기는 지갑의 `owner` 값을 변경합니다. 변경된 워드가 공격자가 통제하는 주소를 인코딩한다면, 플러그인이 지갑 자산을 보유한 적이 없더라도 이후 인가 검사에서 공격자를 소유자로 인식할 수 있습니다.

성공한 거래 영수증만으로는 의도된 상태 변경과 유해한 상태 변경을 구분할 수 없습니다. 따라서 거래 시뮬레이션에서는 실제 프록시와 구현 주소를 기준으로 스토리지 차이, 자산 및 승인 변경, 발생한 이벤트, 후속 호출을 확인해야 합니다.

<a id="risks"></a>

## 위험

- **임의 대상 실행:** 사용자가 제어하거나 검증이 미흡한 대상은 호출자의 권한으로 악성 코드를 실행할 수 있습니다.
- **스토리지 충돌:** 구현은 소유권, 잔액, 일시 중지 상태, 심지어 다음 구현을 선택하는 슬롯까지 덮어쓸 수 있습니다.
- **안전하지 않은 업그레이드:** 관리자나 거버넌스 절차가 침해되면 사용자가 자산을 예치하거나 승인을 부여한 뒤에 이전에 검토된 코드를 교체할 수 있습니다.
- **초기화 실패:** 초기화되지 않은 프록시나 구현에서는 다른 계정이 특권 역할을 차지하거나 위험한 종속성을 설정할 수 있습니다.
- **오해를 부르는 검사:** 프록시 소스, 현재 구현 또는 인터페이스만 검증하면 비콘, 대기 중인 업그레이드, 모듈 레지스트리 또는 다른 실행 경로를 놓칠 수 있습니다.

서명하기 전에 최근 블록에서 구현을 확인하고, 누가 어느 정도의 지연을 거쳐 이를 변경할 수 있는지 검증해야 합니다. 또한 대상의 검증된 바이트코드와 스토리지 레이아웃을 살펴보고, 전체 calldata를 시뮬레이션하며, 실행 전후의 민감한 스토리지와 토큰 승인을 비교해야 합니다. 스마트 지갑의 경우 모듈이 활성화 및 비활성화되는 방식과 대상을 선택하도록 허용되는 방식도 검토해야 합니다.

<a id="misconceptions"></a>

## 흔한 오해

- **“대상은 호출자의 자산에 손댈 수 없다.”** 위임된 코드는 호출자로서 실행되므로, 호출자에게 해당 능력이 있다면 외부 계약 호출, 자산 전송 또는 승인 생성을 수행할 수 있습니다.
- **“변수 이름이 같으면 충돌을 막을 수 있다.”** EVM은 소스 코드 이름이 아니라 스토리지 슬롯을 사용합니다. 레이아웃 순서, 상속, 타입이 호환되어야 합니다.
- **“프록시 코드가 검증되었으면 시스템도 검증된 것이다.”** 현재 구현, 비콘, 업그레이드 관리자, 초기화 상태, 모듈 권한은 각각 신뢰 경계의 독립적인 구성 요소입니다.

<a id="related"></a>

## 관련 주제

- [암호경제적 보안](/ko/crypto/crypto-economic-security/)
- [비공개 거래 RPC](/ko/crypto/private-transaction-rpc/)
- [프록시 계약](/ko/crypto/proxy-contract/)
- [스마트 계약](/ko/crypto/smart-contract/)
- [거래 시뮬레이션](/ko/crypto/transaction-simulation/)

<a id="sources"></a>

## 출처

- [Introduction to Smart Contracts](https://docs.soliditylang.org/en/latest/introduction-to-smart-contracts.html) - Solidity Documentation (확인일: 2026-08-20)
- [Units and Globally Available Variables](https://docs.soliditylang.org/en/latest/units-and-global-variables.html) - Solidity Documentation (확인일: 2026-08-20)
- [ERC-1967: Proxy Storage Slots](https://eips.ethereum.org/EIPS/eip-1967) - Ethereum Improvement Proposals (확인일: 2026-08-20)

Source: https://wiki.fcontext.com/ko/crypto/delegatecall-storage-risk/index.mdx
