Date of engagement: 6th February 2025 - 10th February 2025
-
Timur GüvenkayaPrincipal advisor
Engagement Dashboard
Audit results
Guvenkaya conducted a security assessment of the NEAR Intents Passkeys Pull Request from 6th February 2025 to 10th February 2025. During this engagement, a total of 5 findings were reported. 1 of the findings was medium and the remaining were informational severity. All issues were either fixed, acknowledged, or scheduled per the remediation status.
Engagement record
- Client
- NEAR Intents
- System
- NEAR Intents passkeys pull request #43
- Review period
- 6th February 2025 - 10th February 2025
- Paths in scope
- 1
- Principal advisor
- Timur Güvenkaya
Timeline
- Review start6th February 2025
- Draft report10th February 2025
- Final report6th March 2025
Findings by severity
Finding status at final report
Remediation complexity
Impact
Likelihood
Advisory and Client
The advisory
Guvenkaya specializes in security for digital assets and financial infrastructure, from smart contracts and protocols to applications, infrastructure, custody and cryptography.
Our team, including the sitting Heads of Security at Gauntlet and Agora, brings experience from Kraken, OpenZeppelin, Binance, ZKsync, Nillion, Invicti and EY. Across the team: 200+ security reviews, $30B+ in volume secured, 13 published cryptography research papers, and credentials including OSCP, OSWE and CISM.
- Every reviewer has a public bio and is named before you sign. We match expertise to your system, with a principal leading scoping and checking findings.
The client
NEAR Intents is a cross-chain liquidity protocol for swaps, payments and asset onboarding. Users specify the assets and outcome they want, while the system coordinates routing and execution across supported blockchains. Wallets, applications and agents can integrate these capabilities into their own products.
Applications obtain quotes from competing solvers. Signed intents express the authorized asset movements, which the Verifier contract validates and executes on NEAR. Developers can integrate through a widget or API; the 1Click API handles quote requests, intent creation and execution tracking, reducing the need to build separate integrations for each supported chain and asset pair.
- Cross-chain swaps let users exchange an asset on one network for an asset on another.
- Cross-pay lets a sender use one token while the recipient receives a preferred asset on another supported chain.
- Asset onboarding lets a wallet or application accept deposits from a user's existing chain through the same network.
Scope and Review Boundaries
Review depths
- Deep
- Line-by-line review with explicit attack hypotheses, adversarial reasoning about state transitions, and reproduction attempts for each hypothesis that survived reading.
- Supporting
- The code was read for its effect on a reviewed flow. Behaviour outside that effect was not assessed.
- Targeted
- Entry points were exercised or triaged against the flow's security properties rather than read in full.
This is the code we read, and how closely. 1 paths are in scope. Each path links to the file at the reviewed commit.
| Path | Review depth | Scope note |
|---|---|---|
https:/ | Deep | Passkeys Pull Request |
Out of scope
The audit will include reviewing the code for security vulnerabilities. The audit does not include a review of the tests and dependencies.
Assessment Framework
Guvenkaya rates findings by likelihood and impact so remediation can be prioritized by technical risk, business context, and the decision the engagement is meant to support.
Rating chain applied to every finding
- 01 Likelihood Likely, possible or rare
- 02 Impact Severe, moderate or negligible
- 03 Severity Derived from the matrix below
- 04 Remediation complexity Simple, moderate or difficult
- 05 Status Not fixed, fixed, acknowledged or scheduled
Impact
| Impact | What it means here |
|---|---|
| Severe | Exploitation could result in critical loss or compromise, such as full system control, substantial financial loss, or severe reputational damage. |
| Moderate | Exploitation may lead to limited data loss, partial compromise, moderate financial impact, or noticeable degradation of services. |
| Negligible | Exploitation has minimal impact, such as minor data exposure without significant consequences or slight inconvenience without substantial disruption. |
Likelihood
| Likelihood | What it means here |
|---|---|
| Likely | The vulnerability is easily discoverable and not overly complex to exploit. |
| Possible | The vulnerability presents some challenges either in discovery or in the complexity of the attack. |
| Rare | The vulnerability is either very difficult to discover or complex to exploit, or both. |
This matrix provides a nuanced view, taking into account both the ease of discovering a vulnerability and the complexity involved in exploiting it.
| Attack Complexity \ Discovery Ease | Obvious | Concealed | Hidden |
|---|---|---|---|
| Complex | Possible | Rare | Rare |
| Moderate | Likely | Possible | Rare |
| Straightforward | Likely | Possible | Possible |
Severity
| Severity | What it means here |
|---|---|
| Critical | Assigned to vulnerabilities with severe impact and a likely likelihood of exploitation. |
| High | For vulnerabilities with either severe impact but only a possible likelihood, or moderate impact with a likely likelihood. |
| Medium | Used for vulnerabilities with severe impact but a rare likelihood, moderate impact with a possible likelihood, or negligible impact with a likely likelihood. |
| Low | For vulnerabilities with moderate impact and rare likelihood, or negligible impact with a possible likelihood. |
| Informational | The lowest severity rating, typically for vulnerabilities with negligible impact and a rare likelihood of exploitation. |
| Likelihood \ Impact | Severe | Moderate | Negligible |
|---|---|---|---|
| Likely | Critical | High | Medium |
| Possible | High | Medium | Low |
| Rare | Medium | Low | Informational |
Remediation complexity
This measures how difficult it is to remediate a finding once it has been identified.
| Remediation complexity | What it means here |
|---|---|
| Simple | Patches or fixes are readily available and easily implemented. |
| Moderate | Requires some time and resources to remediate, but well within the capabilities of most organizations. |
| Difficult | Remediation requires significant resources, specialized skills, or substantial changes to systems or architecture. |
Finding status
This tracks the client's response to each finding and whether remediation has been completed, accepted, or scheduled.
| Status | What it means here |
|---|---|
| Not Fixed | Indicates that the vulnerability has been identified but no remedial action has been taken yet. This status is crucial for newly discovered vulnerabilities or those awaiting prioritization. |
| Fixed | This status is applied when the vulnerability has been successfully remediated. It implies that appropriate measures, such as patching, configuration changes, or architectural modifications, have been implemented to resolve the issue. |
| Acknowledged | This status is used for vulnerabilities that have been recognized, but for various reasons (such as risk acceptance, cost, or other business decisions), have not been fixed. It indicates that the risk posed by the vulnerability is known and has been consciously accepted. |
| Scheduled | This status indicates that the vulnerability has been acknowledged and a plan is in place to fix it in the future. It signifies that while remediation hasn't yet occurred, the issue has been prioritized and is part of the planned development roadmap. |
Findings Summary
Findings register
| Finding | Impact | Likelihood | Severity | Remediation complexity | Status |
|---|---|---|---|---|---|
| GUV-1: Potential DoS of The Main Functionality Through Malicious Solvers | Severe | Rare | Medium | Moderate | Scheduled |
| GUV-2: Anyone Can Fake The Passkey Signature For Their Own Account | Negligible | Rare | Informational | Complex | Acknowledged |
| GUV-3: Unsafe Callback URL Validation | Negligible | Rare | Informational | Simple | Acknowledged |
| GUV-4: Insufficient Nonce Entropy Validation | Negligible | Rare | Informational | Simple | Acknowledged |
| GUV-5: Different Signature Malleability For Each Curve | Negligible | Rare | Informational | Simple | Fixed |
Detailed Findings
GUV-1: Potential DoS of The Main Functionality Through Malicious Solvers
Description
Malicious solvers can cause service degradation or denial of service (DoS) to frontends and any systems relying on solver bus data.
Causes That Make This Attack Possible:
- Frontends typically are optimizing to give the best quote to the user
- Solver bus simulates intents and aggregates quotes submitted via websockets
- A time gap exists between the solver bus's intent simulation and user signature submission
- Quote submission to the solver bus is unrestricted
- The failure of one intent causes all other intents to fail:
pub fn execute_signed_intents( mut self, signed: impl IntoIterator<Item = MultiPayload>, ) -> Result<Transfers> { for signed in signed { self.execute_signed_intent(signed)?; } self.finalize() } - An attacker controls multiple solvers with deposited funds for popular token pairs, consistently submitting the best prices. The solver's available funds aren't verified after intent simulation
- The solver bus returns quotes including the attacker's quote. Frontends likely select the attacker's quote due to its superior pricing
- The user signs the transaction and submits it to the smart contract
- A single malicious intent causes the entire transaction to fail, even if other intents were valid, due to the execution loop's error handling
- By repeating this process for each quote request, the attacker prevents reliable intent execution. This risk is heightened during early adoption when solver numbers are limited
Impact
- Reputation damage
- Inability for regular users to execute intents (griefing)
Recommendation
Implement a solver reputation system (possibly using a trusted solver list), economic penalties, and progressive timeout/backoff for unreliable solvers. This could be implemented with the addition of API keys.
Remediation
The NEAR Intents team has acknowledged the issue and will fix it soon by introducing API keys and/or reputaion-based filteting for solvers on Solver Bus level.
GUV-2: Anyone Can Fake The Passkey Signature For Their Own Account
Description
It was observed that, anyone can generate a valid P256 key, add their public key through the add_public_key function, sign the required data, and successfully pass the smart contract verification. This effectively allows users to trick the smart contract into believing that an object was signed by a passkey when it wasn't. The significance of this issue depends on whether there's a need to differentiate between passkey and hardware key signatures, or if there are special benefits planned for passkey users.
Impact
Users can fake signatures without utilizing passkeys
Recommendation
To ensure the passkey is genuine and from a verified source, you should:
Offchain - During Registration:
- Obtain the attestation certificate (CA and device) from the blob at https://fidoalliance.org/metadata/ or other sources
- Verify the device's AAGUID, certificate chain, and newly generated public key
- If verification succeeds, call the smart contract to add the public key (consider mapping between AAGUID/credential_id &pubkey). Disable unverified public key additions for P256 signatures
Offchain - During Signing: Sign the intents object without the public_key field and send it to SC
Onchain:
- Verify the flags and attestedData = true, then fetch the stored public key (using credential ID/AAGUID)
- Check the signature against the known public key
- Perform regular verifications (nonce, signer matches public key, etc.)
Remediation
The NEAR Intents team has acknowledged the issue but it won’t be fixed since it is allowed by design.
GUV-3: Unsafe Callback URL Validation
Description
The Nep413Payload structure and with_callback_url function in Nep413Payload implementation accepts callback URLs without any validation, potentially allowing malicious or unsafe URLs to be passed.
#[near(serializers = [borsh, json])]#[serde(rename_all = "camelCase")]#[derive(Debug, Clone)]pub struct Nep413Payload { pub message: String, #[serde_as(as = "Base64")] pub nonce: [u8; 32], pub recipient: String, #[serde(default, skip_serializing_if = "Option::is_none")] pub callback_url: Option<String>,} // ... existing code ...#[inline]pub fn with_callback_url(mut self, callback_url: String) -> Self {self.callback_url = Some(callback_url);self} Impact
This allows arbitrary strings to be used as callback URLs, including:
- Dangerous protocols (e.g., file://, data://)
- Malformed URLs
- URLs with null bytes or other control characters
If any off-chain component processes these callback URLs, it could be vulnerable to exploitation.
Recommendation
Implement proper URL validation in the with_callback_url and write a custom deserializer to verify Url on the parsing level in Nep413Payload.
Remediation
The NEAR Intents team has acknowledged the issue but it won’t be fixed since it is allowed by design.
GUV-4: Insufficient Nonce Entropy Validation
Description
Any signed payload accepts any 32-byte array as a nonce without validating its entropy or randomness.
#[test]fn test_zero_nonce_security() { let zero_nonce_payload = Nep413Payload { message: payload.message.clone(), nonce: [0u8; 32], // Zero nonce accepted recipient: payload.recipient.clone(), callback_url: None, };} Impact
If you’re only using the nonce as a once-per-user unique value there are no problems. However, It is still safer and more standard to generate a random nonce of sufficient length (128 bits+) so you avoid accidental collisions and stay in line with typical cryptographic best practices.
Recommendation
Implement proper nonce validation and generation
Remediation
The NEAR Intents team has acknowledged the issue but it won’t be fixed since it is allowed by design.
GUV-5: Different Signature Malleability For Each Curve
Description
Each cryptographic curve implements signature malleability differently:
SeckP: Not Allowed. Uses ecrecover with atrueflag to enable malleability checks- Ed25519: Allowed. Uses env::ed25519_verify
- P256: Allowed. Implements passkey verification without signature malleability checking
The behavior of signature malleability should be unified across all curves. Having consistent security properties would simplify threat modeling, debugging, and tracking.
Impact
While nonces currently protect against replay attacks, disallowing malleability for all curves would be more secure. Future code changes, such as adding functions without nonce validation, could introduce vulnerabilities if malleability remains inconsistent.
Recommendation
Enable signature malleability checks across all curves.
Remediation
The NEAR Intents team has fixed the issue by enabling signature malleability checks for all curves in these PRs:
The web version and the PDF (16 pages) are generated from the same source. The report as first delivered is kept in the public reports archive.