Skip to content

🚨 [security] Update thor-devkit 2.0.3 β†’ 2.2.0 (minor)#12

Open
depfu[bot] wants to merge 1 commit intomasterfrom
depfu/update/npm/thor-devkit-2.2.0
Open

🚨 [security] Update thor-devkit 2.0.3 β†’ 2.2.0 (minor)#12
depfu[bot] wants to merge 1 commit intomasterfrom
depfu/update/npm/thor-devkit-2.2.0

Conversation

@depfu
Copy link
Copy Markdown

@depfu depfu bot commented Mar 24, 2026


Welcome to Depfu πŸ‘‹

This is one of the first three pull requests with dependency updates we've sent your way. We tried to start with a few easy patch-level updates. Hopefully your tests will pass and you can merge this pull request without too much risk. This should give you an idea how Depfu works in general.

After you merge your first pull request, we'll send you a few more. We'll never open more than seven PRs at the same time so you're not getting overwhelmed with updates.

Let us know if you have any questions. Thanks so much for giving Depfu a try!



🚨 Your current dependencies have known security vulnerabilities 🚨

This dependency update fixes known security vulnerabilities. Please see the details below and assess their impact carefully. We recommend to merge and deploy this as soon as possible!


Here is everything you need to know about this update. Please take a good look at what changed and the test results before merging this pull request.

What changed?

✳️ thor-devkit (2.0.3 β†’ 2.2.0) Β· Repo

Release Notes

2.2.0

Security

  • Fixed critical vulnerability (GHSA-vjh7-7g9h-fjfh): replaced @vechain/ethers@4.0.27-5 with ethers@^6.13.0, eliminating the elliptic@6.5.4 ECDSA private key extraction risk. Total npm audit vulnerabilities reduced from 23 (including 4 critical, 11 high) to 3 low.

Dependencies

  • Replaced @vechain/ethers with ethers@^6 for ABI encoding/decoding, HD wallet, keystore, and mnemonic.
  • Replaced tslint with eslint@9 + @typescript-eslint@8.
  • Upgraded mocha@5 β†’ mocha@11, nyc@14 β†’ nyc@18, typescript@3 β†’ typescript@5.

Tests

  • Added encode/decode coverage for bytes32[], uint256[3], bare tuple, and tuple[] types.

