Prepared by:
HALBORN
Last Updated 09/10/2024
Date of Engagement by: July 15th, 2024 - August 7th, 2024
100% of all REPORTED Findings have been addressed
All findings
19
Critical
4
High
1
Medium
1
Low
5
Informational
8
The EMoney team
engaged Halborn to conduct a security assessment on their cosmos appchain modules, beginning on 07/15/2024 and ending on 08/07/2024. The security assessment was scoped to the sections of code that pertain to the regulation & lock modules of app chain. Commit hashes and further details can be found in the Scope section of this report.
Halborn was provided 3 weeks for the engagement and assigned 1 full-time security engineer to review the security of the modules in scope. The engineer is a blockchain and smart contract security expert with advanced penetration testing and smart contract hacking skills, and deep knowledge of multiple blockchain protocols.
The purpose of the assessment is to:
- Ensure that the Regulation & Lock Modules operate as intended.
- Identify potential security issues with the custom modules used in the EMoney Chain.
In summary, Halborn identified some security issues that were mostly addressed by the EMoney team
.
Halborn performed a combination of manual and automated security testing to balance efficiency, timeliness, practicality, and accuracy in regard to the scope of the custom modules. While manual testing is recommended to uncover flaws in logic, process, and implementation; automated testing techniques help enhance coverage of structures 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 architecture and purpose.
- Static Analysis of security for scoped repository, and imported functions. (e.g., staticcheck
, gosec
, unconvert
, codeql
, ineffassign
and semgrep
)
- Manual Assessment for discovering security vulnerabilities on the codebase.
- Ensuring the correctness of the codebase.
- Dynamic Analysis of files and modules related to the EMoney AppChain Modules.
External libraries and financial-related attacks.
New features/implementations after/with the remediation commit IDs
Changes that occur outside of the scope of PRs.
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
4
High
1
Medium
1
Low
5
Informational
8
Security analysis | Risk level | Remediation Date |
---|---|---|
Missing Message Type Registrations in Regulation Module | Critical | Solved - 08/18/2024 |
Missing RegisterAminoCodec Implementation in Regulation Module | Critical | Solved - 08/19/2024 |
Incomplete Message Handling in Regulation Module Handler | Critical | Solved - 08/18/2024 |
Comprehensive Error Handling Review in Regulation Module Keeper | Critical | Solved - 09/09/2024 |
Improper Implementation of Cosmos SDK Upgrade Procedures | High | Risk Accepted |
The HTTP/2 protocol in Golang 1.21.5 is susceptible to DoS attacks | Medium | Solved - 08/18/2024 |
Lack of spec on the modules | Low | Risk Accepted |
Lack Of Simulation And Fuzzing Of The Module Invariant | Low | Risk Accepted |
Docker Container Running as Root User | Low | Risk Accepted |
Missing Event Emissions in Application Chain Messages | Low | Solved - 08/19/2024 |
MustAccAddressFromBech32 can panic unexpectedly in the keeper package | Low | Risk Accepted |
Hardcoded Constants as Governance Parameters | Informational | Acknowledged |
ValidatorCommissionDecorator Marked for Removal but Still Present | Informational | Solved - 08/19/2024 |
Lack of Abstain Option in Voting Mechanism | Informational | Acknowledged |
Potential Loss of Vote History in Genesis Export and Import | Informational | Acknowledged |
Package Naming Inconsistencies in Regulation Module | Informational | Acknowledged |
Outdated CometBFT Module and Multiple Vulnerabilities | Informational | Acknowledged |
Outdated ibc-go Module | Informational | Acknowledged |
Outdated Cosmos SDK | Informational | Acknowledged |
// Critical
Several message types defined in the regulation module are not properly registered in the RegisterInterfaces function. Specifically, the following message types are missing from the registration:
- MsgProposeBlock
- MsgProposeAdd
- MsgVote
- MsgProcessVoting
The current RegisterInterfaces function only registers MsgTransferAuthority, MsgAllowAddress, and MsgDisallowAddress. This omission can lead to issues with message handling, serialization, and deserialization within the Cosmos SDK framework.
The existing implementation is as follows:
func RegisterInterfaces(registry types.InterfaceRegistry) {
registry.RegisterImplementations((*sdk.Msg)(nil),
&MsgTransferAuthority{},
&MsgAllowAddress{},
&MsgDisallowAddress{},
)
msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc)
}
1. Update the RegisterInterfaces function in the types package to include all defined message types:
func RegisterInterfaces(registry types.InterfaceRegistry) {
registry.RegisterImplementations((*sdk.Msg)(nil),
&MsgTransferAuthority{},
&MsgAllowAddress{},
&MsgDisallowAddress{},
&MsgProposeBlock{},
&MsgProposeAdd{},
&MsgVote{},
&MsgProcessVoting{},
)
msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc)
}
2. Ensure that all these message types are properly defined in the types package with their respective structs and methods.
3. If these message types are intended to be used with the LegacyAmino codec as well, make sure to register them in the RegisterLegacyAminoCodec function:
func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
cdc.RegisterConcrete(&MsgTransferAuthority{}, "regulation/MsgTransferAuthority", nil)
cdc.RegisterConcrete(&MsgAllowAddress{}, "regulation/MsgAllowAddress", nil)
cdc.RegisterConcrete(&MsgDisallowAddress{}, "regulation/MsgDisallowAddress", nil)
cdc.RegisterConcrete(&MsgProposeBlock{}, "regulation/MsgProposeBlock", nil)
cdc.RegisterConcrete(&MsgProposeAdd{}, "regulation/MsgProposeAdd", nil)
cdc.RegisterConcrete(&MsgVote{}, "regulation/MsgVote", nil)
cdc.RegisterConcrete(&MsgProcessVoting{}, "regulation/MsgProcessVoting", nil)
}
SOLVED : The Emoney team solved the issue by registering message types.
// Critical
The RegisterLegacyAminoCodec method in the AppModuleBasic struct of the regulation module is currently empty. This means that the module's types are not being registered with the LegacyAmino codec, which could lead to serialization and deserialization issues for messages and types used in this module.
The empty implementation is as follows:
// RegisterLegacyAminoCodec registers the regulation module's types on the LegacyAmino codec.
func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {}
This oversight could potentially cause problems with backwards compatibility, especially if there are other parts of the system or external tools that still rely on Amino encoding.
Implement the RegisterLegacyAminoCodec
method to register all relevant types used in the regulation module.
SOLVED : The Emoney team solved the issue by registering codec.
// Critical
The current implementation of the NewHandler function in the regulation module is missing handlers for several message types that are defined in the msgServer struct. Specifically, the handlers for MsgProposeBlock, MsgProposeAdd, MsgVote, and MsgProcessVoting are not included in the handler function. This omission means that these message types cannot be processed by the module, potentially breaking critical functionality related to voting and proposal processes.
The current handler only processes the following message types:
- MsgTransferAuthority
- MsgAllowAddress
- MsgDisallowAddress
However, the msgServer struct implements handlers for additional message types that are not being routed in the NewHandler function.
The missing handlers prevent the module from processing important messages related to proposing blocks, proposing additions, voting, and processing voting results. This severely limits the functionality of the regulation module and could lead to a breakdown of the governance and regulatory processes that depend on these message types.
Update the NewHandler function to include all message types implemented in the msgServer struct. Here's an example of how the updated function should look:
func NewHandler(k keeper.Keeper) sdk.Handler {
msgServer := keeper.NewMsgServerImpl(k)
return func(dsadasctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
switch msg := msg.(type) {
case *types.MsgTransferAuthority:
res, err := msgServer.TransferAuthority(sdk.WrapSDKContext(ctx), msg)
return sdk.WrapServiceResult(ctx, res, err)
case *types.MsgAllowAddress:
res, err := msgServer.AllowAddress(sdk.WrapSDKContext(ctx), msg)
return sdk.WrapServiceResult(ctx, res, err)
case *types.MsgDisallowAddress:
res, err := msgServer.DisallowAddress(sdk.WrapSDKContext(ctx), msg)
return sdk.WrapServiceResult(ctx, res, err)
case *types.MsgProposeBlock:
res, err := msgServer.ProposeBlock(sdk.WrapSDKContext(ctx), msg)
return sdk.WrapServiceResult(ctx, res, err)
case *types.MsgProposeAdd:
res, err := msgServer.ProposeAdd(sdk.WrapSDKContext(ctx), msg)
return sdk.WrapServiceResult(ctx, res, err)
case *types.MsgVote:
res, err := msgServer.Vote(sdk.WrapSDKContext(ctx), msg)
return sdk.WrapServiceResult(ctx, res, err)
case *types.MsgProcessVoting:
res, err := msgServer.ProcessVoting(sdk.WrapSDKContext(ctx), msg)
return sdk.WrapServiceResult(ctx, res, err)
default:
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized regulation message type: %T", msg)
}
}
}
SOLVED : The Emoney team solved the issue by registering message types.
// Critical
A thorough review of the regulation module's Keeper implementation reveals several instances of inadequate or missing error handling. These issues can lead to silent failures, unexpected behavior, or potential security vulnerabilities.
Key Issues:
1. Ignored Errors:
Several functions ignore returned errors, potentially leading to incorrect state or execution flow.
2. Panics Instead of Error Returns:
Some functions panic on error conditions instead of returning errors, which can lead to blockchain instability.
3. Inconsistent Error Handling:
Error handling is not consistent across the module, making the code harder to maintain and debug.
4. Missing Error Checks:
Some operations that could potentially fail are not checked for errors.
Detailed Findings:
1. AddressStatus:
- No error handling for potential store access failures.
2. AllowAddress and DisallowAddress:
- Proper error handling implemented.
3. SetAddressStatus:
- No error handling for potential store access failures.
4. TransferAuthority:
- Proper error handling implemented.
5. RemoveAuthority and AddAuthority:
- Uses panic instead of returning errors.
- Example:
if err != nil {
panic(err)
}
6. ProposeVoting:
- Proper error handling implemented.
7. Vote:
- Error from GetVotingById is properly handled.
8. ProcessVoting:
- Error from GetVotingById is properly handled.
- Error from GetVotingThreshold is ignored.
9. GetVotingById:
- Returns error, but uses MustUnmarshal which can panic.
10. GetVotingThreshold:
- Returns error, but it's often ignored in calling functions.
11. ApplyVote:
- Error from GetVotingThreshold is checked but not properly handled.
- Uses MustUnmarshal which can panic.
12. FinalizeBlock and FinalizeAdd:
- Ignore error from GetVotingById.
1. Consistent Error Handling:
Implement a consistent error handling strategy across all functions.
2. Replace Panics with Error Returns:
Update functions like RemoveAuthority and AddAuthority to return errors instead of panicking.
3. Check All Returned Errors:
Ensure all functions that can return errors have their results checked and handled appropriately.
4. Use Unmarshal Instead of MustUnmarshal:
Replace instances of MustUnmarshal with Unmarshal and handle potential errors.
5. Improve Error Context:
Use error wrapping to provide more context when returning errors.
6. Add Logging:
Implement logging for error conditions, especially in cases where execution continues after an error.
SOLVED : The Emoney team solved the issue by adding error handlers.
// High
The regulation module in the Scallop Bank chain does not fully adhere to the Cosmos SDK upgrade procedures. Specifically, the module's ConsensusVersion() method is static and does not reflect proper version management as recommended by Cosmos SDK. This could lead to issues during chain upgrades and may prevent proper execution of upgrade handlers.
Key observations:
1. The ConsensusVersion() method returns a hard-coded value of 2:
func (AppModule) ConsensusVersion() uint64 { return 2 }
2. There's no implementation of upgrade handlers or migration scripts.
3. The module doesn't seem to track or update its version based on changes or upgrades.
Implement upgrade handlers:
- Create upgrade handlers for each version change.
- Ensure these handlers perform necessary state migrations.
RISK ACCEPTED: The Emoney team accepted the risk of the issue.
// Medium
A vulnerability was discovered with the implementation of the HTTP/2 protocol in Golang prior to 1.21.9 and 1.22.2 versions. The current version used in app chain is 1.20.
An attacker can cause the HTTP/2 endpoint to read arbitrary amounts of header data by sending an excessive number of CONTINUATION frames. This cause excessive CPU consumption of the receiver device since there is no sufficient limitation on the amount of frames. Thus, It could be exploited to cause DoS.
Please note that, many HTTP/2 implementations (including Golang) did not properly limit the amount of CONTINUATION frames within a single stream.
References:
The issue is fixed in both Golang 1.21.9 and 1.22.2. However, If you are intending to use 1.21.X, I would recommend upgrading to 1.21.11 (the latest of 1.21.X) since it has some other security/bug fixes in net/http package.
SOLVED : The Emoney team solved the issue by updating golang version.
// Low
The spec file intends to outline the common structure for specifications within this directory. The regulation/lock module is missing spec. This documentation is segmented into developer-focused messages and end-user-facing messages. These messages may be shown to the end user (the human) at the time that they will interact with the module.
It is recommended that modules are fully annotated using spec for all available functionalities.
RISK ACCEPTED: The Emoney team accepted the risk of the issue.
// Low
The Emoney AppChain system lacks comprehensive CosmosSDK simulations and invariants for its modules. More complete use of the simulation feature would make it easier to fuzz test the entire blockchain and help ensure that invariants hold.
Eventually, extend the simulation module to cover all operations that can occur in a real Emoney Chain deployment, along with all possible error states, and run it many times before each release.
Make sure of the following:
- All module operations are included in the simulation module.
- The simulation uses some accounts (e.g., between 5 and 20) to increase the likelihood of an interesting state change.
- The simulation uses the currencies/tokens that will be used in the production network.
- The simulation continues to run when a transaction fails.
- All paths of the transaction code are executed. (Enable code coverage to see how often individual lines are executed.)
RISK ACCEPTED: The Emoney team accepted the risk of the issue.
// Low
The Dockerfile for the Emoney app chain
application is configured to run the container as the root user. This is evident from the use of the '/root' directory as the working directory and the absence of any user-switching commands.
FROM golang:stretch
RUN apt update
RUN apt install ca-certificates jq -y
WORKDIR /root
COPY --from=build-env /go/src/github.com/ScallopBank/chain/build/emoneyd /usr/bin/emoneyd
CMD ["emoneyd"]
Modify the Dockerfile to create and use a non-root user for running the application. Here's an example of how to modify the Dockerfile:
FROM golang:stretch AS build-env
WORKDIR /go/src/github.com/ScallopBank/chain
RUN apt update && apt install git -y
COPY . .
RUN make build
FROM golang:stretch
RUN apt update && apt install ca-certificates jq -y
# Create a non-root user
RUN useradd -m appuser
WORKDIR /home/appuser
# Copy the binary
COPY --from=build-env /go/src/github.com/ScallopBank/chain/build/emoneyd /usr/local/bin/emoneyd
# Change ownership of the binary
RUN chown appuser:appuser /usr/local/bin/emoneyd
# Switch to non-root user
USER appuser
CMD ["emoneyd"]
RISK ACCEPTED: The Emoney team accepted the risk of the issue.
// Low
The current implementation of the msgServer methods within the keeper package lacks event emissions for various message handling functions. Events are crucial for enabling off-chain services and clients to track and respond to state changes within the blockchain. The absence of these events makes it difficult for external systems to react to important actions such as authority transfers, address allowance/disallowance, proposals, and votes.
To address this issue, it is recommended to emit appropriate events in each method of the msgServer
.
SOLVED : The Emoney team solved the issue by adding events on the modules.
// Low
In the current implementation of the keeper package, the utility function utils.MustAccAddressFromBech32 is used to convert Bech32 encoded addresses to sdk.AccAddress in multiple locations (e.g., SaveVoting, FinalizeBlock, FinalizeAdd, DeleteVoting). The MustAccAddressFromBech32 function can panic if the provided Bech32 address is invalid.
Replace MustAccAddressFromBech32 with AccAddressFromBech32.
RISK ACCEPTED: The Emoney team accepted the risk of the issue.
// Informational
In the provided keeper code for the regulation module, two important constants are hardcoded:
1. MIN_AMOUNT = 20000 * 10
2. VOTING_PERIOD = 86400 * 14 (14 days in seconds)
These values are likely intended to be governance parameters that could be adjusted through governance proposals. Hardcoding these values reduces the flexibility of the system and makes it difficult to adjust these parameters without a code change and chain upgrade.
Impact:
1. Lack of flexibility: Changes to these parameters require code modifications and potentially a chain upgrade.
2. Governance limitations: The community cannot adjust these parameters through standard governance processes.
3. Reduced adaptability: The system cannot easily adapt to changing requirements or market conditions.
1. Convert these hardcoded constants into governance parameters:
type Params struct {
MinAmount sdk.Int
VotingPeriod time.Duration
}
ACKNOWLEDGED: The Emoney team acknowledged the issue.
// Informational
The ValidatorCommissionDecorator struct and its associated methods are marked with a TODO comment indicating that they should be removed once the Cosmos SDK is upgraded to v0.46. However, these components are still present in the codebase, despite the project's go.mod file showing that it already depends on Cosmos SDK v0.46.13.
The relevant code snippet is:
// TODO: remove once Cosmos SDK is upgraded to v0.46
// ValidatorCommissionDecorator validates that the validator commission is always
// greater or equal than the min commission rate
type ValidatorCommissionDecorator struct {
cdc codec.BinaryCodec
}
1. Remove the ValidatorCommissionDecorator struct and all associated methods (NewValidatorCommissionDecorator, AnteHandle, validateAuthz, validateMsg).
SOLVED : The Emoney team solved the issue by deleting redundant code.
// Informational
The current voting mechanism within the regulation module does not provide an option for KYC authorities to abstain from voting. As a result, authorities are forced to vote either "for" or "against" a proposal. This limitation may lead to situations where authorities who prefer to remain neutral or are unsure about a proposal's implications are compelled to make a binary choice, potentially skewing the results.
The absence of an abstain option can lead to biased voting outcomes, as authorities might vote against their true preference just to avoid choosing the opposite option.
To address this issue, it is recommended to introduce an abstain option in the voting mechanism. This will allow KYC authorities to explicitly choose to abstain from voting without influencing the "for" or "against" counts.
ACKNOWLEDGED: The Emoney team acknowledged the issue.
// Informational
In the current implementation of the InitGenesis and ExportGenesis functions, there's a risk of losing historical vote data. The InitGenesis function resets all vote counters to zero when importing genesis state, while the ExportGenesis function only includes votes for active voting. This approach could lead to a loss of important historical data and potentially affect the integrity of the voting system.
Specifically:
1. In InitGenesis
:
voting.VotesForCounter = 0
voting.VotesAgainstCounter = 0
This resets all vote counters, effectively erasing the voting history.
2. In ExportGenesis
:
activeVotings := k.GetActiveVotings(ctx)
This only exports vote for currently active voting, potentially losing data from completed voting.
This behavior could lead to inconsistencies if the chain needs to be restarted from a genesis state, as all historical voting data would be lost.
Modify the ExportGenesis
function to include all votings, not just active ones. This ensures no historical data is lost during export.
ACKNOWLEDGED: The Emoney team acknowledged the issue.
// Informational
The regulation module's keeper package has inconsistencies between the package declaration and the import statements. This suggests that the code may have been copied from a different project (ScallopBank) without proper adaptation to the EMoney-Network repository.
1. Package Declaration:
The file is declared as package keeper
, which is correct for its location in the EMoney-Network repository.
2. Import Statements:
Several import statements reference a "ScallopBank" project, which is inconsistent with the EMoney-Network repository:
"github.com/ScallopBank/chain/utils"
"github.com/ScallopBank/chain/x/regulation/types"
emoneyconfig "github.com/ScallopBank/chain/cmd/config"
Correct all import statements to use the appropriate paths for the EMoney-Network project.
ACKNOWLEDGED: The Emoney team acknowledged the issue.
// Informational
The project is using an outdated version of the CometBFT module (github.com/cometbft/cometbft). This older version is affected by multiple security vulnerabilities of varying severity.
Identified Vulnerabilities:
1. ASA-2024-008 (GHSA-hg58-rf2h-6rr7)
- Severity: Moderate
- Description: Instability during blocksync when syncing from malicious peer
- Published: June 27, 2024
2. ASA-2024-004 (GHSA-555p-m4v6-cqxv)
- Severity: Low
- Description: Default configuration param for Evidence may limit window of validity
- Published: February 28, 2024
3. ASA-2024-001 (GHSA-qr8r-m495-7hc4)
- Severity: High
- Description: Validation of VoteExtensionsEnableHeight
can cause chain halt
- Published: January 18, 2024
4. ASA-2023-002 (GHSA-hq58-p9mv-338c)
- Severity: Not specified (likely Moderate)
- Description: Default for BlockParams.MaxBytes
consensus parameter may increase block times and affect consensus participation
- Published: September 28, 2023
1. Identify the current version of CometBFT in use.
2. Determine the latest stable version of CometBFT that addresses all mentioned vulnerabilities.
ACKNOWLEDGED: The Emoney team acknowledged the issue.
// Informational
The EMoney-Network project is currently using an outdated version of the ibc-go module (v6.1.1) which is vulnerable to a critical security issue (ASA-2024-007). This vulnerability allows potential reentrancy attacks using timeout callbacks in ibc-hooks.
If the EMoney-Network chain satisfies the following conditions, it is vulnerable:
1. IBC-enabled (which it is, given the use of ibc-go).
2. CosmWasm-enabled and allows code uploads for wasm contracts.
3. Utilizes the ibc-hooks middleware and wraps ICS-20 transfer application.
Upgrade the ibc-go module to at least version 6.3.0 or the latest stable version in the v6.x.x series.
ACKNOWLEDGED: The Emoney team acknowledged the issue.
// Informational
The EMoney Appchain project is currently using an outdated version of the Cosmos SDK (v0.46.13). This version is affected by multiple security vulnerabilities of varying severity.
Identified Vulnerabilities:
1. ASA-2024-002 (GHSA-2557-x9mg-76w8)
- Severity: Moderate
- Description: Default PrepareProposalHandler
may produce invalid proposals when used with default SenderNonceMempool
- Published: February 20, 2024
2. ASA-2024-003 (GHSA-4j93-fm92-rp4m)
- Severity: Moderate
- Description: Missing BlockedAddressed
Validation in Vesting Module
- Published: February 20, 2024
3. ASA-2024-005 (GHSA-86h5-xcpx-cfqc)
- Severity: Low
- Description: Potential slashing evasion during re-delegation
- Published: February 27, 2024
Update the Cosmos SDK to the latest stable version that addresses all these vulnerabilities.
ACKNOWLEDGED: The Emoney team acknowledged the issue.
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
* Use Google Chrome for best results
** Check "Background Graphics" in the print settings if needed