GHSA-JFC7-64V2-MR8C

Vulnerability from github – Published: 2026-06-26 19:11 – Updated: 2026-06-26 19:11
VLAI
Summary
@sigstore/core has DSSE payloadType type-binding failure
Details

Impact

The preAuthEncoding function in @sigstore/core uses Node.js 'ascii' encoding when converting the PAE (Pre-Authentication Encoding) string to bytes. This allows payloadType to be mutated after signing without invalidating the signature, breaking the type-binding guarantee that DSSE is designed to provide.

In packages/core/src/dsse.ts, the PAE function builds a string containing payloadType and then encodes it with Buffer.from(prefix, 'ascii').

In Node.js, 'ascii' encoding for string-to-Buffer is equivalent to 'latin1', which truncates characters above U+00FF to their low byte. This means for any ASCII character, there exist Unicode characters (at U+01xx, U+02xx, etc.) that produce the identical encoded byte:

Original Codepoint Mutant Codepoint Encoded byte
t U+0074 Ŵ U+0174 0x74
e U+0065 ť U+0165 0x65

An attacker can substitute every character in payloadType with a Unicode variant whose low byte matches, producing identical PAE bytes and a passing signature verification.

Additionally, payloadType.length returns the JavaScript string length (UTF-16 code units) rather than the UTF-8 byte length required by the DSSE spec, though this is only a contributing factor for non-ASCII types.

Reproduction

const { preAuthEncoding } = require('@sigstore/core/dist/dsse.js');
const payload = Buffer.from('hello world');

const original = preAuthEncoding('text/plain', payload);
// U+01xx chars whose low bytes match the original ASCII chars
const mutant = preAuthEncoding('\u0174\u0165\u0178\u0174/\u0170\u016c\u0161\u0169\u016e', payload);

console.log('PAE bytes equal:', original.equals(mutant)); // true — should be false
Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 3.2.0"
      },
      "package": {
        "ecosystem": "npm",
        "name": "@sigstore/core"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "3.2.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-48758"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-347"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-26T19:11:19Z",
    "nvd_published_at": null,
    "severity": "MODERATE"
  },
  "details": "### Impact\nThe `preAuthEncoding` function in `@sigstore/core` uses Node.js `\u0027ascii\u0027` encoding when converting the PAE (Pre-Authentication Encoding) string to bytes. This allows `payloadType` to be mutated after signing without invalidating the signature, breaking the type-binding guarantee that DSSE is designed to provide.\n\nIn `packages/core/src/dsse.ts`, the PAE function builds a string containing `payloadType` and then encodes it with `Buffer.from(prefix, \u0027ascii\u0027)`.\n\nIn Node.js, `\u0027ascii\u0027` encoding for string-to-Buffer is equivalent to `\u0027latin1\u0027`, which **truncates characters above U+00FF to their low byte**. This means for any ASCII character, there exist Unicode characters (at U+01xx, U+02xx, etc.) that produce the identical encoded byte:\n\n| Original | Codepoint | Mutant | Codepoint | Encoded byte |\n|----------|-----------|--------|-----------|--------------|\n| `t`      | U+0074    | `\u0174`    | U+0174    | `0x74`       |\n| `e`      | U+0065    | `\u0165`    | U+0165    | `0x65`       |\n\nAn attacker can substitute every character in `payloadType` with a Unicode variant whose low byte matches, producing **identical PAE bytes** and a passing signature verification.\n\nAdditionally, `payloadType.length` returns the JavaScript string length (UTF-16 code units) rather than the UTF-8 byte length required by the DSSE spec, though this is only a contributing factor for non-ASCII types.\n\n#### Reproduction\n\n```javascript\nconst { preAuthEncoding } = require(\u0027@sigstore/core/dist/dsse.js\u0027);\nconst payload = Buffer.from(\u0027hello world\u0027);\n\nconst original = preAuthEncoding(\u0027text/plain\u0027, payload);\n// U+01xx chars whose low bytes match the original ASCII chars\nconst mutant = preAuthEncoding(\u0027\\u0174\\u0165\\u0178\\u0174/\\u0170\\u016c\\u0161\\u0169\\u016e\u0027, payload);\n\nconsole.log(\u0027PAE bytes equal:\u0027, original.equals(mutant)); // true \u2014 should be false\n```",
  "id": "GHSA-jfc7-64v2-mr8c",
  "modified": "2026-06-26T19:11:20Z",
  "published": "2026-06-26T19:11:19Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/sigstore/sigstore-js/security/advisories/GHSA-jfc7-64v2-mr8c"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/sigstore/sigstore-js"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L",
      "type": "CVSS_V3"
    }
  ],
  "summary": "@sigstore/core has DSSE payloadType type-binding failure"
}



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…

Detection rules are retrieved from Rulezet.

Loading…

Loading…