Back to Blog

LiNEAR セキュリティ監査レポート

Code Auditing
April 8, 2022
13 min read

レポートマニフェスト

項目 説明
クライアント LiNEAR Protocol
対象 LiNEAR

バージョン履歴

バージョン 日付 説明
1.0 2022年4月1日 初版

1. はじめに

1.1 対象コントラクトについて

情報 説明
タイプ スマートコントラクト
言語 Rust
アプローチ 半自動および手動検証

監査されたリポジトリには、LiNEAR^1が含まれています。

監査プロセスは反復的です。具体的には、発見された問題を修正するコミットを監査します。新しい問題がある場合は、このプロセスを続行します。監査中のコミットSHA値は以下の通りです。当社の監査レポートは、初期バージョン(バージョン1)および、監査レポートの問題を修正するための新しいコード(以下のバージョン)に責任を負います。

1.2 セキュリティモデル

リスクを評価するために、業界と学術界で広く採用されている標準または提案に従います。これには、OWASPリスク評価方法論^2およびCommon Weakness Enumeration^3が含まれます。リスクの全体的な重大度は、発生可能性影響によって決定されます。具体的には、発生可能性は、特定の脆弱性が攻撃者によって発見され、悪用される可能性を推定するために使用され、影響は、攻撃が成功した場合の結果を測定するために使用されます。

このレポートでは、発生可能性と影響の両方を2つの評価、つまりに分類し、それらの組み合わせを表1.1に示します。

したがって、このレポートで測定された重大度は、の3つのカテゴリに分類されます。網羅性のために、リスクを適切に判断できない状況をカバーするために、未定も使用されます。

さらに、発見された問題のステータスは、次の4つのカテゴリのいずれかに分類されます。

  • 未定 まだ応答がありません。

  • 確認済み 問題はクライアントによって受信されましたが、まだ確認されていません。

  • 確認済み 問題はクライアントによって認識されましたが、まだ修正されていません。

  • 修正済み 問題はクライアントによって確認され、修正されました。

2. 発見事項

合計で、スマートコントラクトで4つの潜在的な問題が見つかりました。また、4つの推奨事項があります。

  • 高リスク: 0

  • 中リスク: 2

  • 低リスク: 2

  • 推奨事項: 4

ID 重大度 説明 カテゴリ ステータス
1 精度損失 ソフトウェアセキュリティ 修正済み
2 ユーザーの利用可能残高が一時的にロックされる可能性があります DeFiセキュリティ 確認済み
3 受給者への無制限の報酬配布 DeFiセキュリティ 修正済み
4 ユーザーのアンステークリクエストが時間通りに満たされない可能性があります DeFiセキュリティ 修正済み
7 - 受給者が無制限のため、epoch_update_rewards関数が機能しない可能性があります 推奨事項 修正済み
8 - 冗長なコード 推奨事項 確認済み
6 - ft_transfer_call関数でのprepaid_gasのチェック漏れ 推奨事項 修正済み
9 - 中央集権化設計のリスク 推奨事項 確認済み

詳細は以下のセクションで提供します。

2.1 ソフトウェアセキュリティ

2.1.1 潜在的な問題1:精度損失

情報 説明
ステータス バージョン2で修正済み
由来 バージョン1

説明 関数internal_calculate_distributionの125行目では、変数reward_per_sessionを計算する際に、乗算の前に除算が実行されます。

