Security Audit
Introduction
To be listed on the Ledger Live “My Ledger“ section, Device Apps and Plugins must go through our integration process that includes a security audit performed by one of our trusted partners.
Provided your project fulfills the conditions, this is how an external audit unfolds:
- You get in touch with the auditers 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
The security audit is mandatory for an application to be available on our production providers (accessible by default from the LedgerLive). However it is possible to deploy without security audit on other providers, for test purposes. However, the application will need to display a warning message when starting.
Conditions
To go through an external security audit, ensure your project fulfills the following conditions:
- Your Device App works with all our devices (Ledger Nano S, S Plus, X, Stax and Flex)
- Your Device App has been functionally validated by Ledger team
- - Do not start a security audit process if your Device App is not ready for all Ledger devices (Ledger Nano S, S Plus, X, Stax and Flex).
- - Your Device App must still be functional after the security audit
Security audit specifications
Ledger has established and made public a detailed specification of what needs to be checked during a security audit following Ledger’s standards.
When the word must is used, it indicates a requirement. When the word should is used, it indicates a recommendation. It means that there are reasons not to follow the recommendation and it can be justified.
Do not hesistate to use the following specification as a checklist.
Application privileges
- 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.
- Curves usage must be restricted.
References:
Clear signing
- All signing actions must ask for user approval.
- The user must be able to see every important information (amount, destination address, validator, token…).
- If blind signing is implemented:
- It must be disabled by default.
- It must not apply to basic transactions such as the coin transfers, which must be clear signed.
- A security review of the app workflow using either a live device or Speculos and the functional tests snapshots must ensure:
- Critical and important information are clear signed using 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 (associated snapshots are present).
References:
Compilation
- Makefiles from boilerplate app and secure-sdk must be used to compile the project (the goal is to ensure that security flags are applied).
- New apps must fork the boilerplate template and updated apps must upgrade to the latest standard makefile (located in the boilerplate app).
- The compilation logs review must ensure (can be reviewed through the CI results):
- No compilation errors are returned.
- No compilation warnings are returned.
- No compilation warnings are silenced without a clear reason (though compilation flags or pragma directives).
- No deprecated functions are being used.
References:
Continuous integration
- Guidelines enforcer and build workflows must be integrated to the device application.
- All pipelines must succeed for all supported devices.
References:
Tests
- Unit tests should be implemented for functions that do not require Ledger OS syscalls mocking.
- All unit tests must succeed.
- Functional tests must be written to cover at least the nominal cases (features provided by the applications) and common errors (for example 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 as it will facilitate the audit.
- Ethereum plugins 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
- Dependencies must be used only if they’re strictly needed and maintained without containing impactful vulnerabilities for the chosen version.
- For C apps,
scan-build
must succeed without returning any defects (can be reviewed through the CI results). - For C apps,
CodeQL
must succeed without returning any vulnerabilities with the “security and quality” queries. - For C apps, external libraries are considered part of the app meaning that used APIs must also be reviewed.
- For Rust apps,
clippy
must succeed without returning any issue (can be reviewed through the CI results). - 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 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 (non exhaustive list):
- read/write out of bounds
- integer overflow/underflow
- format string vulnerabilities
- memory leaks
- incorrect type conversions
- usage of unsafe functions (eval, strcpy, strlen, gets, sprintf, …)
- …
- The review must focus on logic errors (non exhaustive list):
- unsanitized or unconventional user input
- cryptographic oracle
- state machine issues (if the intended flow isn’t followed)
- security restrictions bypass (autolock, pin entry)
- …
- The review must report any other weaknesses, for example related to code quality and readability that could impact security indirectly (non exhaustive list):
- 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 it with sizeof operator and/or dedicated macro.
- lack of documentation:
- APDUs that are not documented.
- Functions that are not documented (description, parameters, return value, error cases, specific behavior, …).
- complex functions (huge cyclomatic complexity, length, …)
- …
- magic numbers such as:
Cryptography
- Secrets must be erased from memory as soon as possible after usage.
- Secrets derived from seed must not be stored, exported or shown.
- Structure integrity of messages must be verified before signature (never allow signing 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.
- Authenticated encryption scheme must be used for data being cached on the client.
References:
Deliverables
- The report must contain an executive summary explicitly giving the auditor feedback on whether this app should be deployed or not (and in this case what needs to be done).
- The report must contain the findings, steps to reproduce, impacts and associated recommendations. It should also contains tests that gave no results.
- The report must contain the checklist below in appendix to indicate what has been checked and validated during the audit.
Checklist
- 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 does apply for complex transactions but not to coin transfers or swaps).
- App workflow is considered secure and snapshots cover the nominal and error cases of app features.
- Boilerplate Makefiles and SDK are used to compile the app. If it’s a new app, it has been developed over the C/Rust boilerplates.
- The app compiles without errors or warnings (no errors/warnings are silenced using compilation flags or pragma directives)
- Guidelines enforcer and build workflows are integrated and passed.
- Unit tests, functional tests and fuzzing tests are passing.
- For app-plugins, the generic fuzzing target is integrated.
- scan-build/CodeQL or clippy succeed without returning vulnerabilities
- Dependencies are needed, maintained and secure (no known impactful vulnerability for the used 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 signature.
- No cryptographic primitives are re-implemented if they already exist in Ledger OS or the SDK.
- The client is not able to freely manipulate the device keypairs.
- An authenticated encryption scheme is used for data being cached on the client.