Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 

README.md

CVE-2026-76078 — Probo: broken access control in the public e-signature API

  • Advisory: GHSA-22xj-f767-ppw6 · CVE-2026-76078
  • Affected: go.probo.inc/probo ≤ 0.224.0 (verified on probod v0.222.2, a3b65a644, default config) · Fixed: 0.224.0
  • Severity: Low (GitHub) · reported as Moderate, CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:N/I:H/A:N ≈ 5.9 · CWE-862 / CWE-639
  • Status: publicly disclosed and fixed. Reported by Pig-Tail through coordinated disclosure.

Summary

The public Trust Center GraphQL API exposes acceptElectronicSignature and recordSigningEvent, both gated only by @authentication(required: PRESENT) @sessionOnly — any self-provisioned trust center identity can call them. Neither the resolvers nor the service verify that the signature belongs to the caller.

Any authenticated trust-center visitor holding another visitor's signature GID can therefore:

  1. complete that visitor's NDA signature — overwriting signer name / IP / user-agent with attacker data and setting the status to Accepted, which triggers the sealing worker to issue a completion certificate; and
  2. inject arbitrary audit-trail events into any signature's log.

Both defeat the non-repudiation and integrity guarantees of the e-signature flow.

Root cause

pkg/server/api/trust/v1/nda_resolvers.go:24-83 passes input.SignatureID straight to esign.Service.AcceptSignature. In pkg/esign/service.go:312-404 the tenant scope is derived from the client-supplied GID itself:

scope := coredata.NewScopeFromObjectID(req.SignatureID)   // tenant taken from attacker input
// ... loads the signature by GID
// ... never compares signature.SignerEmail to req.SignerEmail
// ... never looks up the caller's TrustCenterAccess

Contrast with ViewerSignature (nda_resolvers.go:116-140), which correctly resolves via access.ElectronicSignatureID bound to identity.ID. The guard that exists on the read path is simply absent on the two write paths.

Reachability

  1. POST /graphql on any published trust center — @authentication(required: PRESENT) is satisfied by any self-provisioned identity (free signup).
  2. No Authorize() call, no TrustCenterAccess lookup, no email binding check.
  3. AcceptSignature loads the signature by GID, overwrites the signer fields and sets Accepted.

Preconditions

  • A self-provisioned identity on any published trust center.
  • The target signature GID — the same GID-precondition class the vendor accepted as Moderate for CVE-2026-63505 / GHSA-c74x-79w6-63jh.

Fix

Resolve the caller's TrustCenterAccess by (compliancePage.ID, identity.ID) and require access.ElectronicSignatureID == SignatureID; additionally compare signature.SignerEmail to req.SignerEmail in AcceptSignature. Resolved in probo 0.224.0.

Write-up only. No standalone runnable PoC is published for this finding — exercising it requires a live trust center with a second visitor's signature GID. Refer to the linked advisory for full technical detail.