Skip to content

fix(imported-tokens): validate the entered canisters anonymously - #8039

Open
yhabib wants to merge 3 commits into
mainfrom
fix/import-token-anonymous-validation
Open

fix(imported-tokens): validate the entered canisters anonymously#8039
yhabib wants to merge 3 commits into
mainfrom
fix/import-token-anonymous-validation

Conversation

@yhabib

@yhabib yhabib commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Motivation

The import token flow validates the ledger and the index canister before it imports the token. Both validation calls used the user identity, so both carried the user principal to the canister the user or a URL supplied.

The import-ledger-id and import-index-id URL parameters prefill the import form and open the review step with no click. So one visit to a crafted deep link sent the user principal to two attacker-chosen canisters, before the user confirmed anything.

Changes

  • Switched getIcrcTokenMetaData in icrc-accounts.services.ts to the anonymous identity.
  • Switched getLedgerId in icrc-index.services.ts to the anonymous identity, kept certified: true.
  • Added a changelog entry under Security.
  • Updated the service and component tests for the new anonymous identity.
  • Added a new modal test that asserts both validation calls use the anonymous identity and never the signed-in user's.
  • Added an e2e test that opens the deep link and checks the raw IC requests: no request to the URL canisters carries sender_pubkey, while a parallel request to the nns-dapp backend does.

Tests

npm run check, npm run test (672 files, 5906 passed, 9 skipped), and ./scripts/check-relative-imports all pass.

Confirmed the new tests catch the bug: reverting either identity switch alone fails the new modal test and the matching service test.

The e2e test needs a working local replica to run here, so CI must run frontend/src/tests/e2e/import-token-anonymous-validation.spec.ts and frontend/src/tests/e2e/import-token.spec.ts before merge. They are the only proof that the ICRC index canister accepts an anonymous ledger_id update call.

Todos

  • Accessibility (a11y) – no impact, no UI change.
  • Changelog – added, under Security.

The import token flow validates the ledger and the index canister before it
imports the token. Both calls used the user identity, so both carried the user
principal to the canister. A user can type the canister IDs, and the
`import-ledger-id` and `import-index-id` URL parameters can also supply them.
The modal validates a deep link as soon as the imported tokens are loaded, so
one visit to a crafted link sent the user principal to two canisters that the
link chose.

The token metadata and the `ledger_id` of an index canister are public data, so
`getIcrcTokenMetaData` and `getLedgerId` now use the anonymous identity.
`addImportedToken` keeps the user identity, because it writes to the nns-dapp
backend after the user clicks Confirm.
…lidation

The test opens `/tokens/?import-ledger-id=...&import-index-id=...` with a
signed-in user. It records every IC request that the browser sends before the
first click. Each request to the two URL canisters must carry the anonymous
sender and no `sender_pubkey` field. The same window must hold a signed request
to the nns-dapp backend canister, which proves the session is authenticated and
the check is not vacuous.

The test also runs the rest of the deep link flow. The review step must open
with no click, and Confirm must still import the token.
@yhabib
yhabib requested a review from a team as a code owner September 4, 2026 13:03
@yhabib
yhabib requested a lite review from Copilot September 4, 2026 13:03
@zeropath-ai

zeropath-ai Bot commented Sep 4, 2026

Copy link
Copy Markdown

No security or compliance issues detected. Reviewed everything up to 0defe20.

Security Overview
Detected Code Changes
Change Type Relevant files
Enhancement ► frontend/src/lib/services/icrc-accounts.services.ts
       Use anonymous identity for public data calls
► frontend/src/lib/services/icrc-index.services.ts
       Switch to anonymous identity for index canister ID lookup
► frontend/src/tests/lib/services/icrc-accounts.services.spec.ts
       Add test ensuring anonymous identity is used for ledger canister calls
► frontend/src/tests/lib/services/icrc-index.services.spec.ts
       Add test ensuring anonymous identity is used for index canister calls