fn internal_calculate_distribution(
        &self,
        farm: &Farm,
        total_staked: Balance,
    ) -> Option<RewardDistribution> {
        if farm.start_date > env::block_timestamp() {
            // Farm hasn't started.
            return None;
        }
        let mut distribution = farm.last_distribution.clone();
        if distribution.undistributed == 0 {
            // Farm has ended.
            return Some(distribution);
        }
        distribution.reward_round = (env::block_timestamp() - farm.start_date) / SESSION_INTERVAL;
        let reward_per_session =
            farm.amount / (farm.end_date - farm.start_date) as u128 * SESSION_INTERVAL as u128;

リスト 2.1: contracts/linear/src/farm.rs

影響 Rust言語では、整数除算は切り捨てられます。この場合、整数に対して乗算の前に除算を行うと、精度が失われる可能性があります。

提案I 乗算を先に行い、次に除算を行うようにこの計算を変更してください。

提案II ファームが追加されるときにreward_per_sessionの値を事前に計算してください。これは、ファームの所有者が停止しない限り、farm.amount、farm.end_date、farm.start_dateはファーミングプロセス中に変更されないためです。

2.2 DeFiセキュリティ

2.2.1 潜在的な問題2:ユーザーの利用可能残高が一時的にロックされる可能性があります

情報 説明
ステータス 確認済み
由来 バージョン1

説明 ユーザーが預けたNEARは、直接ユーザーのアンステーク残高に追加されます。したがって、ユーザーがunstake/unstake_all関数を呼び出した場合、その額の利用可能NEARは次の0から8エポックの間ロックされます。

pub(crate) fn internal_deposit(&mut self, amount: Balance) {
		let account_id = env::predecessor_account_id();
		let mut account = self.internal_get_account(&account_id);
		account.unstaked += amount;
		self.internal_save_account(&account_id, &account);
  
		Event::Deposit {
			account_id: &account_id,
			amount: &U128(amount),
			new_unstaked_balance: &U128(account.unstaked),
		}
		.emit();
	} 

リスト 2.2: contracts/linear/src/internal.rs

影響 ユーザーがこのコントラクトのワークフローを認識せず、このコントラクトと直接やり取りした場合、ユーザーの利用可能残高が一時的にロックされる可能性があります。

提案I アカウント構造体に別の属性(例:available_amount)を追加して、利用可能なNEARを維持してください。

プロジェクトからのフィードバック これは設計どおりであり、基本的にステーキングプールの元のインターフェースと設計に従っています。潜在的な問題を解決するために、「unstaked」とは区別するために「unstaking」という別のフィールドを追加し、このアカウントの次のアンステークプロセスを開始する前に「unstaking」を「unstaked」に移動させることができます。しかし、現時点では、ステーキングプールとのワークフローの一貫性を保つために、変更は行いたくありません。回避策として、ユーザーがフロントエンドからアンステークする場合、UIはアカウントに「unstaked」額がある場合はまず引き出すようにユーザーに通知します。

2.2.2 潜在的な問題3:受給者への無制限の報酬配布

情報 説明
ステータス バージョン2で修正済み
由来 バージョン1

説明 このコントラクトは、新しい受給者を設定する際に、assert_valid関数で全ての受給者の合計ウェイトをチェックしません。

pub fn set_beneficiary(&mut self, account_id: AccountId, fraction: Fraction) {
		self.assert_owner();
		fraction.assert_valid();
		self.beneficiaries.insert(&account_id, &fraction);
	} 

リスト 2.3: contracts/linear/src/owner.rs

pub fn assert_valid(&self) {
		require!(self.denominator != 0, ERR_FRACTION_BAD_DENOMINATOR);
		require!(
			self.numerator <= self.denominator,
			ERR_FRACTION_BAD_NUMERATOR
		);
	} 

リスト 2.4: contracts/linear/src/utils.rs

影響 受給者の合計ウェイトが100%を超えると、受給者向けにミントされたLiNEARは、action epoch_update_rewardsの実行後にLiNEARの価格を低下させる可能性があります。

提案I 受給者への総報酬を制限する合理的な閾値を導入してください。

2.2.3 潜在的な問題4:ユーザーのアンステークリクエストが時間通りに満たされない可能性があります

情報 説明
ステータス バージョン2で修正済み
由来 バージョン1

説明 get_num_epoch_to_unstake関数の戻り値であるエポック数は、一部のコーナーケースでは倍増する必要があります。例えば、保留中のステータスではないバリデーターのステーキングプールに合計NEARが十分にステークされていない場合、ユーザーは4エポック後に要求したアンステークされたNEARをすべて引き出すことができません。

pub fn get_num_epoch_to_unstake(&self, _amount: u128) -> EpochHeight {
		// the num of epoches can be doubled or trippled if not enough stake is available
		NUM_EPOCHS_TO_UNLOCK
	} 

リスト 2.5: contracts/linear/src/validator_pool.rs

影響 ユーザーのアンステークリクエストは、常に時間通りに満たされない可能性があります。

提案I バリデーターのステーキングプールのステータスに基づいて、ユーザーのアンステーク待機時間を予測する戦略を実装してください。

2.3 追加の推奨事項

2.3.1 受給者が無制限のため、epoch_update_rewards関数が機能しない可能性があります

情報 説明
ステータス バージョン2で修正済み
由来 バージョン1

説明 受給者の数が無制限です。この場合、関数epoch_update_rewardsが関数internal_distribute_staking_rewardsを呼び出すと、ガス不足になる可能性があります。

pub fn epoch_update_rewards(&mut self, validator_id: AccountId) {
	let min_gas = GAS_EPOCH_UPDATE_REWARDS + GAS_EXT_GET_BALANCE + GAS_CB_VALIDATOR_GET_BALANCE;
	require!(
		env::prepaid_gas() >= min_gas,
		format!("{}. require at least {:?}", ERR_NO_ENOUGH_GAS, min_gas)
	);

	let validator = self
		.validator_pool
		.get_validator(&validator_id)
		.expect(ERR_VALIDATOR_NOT_EXIST);

	if validator.staked_amount == 0 && validator.unstaked_amount == 0 {
		return;
	}

	validator
		.refresh_total_balance()
		.then(ext_self_action_cb::validator_get_balance_callback(
			validator.account_id,
			env::current_account_id(),
			NO_DEPOSIT,
			GAS_CB_VALIDATOR_GET_BALANCE,
		));
}

リスト 2.6: contracts/linear/src/epoch_actions.rs

/// When there are rewards, a part of them will be
	/// given to executor, manager or treasury by minting new LiNEAR tokens.
	pub(crate) fn internal_distribute_staking_rewards(&mut self, rewards: Balance) {
		let hashmap: HashMap<AccountId, Fraction> = self.internal_get_beneficiaries();
		for (account_id, fraction) in hashmap.iter() {
			let reward_near_amount: Balance = fraction.multiply(rewards);
			// mint extra LiNEAR for him
			self.internal_mint_beneficiary_rewards(&account_id, reward_near_amount);
		}
	} 

リスト 2.7: contract/src/internal.rs

影響 受給者が多すぎる場合、ガスが限られているため、epoch_update_rewards関数が機能しない可能性があります。

提案I 受給者数を制限する合理的な閾値を導入することをお勧めします。

2.3.2 冗長なコード

情報 説明
ステータス 確認済み
由来 バージョン1

説明 関数storage_depositがこのパラメータに対してロジックを実装していないため、パラメータregistration_onlyは冗長です。

fn storage_deposit(
		&mut self,
		account_id: Option<AccountId>,
		registration_only: Option<bool>,
	) -> StorageBalance {
		let amount: Balance = env::attached_deposit();
		let account_id = account_id.unwrap_or_else(env::predecessor_account_id);
		if let Some(account) = self.accounts.get(&account_id) {
			log!("The account is already registered, refunding the deposit");
			if amount > 0 {
				Promise::new(env::predecessor_account_id()).transfer(amount);
			}
		} else {
			let min_balance = self.storage_balance_bounds().min.0;
			if amount < min_balance {
				env::panic_str("The attached deposit is less than the minimum storage balance");
			}
  
			self.internal_register_account(&account_id);
			let refund = amount - min_balance;
			if refund > 0 {
				Promise::new(env::predecessor_account_id()).transfer(refund);
			}
		}
		self.internal_storage_balance_of(&account_id).unwrap()
	} 

リスト 2.8: contracts/linear/src/fungible_token/storage.rs

提案I 関数storage_depositからこの未使用のパラメータを削除することをお勧めします。

プロジェクトからのフィードバック その通りです。near-contract-standardsクレートの標準FT実装でも同様です。標準のstorage_deposit(account_id, registration_only)インターフェースとの一貫性を保つために、未使用のregistration_onlyパラメータを保持します。

2.3.3 ft_transfer_call関数でのprepaid_gasのチェック漏れ

情報 説明
ステータス バージョン2で修正済み
由来 バージョン1

説明 ft_on_transferおよびft_resolve_transferのターゲット関数で十分であることを保証するために、prepaid_gasをチェックする必要があります。

#[payable]
	fn ft_transfer_call(
		&mut self,
		receiver_id: AccountId,
		amount: U128,
		memo: Option<String>,
		msg: String,
	) -> PromiseOrValue<U128> {
		assert_one_yocto();
		let sender_id = env::predecessor_account_id();
		let amount = amount.into();
		self.internal_ft_transfer(&sender_id, &receiver_id, amount, memo);
		// Initiating receiver's call and the callback
		ext_fungible_token_receiver::ft_on_transfer(
			sender_id.clone(),
			amount.into(),
			msg,
			receiver_id.clone(),
			NO_DEPOSIT,
			env::prepaid_gas() - GAS_FOR_FT_TRANSFER_CALL,
		)
		.then(ext_ft_self::ft_resolve_transfer(
			sender_id,
			receiver_id,
			amount.into(),
			env::current_account_id(),
			NO_DEPOSIT,
			GAS_FOR_RESOLVE_TRANSFER,
		))
		.into()
	}
 

リスト 2.9: contracts/linear/src/fungible_token/core.rs

提案I prepaid_gasをチェックしてください。

2.3.4 中央集権化設計のリスク

情報 説明
ステータス 確認済み
由来 バージョン1

説明 このプロジェクトには、潜在的な中央集権化の問題があります。

提案I コントラクトに、マルチシグネチャやDAOなどの分散化設計を導入することをお勧めします。

プロジェクトからのフィードバックI はい。これはgithub.com/linear-protocol/LiNEAR/issues/60で言及されている計画です。

提案II プロジェクトオーナーは、OWNER_ROLE/MANAGERS_ROLEの秘密鍵のセキュリティを確保し、単一障害点のリスクを軽減するためにマルチシグネチャスキームを使用する必要があります。

プロジェクトからのフィードバックII はい。単一障害点のリスクを軽減するためのセキュリティポリシーに取り組んできました。

3. 通知と注意事項

3.1 免責事項

この監査レポートは、投資アドバイスや個人的な推奨事項を構成するものではありません。トークン、トークンセール、またはその他の製品、サービス、またはその他の資産の潜在的な経済性を考慮しておらず、考慮されたものとして解釈されるべきではありません。いかなるエンティティも、トークン、製品、サービス、またはその他の資産の売買の決定を目的とするなど、いかなる方法でもこのレポートに依存すべきではありません。

この監査レポートは、特定のプロジェクトまたはチームの承認ではなく、レポートは特定のプロジェクトのセキュリティを保証するものではありません。この監査は、全てのセキュリティ問題を検出する保証を与えるものではありません。つまり、評価結果は、さらにセキュリティ問題が見つからないことを保証するものではありません。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
Newsletter - April 2026
Security Insights

Newsletter - April 2026

In April 2026, the DeFi ecosystem experienced three major security incidents. KelpDAO lost ~$290M due to an insecure 1-of-1 DVN bridge configuration exploited via RPC infrastructure compromise, Drift Protocol suffered ~$285M from a multisig governance takeover leveraging Solana's durable nonce mechanism, and Rhea Finance incurred ~$18.4M following a business logic flaw in its margin-trading module that allowed circular swap path manipulatio

~$7.04M Lost: GiddyDefi, Volo Vault & More | BlockSec Weekly
Security Insights

~$7.04M Lost: GiddyDefi, Volo Vault & More | BlockSec Weekly

This BlockSec weekly security report covers eight attack incidents detected between April 20 and April 26, 2026, across Ethereum, Avalanche, Sui, Base, HyperLiquid, and MegaETH, with total estimated losses of approximately $7.04M. The highlighted incident is the $1.3M GiddyDefi exploit, where the attacker did not break any cryptography or use a flash loan but simply replayed an existing on-chain EIP-712 signature with the unsigned `aggregator` and `fromToken` fields swapped out for a malicious contract, demonstrating how partial signature coverage turns any historical signature into a generic permit. Other incidents include a $3.5M Volo Vault operator key compromise on Sui, a $1.5M Purrlend privileged-role takeover, a $413K SingularityFinance oracle misconfiguration, a $142.7K Scallop cross-pool index injection, a $72.35K Kipseli Router decimal mismatch, a $50.7K REVLoans (Juicebox) accounting pollution, and a $64K Custom Rebalancer arbitrary-call exploit.

Weekly Web3 Security Incident Roundup | Apr 13 – Apr 19, 2026
Security Insights

Weekly Web3 Security Incident Roundup | Apr 13 – Apr 19, 2026

This BlockSec weekly security report covers four attack incidents detected between April 13 and April 19, 2026, across multiple chains such as Ethereum, Unichain, Arbitrum, and NEAR, with total estimated losses of approximately $310M. The highlighted incident is the $290M KelpDAO rsETH bridge exploit, where an attacker poisoned the RPC infrastructure of the sole LayerZero DVN to fabricate a cross-chain message, triggering a cascading WETH freeze across five chains and an Arbitrum Security Council forced state transition that raises questions about the actual trust boundaries of decentralized systems. Other incidents include a $242K MMR proof forgery on Hyperbridge, a $1.5M signed integer abuse on Dango, and an $18.4M circular swap path exploit on Rhea Finance's Burrowland protocol.

Best Security Auditor for Web3

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

BlockSec Audit