Prepared by:
HALBORN
Last Updated 04/30/2025
Date of Engagement: January 14th, 2025 - February 14th, 2025
100% of all REPORTED Findings have been addressed
All findings
7
Critical
0
High
0
Medium
2
Low
3
Informational
2
Wayru
engaged Halborn
to conduct a security assessment on their NfNode Rewards Solana program beginning on January 14th, 2025, and ending on January 16th, 2025. The security assessment was scoped to the Solana Program provided in rewards-system-program GitHub repository. Commit hashes and further details can be found in the Scope section of this report.
The NfNode Rewards Program enables users to claim rewards based on their NfNode operation and ownership. It leverages the Anchor framework to streamline the development of Solana programs. It allows administrators to establish a reward system, fund it with tokens, and manage the reward claiming process. Users, who are NfNode owners or operators, can claim rewards once per day. Each claim requires a partial signature from an administrator, enhancing security. The user claiming the reward is responsible for the transaction fees.
The Wayru team
provided an updated version of the NfNode Rewards programa which introduces a new feature that requires users to make a deposit when creating a new NfNode entry. Depending on the NfNode type, the deposit is required at the time of entry creation. For BYOD and WayruHotspot types, the deposit must be made along with the creation of the NfNode entry. For the DON type, no deposit is needed for the owner to claim rewards; however, the deposit is required for the manufacturer or host to be able to claim rewards. Additionally, users must wait a 30-day cooldown period before they can withdraw the deposited amount.
Halborn
was provided 3 days for the engagement and assigned one full-time security engineer to review the security of the Solana Programs in scope. The engineer is a blockchain and smart contract security expert with advanced smart contract hacking skills, and deep knowledge of multiple blockchain protocols. This program allows administrators to establish a reward system, fund it with tokens, and manage the reward claiming process. Users, who are NfNode owners or operators, can claim rewards once per day.
The purpose of the assessment is to:
Identify potential security issues within the Solana Programs.
Ensure that smart contract functionality operates as intended.
In summary, Halborn
identified some improvements to reduce the likelihood and impact of risks, which were completely addressed by the Wayru team
:
Implement a validation to ensure that the Initialize instruction can only be executed by a known and trusted address, such as the program upgrade authority.
Add a "owner" field in nfnode_entry to hold the user's address who initializes. Add a check in in update_nfnode and owner_claim_rewards to ensure the user who is signing is the owner of the provided nfnode_entry. Also, add a validation in init_nfnode, update_nfnode and owner_claim_rewardsto ensure the user who is signing is the authority of the user_nft_token_account provided.
Implementing a two-step authority transfer functionality and add a validation to ensure the new authority candidate is not the current admin.
Add a check to ensure the reward amount and fund amount is strictly greater than zero.
Add validations to Verify that the mint's total supply is exactly 1 and its decimal is 0.
Halborn performed a combination of a manual review of the source code and automated security testing to balance efficiency, timeliness, practicality, and accuracy in regard to the scope of the program assessment. While manual testing is recommended to uncover flaws in business logic, processes, and implementation; automated testing techniques help enhance coverage of programs and can quickly identify items that do not follow security best practices.
The following phases and associated tools were used throughout the term of the assessment:
Research into the architecture, purpose, and use of the platform.
Manual program source code review to identify business logic issues.
Mapping out possible attack vectors
Thorough assessment of safety and usage of critical Rust variables and functions in scope that could lead to arithmetic vulnerabilities.
Scanning dependencies for known vulnerabilities (`cargo audit`).
Local runtime testing (`solana-test-framework`)
EXPLOITABILITY METRIC () | METRIC VALUE | NUMERICAL VALUE |
---|---|---|
Attack Origin (AO) | Arbitrary (AO:A) Specific (AO:S) | 1 0.2 |
Attack Cost (AC) | Low (AC:L) Medium (AC:M) High (AC:H) | 1 0.67 0.33 |
Attack Complexity (AX) | Low (AX:L) Medium (AX:M) High (AX:H) | 1 0.67 0.33 |
IMPACT METRIC () | METRIC VALUE | NUMERICAL VALUE |
---|---|---|
Confidentiality (C) | None (I:N) Low (I:L) Medium (I:M) High (I:H) Critical (I:C) | 0 0.25 0.5 0.75 1 |
Integrity (I) | None (I:N) Low (I:L) Medium (I:M) High (I:H) Critical (I:C) | 0 0.25 0.5 0.75 1 |
Availability (A) | None (A:N) Low (A:L) Medium (A:M) High (A:H) Critical (A:C) | 0 0.25 0.5 0.75 1 |
Deposit (D) | None (D:N) Low (D:L) Medium (D:M) High (D:H) Critical (D:C) | 0 0.25 0.5 0.75 1 |
Yield (Y) | None (Y:N) Low (Y:L) Medium (Y:M) High (Y:H) Critical (Y:C) | 0 0.25 0.5 0.75 1 |
SEVERITY COEFFICIENT () | COEFFICIENT VALUE | NUMERICAL VALUE |
---|---|---|
Reversibility () | None (R:N) Partial (R:P) Full (R:F) | 1 0.5 0.25 |
Scope () | Changed (S:C) Unchanged (S:U) | 1.25 1 |
Severity | Score Value Range |
---|---|
Critical | 9 - 10 |
High | 7 - 8.9 |
Medium | 4.5 - 6.9 |
Low | 2 - 4.4 |
Informational | 0 - 1.9 |
Critical
0
High
0
Medium
2
Low
3
Informational
2
Security analysis | Risk level | Remediation Date |
---|---|---|
Program initializer can be front-run | Medium | Solved - 01/20/2025 |
Multiple vulnerabilities in reward claiming and NfNode initialization and update process | Medium | Solved - 01/21/2025 |
New admin check missing | Low | Solved - 01/21/2025 |
Zero amount check missing | Low | Solved - 01/21/2025 |
Insufficient validation of NFT mint properties in nfnode entry initialization | Low | Solved - 02/04/2025 |
Insufficient validation of mint authority at system initialization | Informational | Solved - 02/17/2025 |
Paused status check missing in pause instructions | Informational | Solved - 01/21/2025 |
//
The current implementation of the init_system
instruction lacks proper restrictions to ensure that it is signed by a known and trusted authority, such as the program's update authority. This absence of validation allows an attacker to execute the initialization process prematurely, potentially enabling an attacker to configure the program with malicious or unauthorized accounts under their control.
The lack of safeguards during the system initialization phase poses significant risks, particularly given the critical role of the admin's signature in core operations such as initializing and updating nfnode_entry
entries, as well as claiming rewards. Without proper validation, this vulnerability could result in severe consequences, including enabling malicious administrators to perform unauthorized actions, as outlined in related attacks described in HAL-08, without any form of restriction.
init_system.rs:
pub fn initialize_system(ctx: Context<InitializeSystem>) -> Result<()> {
let admin_account = &mut ctx.accounts.admin_account;
admin_account.admin_pubkey = ctx.accounts.user.key();
admin_account.paused = false;
Ok(())
}
#[derive(Accounts)]
pub struct InitializeSystem<'info> {
#[account(mut)]
pub user: Signer<'info>,
#[account(
init,
payer = user,
space = 8 + std::mem::size_of::<AdminAccount>(),
seeds = [b"admin_account"],
bump
)]
pub admin_account: Account<'info, AdminAccount>,
pub system_program: Program<'info, System>,
1. Call the program's initializer as low-privileged (any) user, in this case, Bob.
To address this issue, it is recommended to implement a validation to ensure that the Initialize
instruction can only be executed by a known and trusted address, such as the program upgrade authority.
The following code snippet shows an example of this measure to be implemented in the init_system
instruction:
pub admin: Signer<'info>,
#[account(constraint = program.programdata_address()? == Some(program_data.key()))]
pub program: Program<'info, NfnodeRewards>,
#[account(constraint = program_data.upgrade_authority_address == Some(user.key()))]
pub program_data: Account<'info, ProgramData>,
SOLVED: The Wayru team solved this issue by implementing the validation suggested, ensuring only the upgrade authority can initialize the system.
//
A user holding an NFT that was previously minted can initialize a new NfNode
entry using the init_nfnode
instruction. To do so, the user must provide several accounts, including the nft_mint_address
, user_nft_token_account
, host
, manufacturer
, among others. This instruction initializes an nfnode_entry
, which is a Program Derived Address (PDA) composed of a fixed seed and a variable component, specifically the nft_mint_address
.
The owner of this nfnode_entry
, who created it, will be able to claim their corresponding rewards daily using the owner_claim_rewards
instruction. Similarly, the host
or manufacturer
assigned by the owner during the creation of the nfnode_entry
can claim their corresponding rewards daily using the other_claim_rewards
instruction. Furthermore, the owner of the nfnode_entry
can change the address of the host
at any time.
However, the init_nfnode
, update_nfnode
, and owner_claim_rewards
instructions do not verify that the signing user is the authority over the user_nft_token_account
, nor do the latter two instructions verify that the signer is the actual owner who created the nfnode_entry
.
This lack of verification results in the following vulnerabilities:
Unauthorized Initialization:
Any user who knows the user_nft_token_account
address of the legitimate NFT owner can initialize an nfnode_entry
by providing that user_nft_token_account
and assigning its own address as the host
. This would allow the attacker to subsequently claim rewards both as the host
and as the owner
, while the legitimate NFT owner would no longer be able to create an nfnode_entry
.
Unauthorized Updates:
Any user can update the nfnode_entry
of a legitimate user using the update_nfnode
instruction by providing the user_nft_token_account
address of the legitimate user who created the nfnode_entry
and assigning its own address as the new host
. This would allow the attacker to subsequently claim rewards legitimately using the other_claim_rewards
instruction.
Unauthorized Reward Claims:
Any user can claim daily rewards before the legitimate owner of the nfnode_entry
by providing the user_nft_token_account
address of the legitimate user who created the nfnode_entry
. This would prevent the rightful owner from claiming their rewards for that day.
The mentioned operations require partial approval from the admin, as their signature is necessary. However, if the admin does not have an external system outside the program to verify:
That the signer is legitimately the owner of the NFT in the provided user_nft_token_account
.
That the signer is the original creator of the nfnode_entry
.
The admin will lack the ability to verify which signers are legitimate, potentially resulting in the approval of transactions that introduce critical vulnerabilities. These include:
Reward theft from a legitimate nfnode_entry
Unauthorized updates to an existing nfnode_entry
Creation of fraudulent nfnode_entry
entries using other user's nft token account. Consequently, rightful NFT owners may be prevented from initializing their entries, compromising the integrity and security of the system.
init_nfnode.rs:
pub struct InitializeNfNode<'info> {
#[account(mut)]
pub user_admin: Signer<'info>,
#[account(mut)]
pub user: Signer<'info>,
///CHECK: only read account
pub host: AccountInfo<'info>,
///CHECK: only read account
pub manufacturer: AccountInfo<'info>,
///CHECK: only read account
pub nft_mint_address: InterfaceAccount<'info, Mint2022>,
/// CHECK: used to check nft ownership
pub user_nft_token_account: AccountInfo<'info>,
#[account(
init,
payer = user,
space = 8 + std::mem::size_of::<NfNodeEntry>(),
seeds = [b"nfnode_entry", nft_mint_address.key().as_ref()],
bump
)]
pub nfnode_entry: Account<'info, NfNodeEntry>,
update_nfnode.rs:
pub struct UpdateNfNode<'info> {
#[account(mut)]
pub user_admin: Signer<'info>,
#[account(mut)]
pub user: Signer<'info>, //TODO: no parece necesario
///CHECK: only read account
pub host: AccountInfo<'info>,
///CHECK: only read account
pub nft_mint_address: InterfaceAccount<'info, Mint2022>,
/// CHECK: used to check nft ownership
pub user_nft_token_account: AccountInfo<'info>,
owner_claim_rewards.rs:
pub struct OwnerClaimRewards<'info> {
/// CHECK:
#[account(mut)]
pub user_admin: Signer<'info>,
#[account(mut)]
pub user: Signer<'info>,
/// CHECK:
pub nft_mint_address: InterfaceAccount<'info, Mint2022>,
#[account(
init_if_needed,
payer = user,
space = 8 + std::mem::size_of::<RewardEntry>(),
seeds = [b"reward_entry", user.key().as_ref(), nft_mint_address.key().as_ref()],
bump
)]
pub reward_entry: Account<'info, RewardEntry>,
#[account(
mut,
seeds = [b"nfnode_entry", nft_mint_address.key().as_ref()],
bump
)]
pub nfnode_entry: Box<Account<'info, NfNodeEntry>>,
pub token_mint: Account<'info, Mint>,
/// CHECK:
#[account(mut, seeds = [b"token_storage"], bump)]
pub token_storage_authority: AccountInfo<'info>,
#[account(
mut,
associated_token::mint = token_mint,
associated_token::authority = token_storage_authority,
)]
pub token_storage_account: Box<Account<'info, TokenAccount>>,
#[account(
init_if_needed,
payer = user,
associated_token::mint = token_mint,
associated_token::authority = user
)]
pub user_token_account: Box<Account<'info, TokenAccount>>,
/// CHECK: used to check nft ownership
pub user_nft_token_account: AccountInfo<'info>,
Steps to reproduce the attacks:
Unauthorized Initialization:
Tom has a nft
Bob, knowing Tom's nft token account, init a nfNode entry providing Tom's token account with the nft
The Token Storage is funded
Bob claims rewards since is the owner of the nfNode entry that initialized previously
Unauthorized Updates:
A legitimate user who has a nft initialize the nfNode entry setting the corresponding host and manufacturer
The Token Storage is funded
A malicious user (Alice) updated the nfNode entry providing the user's nft token account and setting its own address as host
Alice claims rewards as legitimate host ( other_claim_rewards)
Unauthorized Reward Claims:
A legitimate user who has a nft initialize the nfNode entry setting the corresponding host and manufacturer
The Token Storage is funded
A malicious user (Alice) claim rewards providing the user's nft token account ( owner_claim_rewards).
To address this issue, it is recommended to implement the following measures:
Add an "owner" field in nfnode_entry to hold the user's address who initializes.
Add a validation in update_nfnode
and owner_claim_rewards
to ensure the user who is signing is the owner of the provided nfnode_entry.
Add a validation in init_nfnode
, update_nfnode
and owner_claim_rewards
to ensure the user who is signing is the authority of the user_nft_token_account provided.
SOLVED: The Wayru team solved this issue by implementing validation mechanisms in the init_nfnode
, update_nfnode
, and owner_claim_rewards
instructions. These validations ensure that the user_nft_token_account provided corresponds to the signer's Associated Token Account (ATA) for the specified NFT mint of the nfnode. Combined with the existing validation that checks the ATA's token balance is greater than zero, these measures ensure that only the current holder of the NFT can execute these instructions, alongside the administrator's partial signature.
//
The update_admin
instruction allows the current system administrator to transfer ownership and designate a new admin. This admin role is critical within this Solana program, as its partial signature is required for operations such as initializing and updating the NF node and claiming rewards.
However, the instruction does not validate the public key provided as the new admin parameter. As a result, the following scenarios could occur:
Reassigning the Admin to the Current Admin
The current admin could mistakenly assign the role to itself. While this does not disrupt the program’s functionality, it incurs an unnecessary transaction cost without achieving any effect.
Assigning an Invalid Address
If an invalid or non-existent address is assigned as the new admin, it would render most subsequent instructions inoperable due to the inability to obtain the required admin signature. This effectively creates a Denial-of-Service (DoS) scenario for critical operations dependent on the admin’s authorization.
Assigning an Incorrect or Malicious Address
If the admin role is mistakenly or maliciously transferred to an unintended address, such as a malicious user’s account, this entity could exploit their new administrative privileges to compromise the program’s integrity.
update_admin.rs:
pub fn update_admin(ctx: Context<UpdateAdmin>, new_admin_pubkey: Pubkey) -> Result<()> {
let admin_account = &mut ctx.accounts.admin_account;
require!(
ctx.accounts.user.key() == admin_account.admin_pubkey,
RewardError::UnauthorizedAdmin
);
admin_account.admin_pubkey = new_admin_pubkey;
Ok(())
While this instruction can only be executed by the current admin, assigning an invalid or incorrect address results in an irreversible outcome. In scenarios where the admin role is transferred to an invalid or malicious account, critical operations requiring admin authorization would be permanently blocked or exploited.
To address this issue, consider implementing a two-step authority transfer functionality. This can be achieved by adding a function that designates a new authority candidate, ensuring that this candidate is not the zero address. Authority is only transferred once the new authority accepts it by sending a signed transaction.
It is also recommended to add a validation to ensure the new authority candidate is not the current admin.
SOLVED: The Wayru team solved this issue by adding two-step authority transfer process implementation ensuring the new candidate is not the current admin or the zero address.
//
The owner_claim_rewards
and others_claim_rewards
instructions allow the owner and host/manufacturer , respectively, to claim rewards by providing a reward amount as a parameter. The specified amount is transferred to the owner or host/manufacturer accordingly.
However, the program does not validate the provided amount in any of these instructions, leading into potential zero amount claims. The lack of validation allows users to provide a reward amount of zero when claiming rewards. If this occurs, the user calling the instruction will receive no rewards but the fields that track the last claim timestamp will be updated as if a valid claim occurred, preventing further reward claims during that day. This effectively causes the user to lose the opportunity to claim their rightful rewards for that day, as the state reflects a completed claim despite no rewards being distributed.
Although both operations require approval from the admin, as their partial signature is necessary, it is important to add validations to prevent the aforementioned scenario as a best practice.
other_claim_rewards.rs:
reward_entry.last_claimed_nonce = nonce;
reward_entry.last_claimed_timestamp = current_timestamp;
//verify if host or manufacturer
if ctx.accounts.user.key() == nfnode_entry.host {
nfnode_entry.host_last_claimed_timestamp = current_timestamp;
} else if ctx.accounts.user.key() == nfnode_entry.manufacturer {
nfnode_entry.manufacturer_last_claimed_timestamp = current_timestamp;
} else {
return Err(RewardError::UnauthorizedUser.into());
}
nfnode_entry.total_rewards_claimed += reward_amount;
let authority_bump = ctx.bumps.token_storage_authority;
let authority_seeds = &[&b"token_storage"[..], &[authority_bump]];
let signer_seeds = &[&authority_seeds[..]];
token::transfer(
CpiContext::new_with_signer(
ctx.accounts.token_program.to_account_info(),
Transfer {
from: ctx.accounts.token_storage_account.to_account_info(),
to: ctx.accounts.user_token_account.to_account_info(),
authority: ctx.accounts.token_storage_authority.to_account_info(),
},
signer_seeds
),
reward_amount
)?;
Similarly, the fund_token_storage
instruction facilitates the funding of the token storage account by allowing users to provide a funding amount as a parameter. However the absence of validation for the provided funding amount allows users to perform funding operations with an amount of zero resulting in a zero-value transfer takes place, resulting in a redundant transaction with no functional impact.
lib.rs:
pub fn fund_token_storage(ctx: Context<FundTokenStorage>, amount: u64) -> Result<()> {
token::transfer(ctx.accounts.transfer_to_token_storage(), amount)?;
Ok(())
}
To address this issue, it is recommended to implement validations to ensure the reward amount in owner_claim_rewards
and others_claim_rewards
instructions is strictly greater than zero. Similarly, validate the funding amount in the fund_token_storage
instruction to prevent zero-value operations.
SOLVED: The Wayru team solved this issue by adding:
A check in owner_claim_rewards
and others_claim_rewards
instructions to ensure the provided reward_amount value is greater than 0.
A validation in fund_token_storage
to check the provided amount is greater than the zero value.
//
A user holding a previously minted NFT can initialize a new nfnode_entry
using the init_nfnode
instruction. To perform this action, the user must provide several accounts, including the nft_mint_address
, user_nft_token_account
, and others. This instruction initializes an nfnode_entry
, which is a Program Derived Address (PDA) derived from a fixed seed and a variable component, specifically the nft_mint_address
.
The instruction handler verifies that the user_nft_token_account
is a token account whose associated mint matches the provided nft_mint_address
and that its token amount is not zero. However, these validations are insufficient to ensure that the nft_mint_address
corresponds to a valid NFT. Currently, the only validation for nft_mint_address
is that it represents a Mint22
, allowing any mint to pass as valid. Consequently, any user_nft_token_account
associated with that mint and containing tokens would be accepted.
init_nfnode.rs:
let user_nft_token_account_info = &ctx.accounts.user_nft_token_account;
if user_nft_token_account_info.owner != &ctx.accounts.token_program_2022.key() {
return err!(RewardError::InvalidNftMint);
}
let user_nft_token_account_data = user_nft_token_account_info.try_borrow_data()?;
let user_nft_token_account = SplToken2022Account::try_deserialize(
&mut &user_nft_token_account_data[..]
)?;
if user_nft_token_account.amount == 0 {
return err!(RewardError::InsufficientNftBalance);
}
if user_nft_token_account.mint != ctx.accounts.nft_mint_address.key() {
return err!(RewardError::InvalidNftMint);
}
let nfnode_entry = &mut ctx.accounts.nfnode_entry;
nfnode_entry.host = ctx.accounts.host.key();
pub struct InitializeNfNode<'info> {
#[account(mut)]
pub user_admin: Signer<'info>,
#[account(mut)]
pub user: Signer<'info>,
///CHECK: only read account
pub host: AccountInfo<'info>,
///CHECK: only read account
pub manufacturer: AccountInfo<'info>,
///CHECK: only read account
pub nft_mint_address: InterfaceAccount<'info, Mint2022>,
/// CHECK: used to check nft ownership
pub user_nft_token_account: AccountInfo<'info>,
#[account(
init,
payer = user,
space = 8 + std::mem::size_of::<NfNodeEntry>(),
seeds = [b"nfnode_entry", nft_mint_address.key().as_ref()],
bump
)]
pub nfnode_entry: Account<'info, NfNodeEntry>,
To address this issue, it is recommended to implement additional validation within the nfnode_entry
initialization process to:
Verify that the mint's total supply is exactly 1.
Ensure that the mint's decimal precision is set to 0.
Note: Although the program does not perform transfers to or from the token accounts associated with these NFT mints, the fact that they are Mint22
accounts introduces the potential for unexpected extensions. Therefore, it is advisable to include a validation step that confirms the mint does not have any undesired extensions. This precaution would help mitigate unforeseen risks associated with improperly configured mints.
SOLVED: The Wayru team solved this issue by adding a validation that ensures that the total supply and decimals are those corresponding to the NFT. In addition, the AdminAccount now has a vector where your administrator can add and remove mint_authority addresses, which will correspond to the authorities that minted the allowed nft for new nfNode entries.
//
For the system initialization, the program’s upgrade authority is required to provide several accounts, including the mint_authority
, which is added to the mint_authorities
vector within the AdminAccount
. The maximum amount of mint authority addresses allowed in the vector is ten. These represent the mint authorities responsible for minting the NFTs that will allow their owners to create a new NfNode entry.
However, the mint_authority
account provided during initialization is not validated to ensure it corresponds to a valid and correct address. While this does not pose a significant security risk—since a trusted authority oversees the initialization process and can rectify errors by removing an incorrect mint_authority
and adding the correct one—it is still recommended to implement a validation check to ensure that the provided address is at least not invalid.
init_system.rs:
pub fn initialize_system(ctx: Context<InitializeSystem>) -> Result<()> {
let admin_account = &mut ctx.accounts.admin_account;
admin_account.admin_pubkey = ctx.accounts.user.key();
admin_account.paused = false;
admin_account.valid_mint = ctx.accounts.token_mint.key();
admin_account.mint_authorities.push(ctx.accounts.mint_authority.key());
Ok(())
}
#[derive(Accounts)]
pub struct InitializeSystem<'info> {
#[account(mut)]
pub user: Signer<'info>,
#[account(
init,
payer = user,
space = 8 +
std::mem::size_of::<AdminAccount>() +
MAX_MINT_AUTHORITIES * std::mem::size_of::<Pubkey>(),
seeds = [b"admin_account"],
bump
)]
pub admin_account: Account<'info, AdminAccount>,
///CHECK: only read account
pub mint_authority: AccountInfo<'info>,
Consider to add a validation to ensure the mint_authority provided is a trusted and valid address.
SOLVED: The Wayru team solved this issue by adding a check in the init_system
instruction to ensure the mint_authority provided matches the upgrade authority of the program.
//
The administrator is granted the ability to manage the program’s operational state by pausing and unpausing it. This is achieved through the pause_program
and unpause_program
instructions, which respectively halt or resume the claiming of rewards.
Neither the pause_program
nor the unpause_program
instruction handlers validate whether the current program state already matches the intended state to be set. This oversight results in the program allowings the administrator to execute unnecessary state updates, such as pausing an already-paused program or unpausing an already-active one. These redundant actions incur transaction fees without resulting in any functional changes.
lib.rs:
pub fn pause_program(ctx: Context<UpdateAdmin>) -> Result<()> {
let admin_account = &mut ctx.accounts.admin_account;
require!(
ctx.accounts.user.key() == admin_account.admin_pubkey,
RewardError::UnauthorizedAdmin
);
admin_account.paused = true;
Ok(())
}
pub fn unpause_program(ctx: Context<UpdateAdmin>) -> Result<()> {
let admin_account = &mut ctx.accounts.admin_account;
require!(
ctx.accounts.user.key() == admin_account.admin_pubkey,
RewardError::UnauthorizedAdmin
);
admin_account.paused = false;
To enhance efficiency and prevent the mentioned redundant operations, it is recommended to implement the following measures:
Add a check in the pause_program
and unpause_program
instruction handlers to verify whether the current state already matches the desired state.
Return a clear error message when these redundant actions are attempted, informing the administrator that the state is already set to the requested value.
SOLVED: The Wayru team solved this issue by adding a check in the pause_program
and unpause_program
instruction handlers to ensure that the current status is not set again.
Halborn used automated security scanners to assist with detection of well-known security issues and vulnerabilities. Among the tools used was cargo audit
, a security scanner for vulnerabilities reported to the RustSec Advisory Database. All vulnerabilities published in https://crates.io
are stored in a repository named The RustSec Advisory Database. cargo audit
is a human-readable version of the advisory database which performs a scanning on Cargo.lock. Security Detections are only in scope. All vulnerabilities shown here were already disclosed in the above report. However, to better assist the developers maintaining this code, the auditors are including the output with the dependencies tree, and this is included in the cargo audit output to better know the dependencies affected by unmaintained and vulnerable crates.
Cargo Audit Results
ID | Crate | Desccription |
---|---|---|
RUSTSEC-2022-0093 | ed25519-dalek | Double Public Key Signing Function Oracle Attack on |
RUSTSEC-2024-0344 | curve25519-dalek | Timing variability in |
Halborn strongly recommends conducting a follow-up assessment of the project either within six months or immediately following any material changes to the codebase, whichever comes first. This approach is crucial for maintaining the project’s integrity and addressing potential vulnerabilities introduced by code modifications.
// Download the full report
NfNode Rewards Program
* Use Google Chrome for best results
** Check "Background Graphics" in the print settings if needed