Security audit
Introduction
Before Device Apps and Plugins can be listed in the My Ledger section of Ledger Wallet, they must complete our integration process. This process includes a security audit by one of our trusted partners.
If your project fulfills the conditions, the external audit follows these steps:
- Contact the auditors and sign a contract with them. Read more.
- The auditors review your app based on Ledger specifications. Read more.
- Ledger reviews the security audit report.
- Ledger publishes your app.
Conditions
Before starting an external security audit, ensure that your project fulfills these conditions:
- Your Device App works with all our signers (Ledger Nano S Plus, X, Stax, and Flex).
- The Ledger team has functionally validated your Device App.
- - Do not start a security audit if your Device App is not ready for all Ledger signers (Ledger Nano S Plus, X, Stax, and Flex).
- - Your Device App must remain functional after the security audit.
Security audit specifications
Ledger provides a detailed specification of the checks required for a security audit that follows Ledger’s standards.
The word must indicates a requirement. The word should indicates a recommendation. Auditors can deviate from a recommendation when they have a valid justification.
Use the following specification as a checklist.
AI-assisted review
Large language models (LLMs) can identify vulnerabilities in embedded applications, and auditors are expected to use them.
- The audit must include an AI-based review performed with an advanced LLM (such as Claude or GPT).
- The AI-based review must not replace the human review. It complements the human review. The auditor remains responsible for confirming findings, eliminating false positives, and signing off on the report.
- The AI-based review should follow a structured methodology. Ledger provides a security review skill that can be used to drive the LLM: SECURITY.REVIEW.md .
- The context provided to the model must include the blockchain protocol that the application implements (see Clear Signing). This context helps surface deeper, protocol-aware vulnerabilities.
Application privileges
The application must request only the privileges it strictly needs. The audit verifies that flags, derivation paths, and curves follow the principle of least privilege.
- The application flags must abide by the principle of least privilege.
- When required, privileges must be justified.
- The application derivation paths must be restricted to coin-specific BIP32 prefixes.
- The application derivation paths must be declared in the Ledger app database.
- Curve usage must be restricted.
References:
Clear Signing
Auditors must assess clear signing in the context of the underlying blockchain protocol, at least from a security standpoint. This assessment is not a review of the protocol itself. However, the application must follow the protocol correctly and must not allow abuse that could harm the user. Even seemingly functional aspects of transaction signing can have a security impact and should therefore be in scope.
- All signing actions must ask for user approval.
- The user must be able to see all important information (amount, destination address, validator, token, and so on).
- The application must follow its blockchain protocol correctly and must not allow abuse that could harm the user. For example, it must properly handle and present dangerous flows or transaction types.
- The review is not limited to the application code. The auditor must understand the application’s blockchain protocol well enough to uncover deeper vulnerabilities. Examples include dangerous transaction types, protocol edge cases, or flows that the application does not represent accurately to the user.
- If blind signing is implemented:
- It must be disabled by default.
- It must not apply to basic transactions such as coin transfers, which must be clear signed.
- A security review of the app workflow must use either a live signer or Speculos and the functional test snapshots to ensure:
- Critical and important information is clear signed in a user-friendly format.
- The user cannot be confused or tricked by the application workflow and the displayed information.
- Every possible flow is functionally tested, with the associated snapshots present.
References:
Compilation
- Makefiles from the boilerplate app and secure-sdk must be used to compile the project. This requirement ensures that security flags are applied.
- New apps must fork the boilerplate template. Updated apps must upgrade to the latest standard Makefile in the boilerplate app.
- The compilation log review must ensure the following, which can be reviewed in the CI results:
- No compilation errors are returned.
- No compilation warnings are returned.
- No compilation warnings are silenced without a clear reason through compilation flags or pragma directives.
- No deprecated functions are used.
References:
Continuous integration
- Guidelines enforcer and build workflows must be integrated into the Device App.
- All pipelines must succeed for all supported devices.
References:
Tests
Test coverage provides confidence during the audit. The application should provide unit, functional, and, where relevant, fuzzing tests that cover both nominal and error cases.
- Unit tests should be implemented for functions that do not require Ledger OS syscalls mocking.
- All unit tests must succeed.
- Functional tests must cover at least the nominal cases, which are the features provided by the applications, and common errors, such as Clear Signing cancellation.
- All functional tests must succeed for all devices.
- Fuzzing targets should be implemented at least for parsers and critical functions that are easy to fuzz. These targets facilitate the audit.
- Ethereum plugin handlers must be fuzzed. A generic target is available in the boilerplate.
- Fuzzing should be done using libfuzzer to integrate with ClusterFuzzLite as shown in the boilerplate apps and plugins.
References:
Static analysis
Static analysis tools must run without issues, and their results are reviewed through CI. For C apps, external libraries are part of the application, so the APIs used from those libraries are also in scope.
- Dependencies must be used only when strictly necessary. The selected versions must be maintained and free of impactful vulnerabilities.
- For C apps,
scan-buildmust succeed without reporting any defects. This result can be reviewed through CI. - For C apps,
CodeQLmust succeed without returning any vulnerabilities with the “security and quality” queries. - For C apps, external libraries are part of the app, so the APIs used from those libraries must also be reviewed.
- For Rust apps,
clippymust succeed without reporting any issues. This result can be reviewed through CI. - For Rust apps, dependencies must be checked using
cargo-audit. - Other tools may be used as part of the static analysis process.
References:
Vulnerabilities and weaknesses
The review must look for technical vulnerabilities, logic errors, and weaknesses that could indirectly affect security. The following lists are not exhaustive.
- The application or its dependencies must not contain any medium or high severity vulnerabilities.
- The application should not contain any low vulnerabilities.
- The review must check for security vulnerabilities, including:
- read/write out of bounds
- integer overflow/underflow
- format string vulnerabilities
- memory leaks
- use-after-free or double-free
- incorrect type conversions
- usage of unsafe functions (eval, strcpy, strlen, gets, sprintf, …)
- returning uninitialized memory that could expose sensitive data
- …
- In particular, input validation must be comprehensive and thoroughly tested. Fuzzing is recommended:
- All parsing and other relevant functions must validate input lengths before processing.
- Parser functions handle malformed data gracefully without crashes or infinite loops.
- All type mismatches are prevented, such as using a uint8 loop counter with a uint32 bound.
- All array accesses are bounds-checked appropriately.
- …
- The review must focus on logic errors, including:
- unsanitized or unconventional user input
- cryptographic oracle
- state management handling (the application state is properly initialized and cleared or erased when finalized or when an error occurs; multi-step operations that change state enforce the correct order)
- security restrictions bypass (autolock, pin entry)
- secure error handling (all return values are checked, errors do not result in invalid or partial states, and cryptographic operation failures are handled securely)
- …
- The review must report any other weaknesses that could indirectly affect security, including weaknesses related to code quality and readability:
- magic numbers such as:
- Using raw numbers where an enum or a macro would be preferred to ease code reading and maintenance.
- Using raw numbers instead of computing them with the sizeof operator or a dedicated macro.
- lack of documentation:
- APDUs that are not documented.
- Functions that are not documented (description, parameters, return value, error cases, specific behavior, and so on).
- complex functions (huge cyclomatic complexity, length, …)
- Rust application-specific checks:
- All unsafe code blocks are justified and documented.
- There are no known panics in production code paths.
- Error handling is properly performed for all returned
Resulttypes. - Arithmetic overflows and underflows are handled securely by using
saturing_x,checked_x, or a manual check. - Utility code for testing is guarded by the
#[cfg(test)]attribute to ensure that potentially insecure test code is not included in the production application.
- …
- magic numbers such as:
Cryptography
We do not expect an advanced cryptographic evaluation, such as a formal analysis of a cryptographic scheme. However, some applications implement specific or custom cryptographic schemes that are not directly related to the blockchain protocol. The auditor must ensure that these applications use cryptographic primitives correctly.
- Secrets must be erased from memory as soon as possible after use.
- Secrets derived from the seed must not be stored, exported, or shown.
- The structural integrity of messages must be verified before signing. Never allow the signing of attacker-controlled messages.
- User-supplied messages must use a prefix if they are to be signed.
- Cryptographic primitives must not be re-implemented if they already exist in Ledger OS or the SDK.
- Cryptographic functions that can throw exceptions are deprecated and must not be used (can be reviewed through the CI results).
- Cryptographic helpers and ledger assertions provided by the SDK should be used to handle cryptographic operations.
- The client must not be able to freely manipulate keypairs.
- An authenticated encryption scheme must be used for data being cached on the client.
- If custom cryptographic code is implemented, the implementation should make a best-effort attempt to protect against side-channel leaks and fault injection.
- The review must check for common cryptographic misuse, including:
- nonce reuse
- hardcoded secrets
- lack of randomness or predictable randomness
- use of weak or deprecated algorithms
- wrong or insecure mode of operation
- weak key management
- homemade or reimplemented cryptography instead of SDK primitives
- reuse of a single key for different purposes
- …
References:
Deliverables
- The report must contain an executive summary that clearly states whether the auditor recommends deploying the app. If not, the summary must state what needs to be done.
- The report must contain the findings, reproduction steps, impacts, and associated recommendations. It should also contain tests that produced no findings.
- The report must include the following checklist in an appendix to show what the audit checked and validated.
Checklist
- An AI-based review using an advanced LLM (such as Claude or GPT) has been performed and its findings reviewed.
- The review accounts for the blockchain protocol: the app follows it correctly and cannot be abused in a way that harms the user (clear signing, dangerous flows, or transaction types).
- Cryptographic primitives are correctly used (no nonce reuse, no hardcoded secrets, sufficient randomness, strong algorithms/modes, sound key management, no homemade crypto, no key reused across usages).
- Application flags, derivation paths, and curves are correctly set.
- Clear Signing correctly displays information and asks for user confirmation.
- Blind signing is disabled by default or does not exist. If it exists, it applies to complex transactions but not to coin transfers or swaps.
- The app workflow is considered secure, and snapshots cover the nominal and error cases of app features.
- The boilerplate Makefiles and SDK are used to compile the app. A new app is based on the C or Rust boilerplate.
- The app compiles without errors or warnings. No errors or warnings are silenced using compilation flags or pragma directives.
- Guidelines enforcer and build workflows are integrated and pass.
- Unit, functional, and fuzzing tests pass.
- For app-plugins, the generic fuzzing target is integrated.
- scan-build/CodeQL or clippy succeeds without reporting vulnerabilities.
- Dependencies are necessary, maintained, and secure, with no known impactful vulnerability in the selected version.
- The app does not contain any medium or high severity vulnerabilities.
- The review process looked into technical vulnerabilities as well as logical ones and weaknesses.
- Secrets are correctly erased from memory, not exported or shown to the user.
- User-supplied messages use a prefix and are validated before signing.
- No cryptographic primitives are re-implemented if they already exist in Ledger OS or the SDK.
- The client cannot freely manipulate the device keypairs.
- An authenticated encryption scheme is used for data being cached on the client.