► frontend/src/tests/lib/pages/IcrcWallet.spec.ts
       Adapt tests to expect anonymous identity for certain calls
► frontend/src/tests/lib/components/accounts/ImportTokenModal.spec.ts
       Add test validating anonymous identity during URL canister validation
► frontend/src/tests/e2e/import-token-anonymous-validation.spec.ts
       Add end-to-end test for anonymous validation during import token flow
► frontend/src/CHANGELOG-Nns-Dapp-unreleased.md
       Document anonymous identity behavior changes

Copilot AI previously approved these changes Sep 4, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approved

The core change is narrowly scoped to identity selection for untrusted-canister validation and is backed by updated unit coverage plus a targeted e2e regression test.

Pull request overview

Addresses a privacy leak in the “import token” deep-link flow by ensuring canister validation requests (based on untrusted URL/form inputs) are made with an anonymous identity so the user principal is not disclosed before confirmation.

Changes:

  • Switch ICRC ledger token-metadata and ICRC index ledger-id validation calls to use an anonymous identity.
  • Update/add unit and modal tests to assert anonymous identity is used for zero-click validation, while the actual import remains authenticated.
  • Add a Playwright e2e test that inspects raw IC request envelopes to ensure URL-canister requests are unsigned/anonymous.
File summaries
File Description
frontend/src/lib/services/icrc-index.services.ts Uses anonymous identity for index→ledger-id validation calls.
frontend/src/lib/services/icrc-accounts.services.ts Uses anonymous identity for ledger token-metadata fetch during import validation.
frontend/src/tests/lib/services/icrc-index.services.spec.ts Updates service unit test to expect anonymous identity usage.
frontend/src/tests/lib/services/icrc-accounts.services.spec.ts Updates/adds unit tests asserting anonymous identity for metadata fetch.
frontend/src/tests/lib/pages/IcrcWallet.spec.ts Updates page-level test to expect anonymous identity in index validation.
frontend/src/tests/lib/components/accounts/ImportTokenModal.spec.ts Adds modal test ensuring URL-based validation uses anonymous identity, import uses authenticated identity.
frontend/src/tests/e2e/import-token-anonymous-validation.spec.ts Adds e2e deep-link test validating raw IC requests are anonymous for URL canisters.
CHANGELOG-Nns-Dapp-unreleased.md Adds Security changelog entry documenting the privacy fix.
Review details

Suppressed comments (1)

frontend/src/tests/lib/services/icrc-accounts.services.spec.ts:864

  • Same brittleness as above: comparing against new AnonymousIdentity() by deep equality makes the test depend on implementation details rather than the requirement (anonymous principal). Use expect.any(AnonymousIdentity) for the argument match.
      expect(ledgerApi.queryIcrcToken).toHaveBeenCalledWith({
        identity: new AnonymousIdentity(),
        certified: false,
        canisterId: ledgerCanisterId,
      });
  • Files reviewed: 8/8 changed files
  • Comments generated: 4
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread frontend/src/tests/lib/components/accounts/ImportTokenModal.spec.ts
Comment thread frontend/src/tests/lib/pages/IcrcWallet.spec.ts
Comment thread frontend/src/tests/lib/services/icrc-accounts.services.spec.ts
Comment thread frontend/src/tests/lib/services/icrc-index.services.spec.ts
…ality

Replace the deep-equality checks on new AnonymousIdentity() with
expect.any(AnonymousIdentity). A deep-equality check on the identity
couples the test to how getAnonymousIdentity() builds the instance.
The behavioral principal checks stay in place.
@yhabib
yhabib requested a lite review from Copilot September 4, 2026 13:12
Copilot AI dismissed their stale review, a newer Copilot review was requested September 4, 2026 13:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approved

The identity changes are narrowly scoped to validation calls and are covered by updated unit tests plus a targeted new e2e test that verifies request envelopes remain anonymous for URL-supplied canisters.

Review details
  • Files reviewed: 8/8 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants