{
  "variant_id": "cve-2026-48816-forged-set-decoupled-bypass",
  "created_at": "2026-07-02",
  "variant_summary": "Bypass of the @sigstore/verify 3.1.1 fix (commit f074710) for CVE-2026-48816. The fix gates getTLogTimestamp() on inclusionPromise *presence* and relies on verifyTLogs()->verifyTLogSET() to authenticate integratedTime. A SignedEntity supplied to the public Verifier.verify(SignedEntity) API in which the timestamp-providing tlog entry is NOT present in tlogEntries (decoupled) carries a FORGED inclusionPromise + attacker-chosen integratedTime: the presence-check passes, verifyTLogSET never runs (verifyTLogs iterates the empty tlogEntries), and verify() succeeds -- accepting an EXPIRED certificate at the attacker-chosen time. Reproduces the original CVE's expired-cert-accepted impact on the FIXED version. Through the standard toSignedEntity(bundle) path the entries are coupled and a forged SET is rejected (negative control), so the fix is effective for the normal bundle path but its own logic does not enforce that coupling.",
  "relation": "newer_version_sibling",
  "origin_kind": "pruva_variant",
  "repository": "https://github.com/sigstore/sigstore-js",
  "submitted_target": {
    "target_kind": "npm_package",
    "commit_sha": "7845532f9d17f6f765363dbee82b01bd159fb52b",
    "version": "3.1.0",
    "ref": "f074710^ (parent of fix)",
    "display": "@sigstore/verify 3.1.0 (vulnerable commit 7845532)"
  },
  "variant_target": {
    "target_kind": "npm_package",
    "commit_sha": "f074710a91ea9260a9ac2142345634579843a3cd",
    "version": "3.1.1",
    "ref": "f074710 (fix commit)",
    "display": "@sigstore/verify 3.1.1 (fixed commit f074710) -- bypass reproduced here"
  },
  "same_root_cause_confidence": "high",
  "same_surface_confidence": "medium",
  "claimed_surface": "library_api",
  "validated_surface": "library_api",
  "required_entrypoint_kind": "library_api",
  "required_entrypoint_detail": "Public Verifier.verify(SignedEntity) API in @sigstore/verify, supplied a SignedEntity whose sole transparency-log timestamp references a tlog entry that is NOT present in entity.tlogEntries (decoupled construction). Identical in shape to the original CVE PoC Part B (tlogEntries:[], sole transparency-log timestamp). The standard toSignedEntity(bundle) helper couples timestamps and tlogEntries and is NOT vulnerable to this bypass.",
  "attacker_controlled_input": "tlogEntries[].integratedTime (attacker-chosen) and inclusionPromise.signedEntryTimestamp (forged/arbitrary bytes) on a tlog entry that appears in entity.timestamps but not in entity.tlogEntries, supplied via Verifier.verify(SignedEntity)",
  "trigger_path": "Verifier.verify (packages/verify/src/verifier.ts:73) -> verifyTimestamps (:87) -> getTLogTimestamp (packages/verify/src/timestamp/index.ts:44) passes the fix's !entry.inclusionPromise presence-check (:48) because a FORGED inclusionPromise is present, returning the attacker-chosen integratedTime as a trusted timestamp (:55); verifySigningKey/verifyCertificate (packages/verify/src/key/index.ts) accepts an EXPIRED certificate at that time; verifyTLogs (packages/verify/src/verifier.ts:165) iterates entity.tlogEntries (empty) -> no-op, so verifyTLogSET (packages/verify/src/tlog/set.ts:33) never validates the forged SET; verifySignature succeeds -> verify() returns success on the FIXED version",
  "observed_impact_class": "other",
  "exploitability_confidence": "medium",
  "evidence_scope": "realistic_harness",
  "runtime_manifest_present": true,
  "end_to_end_target_reached": true,
  "inferred": false,
  "claim_block_reason": null,
  "blocking_mitigation": null,
  "file_path": "packages/verify/src/timestamp/index.ts",
  "line_start": 44,
  "line_end": 59,
  "secondary_anchors": [
    {
      "file_path": "packages/verify/src/verifier.ts",
      "line_start": 73,
      "line_end": 77
    },
    {
      "file_path": "packages/verify/src/verifier.ts",
      "line_start": 165,
      "line_end": 181
    },
    {
      "file_path": "packages/verify/src/tlog/set.ts",
      "line_start": 33,
      "line_end": 60
    },
    {
      "file_path": "packages/verify/src/bundle/index.ts",
      "line_start": 28,
      "line_end": 57
    }
  ],
  "review_scope_paths": [
    "packages/verify/src/timestamp/index.ts",
    "packages/verify/src/verifier.ts",
    "packages/verify/src/tlog/index.ts",
    "packages/verify/src/tlog/set.ts",
    "packages/verify/src/bundle/index.ts"
  ],
  "artifact_refs": {
    "variant_manifest": "bundle/vuln_variant/variant_manifest.json",
    "validation_verdict": "bundle/vuln_variant/validation_verdict.json",
    "runtime_manifest": "bundle/vuln_variant/runtime_manifest.json",
    "repro_log": "bundle/logs/vuln_variant_fixed.log",
    "root_cause_equivalence": "bundle/vuln_variant/root_cause_equivalence.json",
    "reproducer": [
      "bundle/vuln_variant/reproduction_steps.sh",
      "bundle/vuln_variant/variant_harness.ts"
    ]
  }
}