CI

  • Node.js test matrix updated to [22, lts/*, latest].
  • Removed SonarCloud job.

2.1.1

What's Changed

  • Fixed compatibility issue with ESM module.

Full Changelog: v2.1.0...v2.1.1

2.0.9

What's Changed

New Contributors

Full Changelog: v2.0.8...v2.0.9

2.0.8

What's Changed

Full Changelog: v2.0.7...v2.0.8

2.0.7

What's Changed

  • add named imports for Buffer module by @grenos in #50

New Contributors

Full Changelog: v2.0.6...v2.0.7

2.0.6

What's Changed

Full Changelog: v2.0.5...v2.0.6

2.0.5

What's Changed

  • add abi v2 support for non-indexed value in event by @libotony in #45

Full Changelog: v2.0.4...v2.0.5

2.0.4

What's Changed

Full Changelog: v2.0.3...v2.0.4

Does any of this look wrong? Please let us know.

Commits

See the full diff on Github. The new version differs by 48 commits:

↗️ aes-js (indirect, 3.0.0 β†’ 4.0.0-beta.5) Β· Repo

Sorry, we couldn't find anything useful about this release.

↗️ blakejs (indirect, 1.1.1 β†’ 1.2.1) Β· Repo

Commits

See the full diff on Github. The new version differs by 8 commits:

↗️ bn.js (indirect, 4.12.0 β†’ 4.12.3) Β· Repo Β· Changelog

Security Advisories 🚨

🚨 bn.js affected by an infinite loop

This affects versions of the package bn.js before 4.12.3 and 5.2.3. Calling maskn(0) on any BN instance corrupts the internal state, causing toString(), divmod(), and other methods to enter an infinite loop, hanging the process indefinitely.

Commits

See the full diff on Github. The new version differs by 7 commits:

↗️ elliptic (indirect, 6.5.4 β†’ 6.6.1) Β· Repo

Security Advisories 🚨

🚨 Elliptic's private key extraction in ECDSA upon signing a malformed input (e.g. a string)

Summary

Private key can be extracted from ECDSA signature upon signing a malformed input (e.g. a string or a number), which could e.g. come from JSON network input

Note that elliptic by design accepts hex strings as one of the possible input types

Details

In this code:

    <tbody>
    <tr class="border-0">
      <td id="L101" class="blob-num border-0 px-3 py-0 color-bg-default" data-line-number="101"></td>
      <td id="LC101" class="blob-code border-0 px-3 py-0 color-bg-default blob-code-inner js-file-line">  </td>
    </tr>

    <tr class="border-0">
      <td id="L102" class="blob-num border-0 px-3 py-0 color-bg-default" data-line-number="102"></td>
      <td id="LC102" class="blob-code border-0 px-3 py-0 color-bg-default blob-code-inner js-file-line"> <span class="pl-c">// Zero-extend key to provide enough entropy</span> </td>
    </tr>

    <tr class="border-0">
      <td id="L103" class="blob-num border-0 px-3 py-0 color-bg-default" data-line-number="103"></td>
      <td id="LC103" class="blob-code border-0 px-3 py-0 color-bg-default blob-code-inner js-file-line"> <span class="pl-k">var</span> <span class="pl-s1">bytes</span> <span class="pl-c1">=</span> <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-c1">n</span><span class="pl-kos">.</span><span class="pl-en">byteLength</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span> </td>
    </tr>

    <tr class="border-0">
      <td id="L104" class="blob-num border-0 px-3 py-0 color-bg-default" data-line-number="104"></td>
      <td id="LC104" class="blob-code border-0 px-3 py-0 color-bg-default blob-code-inner js-file-line"> <span class="pl-k">var</span> <span class="pl-s1">bkey</span> <span class="pl-c1">=</span> <span class="pl-s1">key</span><span class="pl-kos">.</span><span class="pl-en">getPrivate</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">toArray</span><span class="pl-kos">(</span><span class="pl-s">'be'</span><span class="pl-kos">,</span> <span class="pl-s1">bytes</span><span class="pl-kos">)</span><span class="pl-kos">;</span> </td>
    </tr>

    <tr class="border-0">
      <td id="L105" class="blob-num border-0 px-3 py-0 color-bg-default" data-line-number="105"></td>
      <td id="LC105" class="blob-code border-0 px-3 py-0 color-bg-default blob-code-inner js-file-line">  </td>
    </tr>

    <tr class="border-0">
      <td id="L106" class="blob-num border-0 px-3 py-0 color-bg-default" data-line-number="106"></td>
      <td id="LC106" class="blob-code border-0 px-3 py-0 color-bg-default blob-code-inner js-file-line"> <span class="pl-c">// Zero-extend nonce to have the same byte size as N</span> </td>
    </tr>

    <tr class="border-0">
      <td id="L107" class="blob-num border-0 px-3 py-0 color-bg-default" data-line-number="107"></td>
      <td id="LC107" class="blob-code border-0 px-3 py-0 color-bg-default blob-code-inner js-file-line"> <span class="pl-k">var</span> <span class="pl-s1">nonce</span> <span class="pl-c1">=</span> <span class="pl-s1">msg</span><span class="pl-kos">.</span><span class="pl-en">toArray</span><span class="pl-kos">(</span><span class="pl-s">'be'</span><span class="pl-kos">,</span> <span class="pl-s1">bytes</span><span class="pl-kos">)</span><span class="pl-kos">;</span> </td>
    </tr>
</tbody>
msg = this._truncateToN(new BN(msg, 16));

msg is a BN instance after conversion, but nonce is an array, and different BN instances could generate equivalent arrays after conversion.

Meaning that a same nonce could be generated for different messages used in signing process, leading to k reuse, leading to private key extraction from a pair of signatures

Such a message can be constructed for any already known message/signature pair, meaning that the attack needs only a single malicious message being signed for a full key extraction

While signing unverified attacker-controlled messages would be problematic itself (and exploitation of this needs such a scenario), signing a single message still should not leak the private key

Also, message validation could have the same bug (out of scope for this report, but could be possible in some situations), which makes this attack more likely when used in a chain

PoC

k reuse example

import elliptic from 'elliptic'

const { ec: EC } = elliptic

const privateKey = crypto.getRandomValues(new Uint8Array(32))
const curve = 'ed25519' // or any other curve, e.g. secp256k1
const ec = new EC(curve)
const prettyprint = ({ r, s }) => r: <span class="pl-s1"><span class="pl-kos">${</span><span class="pl-s1">r</span><span class="pl-kos">}</span></span>, s: <span class="pl-s1"><span class="pl-kos">${</span><span class="pl-s1">s</span><span class="pl-kos">}</span></span>
const sig0 = prettyprint(ec.sign(Buffer.alloc(32, 1), privateKey)) // array of ones
const sig1 = prettyprint(ec.sign('01'.repeat(32), privateKey)) // same message in hex form
const sig2 = prettyprint(ec.sign('-' + '01'.repeat(32), privateKey)) // same r, different s
console.log({ sig0, sig1, sig2 })

Full attack

This doesn't include code for generation/recovery on a purpose (bit it's rather trivial)

import elliptic from 'elliptic'

const { ec: EC } = elliptic

const privateKey = crypto.getRandomValues(new Uint8Array(32))
const curve = 'secp256k1' // or any other curve, e.g. ed25519
const ec = new EC(curve)

// Any message, e.g. previously known signature
const msg0 = crypto.getRandomValues(new Uint8Array(32))
const sig0 = ec.sign(msg0, privateKey)

// Attack
const msg1 = funny(msg0) // this is a string here, but can also be of other non-Uint8Array types
const sig1 = ec.sign(msg1, privateKey)

const something = extract(msg0, sig0, sig1, curve)

console.log('Curve:', curve)
console.log('Typeof:', typeof msg1)
console.log('Keys equal?', Buffer.from(privateKey).toString('hex') === something)
const rnd = crypto.getRandomValues(new Uint8Array(32))
const st = (x) => JSON.stringify(x)
console.log('Keys equivalent?', st(ec.sign(rnd, something).toDER()) === st(ec.sign(rnd, privateKey).toDER()))
console.log('Orig key:', Buffer.from(privateKey).toString('hex'))
console.log('Restored:', something)

Output:

Curve: secp256k1
Typeof: string
Keys equal? true
Keys equivalent? true
Orig key: c7870f7eb3e8fd5155d5c8cdfca61aa993eed1fbe5b41feef69a68303248c22a
Restored: c7870f7eb3e8fd5155d5c8cdfca61aa993eed1fbe5b41feef69a68303248c22a

Similar for ed25519, but due to low n, the key might not match precisely but is nevertheless equivalent for signing:

Curve: ed25519
Typeof: string
Keys equal? false
Keys equivalent? true
Orig key: f1ce0e4395592f4de24f6423099e022925ad5d2d7039b614aaffdbb194a0d189
Restored: 01ce0e4395592f4de24f6423099e0227ec9cb921e3b7858581ec0d26223966a6

restored is equal to orig mod N.

Impact

Full private key extraction when signing a single malicious message (that passes JSON.stringify/JSON.parse)

🚨 Valid ECDSA signatures erroneously rejected in Elliptic

The Elliptic prior to 6.6.0 for Node.js, in its for ECDSA implementation, does not correctly verify valid signatures if the hash contains at least four leading 0 bytes and when the order of the elliptic curve's base point is smaller than the hash, because of an _truncateToN anomaly. This leads to valid signatures being rejected. Legitimate transactions or communications may be incorrectly flagged as invalid.

🚨 Elliptic's verify function omits uniqueness validation

The Elliptic package 6.5.5 for Node.js for EDDSA implementation does not perform the required check if the signature proof(s) is within the bounds of the order n of the base point of the elliptic curve, leading to signature malleability. Namely, the verify function in lib/elliptic/eddsa/index.js omits sig.S().gte(sig.eddsa.curve.n) || sig.S().isNeg() validation.

This vulnerability could have a security-relevant impact if an application relies on the uniqueness of a signature.

🚨 Elliptic allows BER-encoded signatures

In the Elliptic package 6.5.6 for Node.js, ECDSA signature malleability occurs because BER-encoded signatures are allowed.

🚨 Elliptic's ECDSA missing check for whether leading bit of r and s is zero

In the Elliptic package 6.5.6 for Node.js, ECDSA signature malleability occurs because there is a missing check for whether the leading bit of r and s is zero.

🚨 Elliptic's EDDSA missing signature length check

In the Elliptic package 6.5.6 for Node.js, EDDSA signature malleability occurs because there is a missing signature length check, and thus zero-valued bytes can be removed or appended.

Commits

See the full diff on Github. The new version differs by 11 commits:

↗️ hash.js (indirect, 1.1.3 β†’ 1.1.7) Β· Repo

Commits

See the full diff on Github. The new version differs by 10 commits:

πŸ†• @​adraffy/ens-normalize (added, 1.10.1)

πŸ†• @​noble/curves (added, 1.2.0)

πŸ†• @​noble/hashes (added, 1.3.2)

πŸ†• ethers (added, 6.16.0)

πŸ†• tslib (added, 2.7.0)

πŸ†• undici-types (added, 6.19.8)

πŸ†• ws (added, 8.17.1)

πŸ—‘οΈ @​vechain/ethers (removed)

πŸ—‘οΈ scrypt-js (removed)

πŸ—‘οΈ setimmediate (removed)

πŸ—‘οΈ uuid (removed)

πŸ—‘οΈ xmlhttprequest (removed)


Depfu Status

Depfu will automatically keep this PR conflict-free, as long as you don't add any commits to this branch yourself. You can also trigger a rebase manually by commenting with @depfu rebase.

All Depfu comment commands
@​depfu rebase
Rebases against your default branch and redoes this update
@​depfu recreate
Recreates this PR, overwriting any edits that you've made to it
@​depfu merge
Merges this PR once your tests are passing and conflicts are resolved
@​depfu cancel merge
Cancels automatic merging of this PR
@​depfu close
Closes this PR and deletes the branch
@​depfu reopen
Restores the branch and reopens this PR (if it's closed)
@​depfu pause
Ignores all future updates for this dependency and closes this PR
@​depfu pause [minor|major]
Ignores all future minor/major updates for this dependency and closes this PR
@​depfu resume
Future versions of this dependency will create PRs again (leaves this PR as is)

@depfu depfu bot added the depfu label Mar 24, 2026
@codesandbox
Copy link
Copy Markdown

codesandbox bot commented Mar 24, 2026

Review or Edit in CodeSandbox

Open the branch in Web Editor β€’ VS Code β€’ Insiders

Open Preview

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 24, 2026

⚠️ No Changeset found

Latest commit: 74699dc

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@socket-security
Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatedthor-devkit@​2.0.3 ⏡ 2.2.082 -1210010089 +9100 +31

View full report

@entelligence-ai-pr-reviews
Copy link
Copy Markdown



Confidence Score: 5/5 - Safe to Merge

  • No critical or significant issues found
  • 1/2 changed files reviewed (50% coverage)

@openzeppelin-code
Copy link
Copy Markdown

🚨 [security] Update thor-devkit 2.0.3 β†’ 2.2.0 (minor)

Generated at commit: 74699dc93af1126f325f1f16b21a2c03c8904dfc

🚨 Report Summary

Severity Level Results
Contracts Critical
High
Medium
Low
Note
Total
0
0
0
0
0
0
Dependencies Critical
High
Medium
Low
Note
Total
0
0
0
0
0
0

For more details view the full report in OpenZeppelin Code Inspector

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants