Evervault Go SDK: Incomplete PCR Validation in Enclave Attestation for non-Evervault hosted Enclaves
Description
Evervault is a payment security solution. A vulnerability was identified in the evervault-go SDK’s attestation verification logic in versions of evervault-go prior to 1.3.2 that may allow incomplete documents to pass validation. This may cause the client to trust an enclave operator that does not meet expected integrity guarantees. The exploitability of this issue is limited in Evervault-hosted environments as an attacker would require the pre-requisite ability to serve requests from specific evervault domain names, following from our ACME challenge based TLS certificate acquisition pipeline. The vulnerability primarily affects applications which only check PCR8. Though the efficacy is also reduced for applications that check all PCR values, the impact is largely remediated by checking PCR 0, 1 and 2. The identified issue has been addressed in version 1.3.2 by validating attestation documents before storing in the cache, and replacing the naive equality checks with a new SatisfiedBy check. Those who useevervault-go to attest Enclaves that are hosted outside of Evervault environments and cannot upgrade have two possible workarounds available. Modify the application logic to fail verification if PCR8 is not explicitly present and non-empty and/or add custom pre-validation to reject documents that omit any required PCRs.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Evervault-go SDK versions before 1.3.2 allow incomplete attestation documents to pass validation, potentially trusting untrusted enclave operators.
Root
Cause The evervault-go SDK's attestation verification logic prior to version 1.3.2 contained flawed equality checks that did not properly validate the presence of all required PCR values in attestation documents. Specifically, the naive comparison allowed incomplete documents (e.g., missing certain PCRs) to pass verification, undermining integrity guarantees [1]. The fix introduced a SatisfiedBy check and pre-cache validation to ensure only complete documents are accepted [2].
Attack
Surface In Evervault-hosted environments, exploitability is limited because an attacker would need the ability to serve requests from specific Evervault domain names, which is mitigated by the ACME challenge-based TLS certificate acquisition pipeline [3]. However, for Enclaves hosted outside Evervault, the vulnerability is more easily exploitable, especially if the application only checks PCR8. The impact is partially reduced when all PCRs (0, 1, 2) are verified, but full remediation requires checking PCRs 0, 1, and 2 [1].
Impact
A successful attack could cause the client to trust an enclave operator that does not meet the expected integrity guarantees, potentially leading to unauthorized data access or tampering [3].
Mitigation
The vulnerability is fixed in version 1.3.2 of the SDK [2][4]. Users unable to upgrade, particularly those attesting enclaves outside Evervault, should apply workarounds: (1) modify application logic to fail verification if PCR8 is not explicitly present and non-empty, and/or (2) add custom pre-validation to reject documents that omit any required PCRs [3].
AI Insight generated on May 19, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/evervault/evervault-goGo | < 1.3.2 | 1.3.2 |
Affected products
2- Range: <1.3.2
- evervault/evervault-gov5Range: < 1.3.2
Patches
17c824d289bbaImprove correctness of PCR check in enclaves Go SDK (#48)
18 files changed · +348 −97
attestation/pcrs.go+37 −0 modified@@ -31,6 +31,43 @@ func (p *PCRs) Equal(pcrs PCRs) bool { return true } +func (p *PCRs) isMinimalPCRSet() bool { + return p.PCR0 != "" && p.PCR1 != "" && p.PCR2 != "" +} + +// Check if the receivedPCRs meet the expectations of the provided PCRs. +// The PCRs given as a parameter are expected to be the PCRs received from the remote enclave. +// +// The `receivedPCRs` are compared against the current PCR object which is assumed to be a +// partial set of expected PCR values. Any set PCR values are expected to be equal to the +// corresponding `receivedPCRs` value. +// +// If any expected PCR value is not equal, this function returns false. +func (p *PCRs) SatisfiedBy(receivedPCRs PCRs) bool { + // If the set of receivedPCRs has zero values for any of the minimally expected PCRs, short circuit + if !receivedPCRs.isMinimalPCRSet() { + return false + } + + if p.PCR0 != "" && p.PCR0 != receivedPCRs.PCR0 { + return false + } + + if p.PCR1 != "" && p.PCR1 != receivedPCRs.PCR1 { + return false + } + + if p.PCR2 != "" && p.PCR2 != receivedPCRs.PCR2 { + return false + } + + if p.PCR8 != "" && p.PCR8 != receivedPCRs.PCR8 { + return false + } + + return true +} + // IsEmpty checks if all PCRs in the struct are empty. func (p *PCRs) IsEmpty() bool { return p.PCR0 == "" && p.PCR1 == "" && p.PCR2 == "" && p.PCR8 == ""
attestation/pcrs_test.go+86 −0 added@@ -0,0 +1,86 @@ +package attestation_test + +import ( + "testing" + + "github.com/evervault/evervault-go/attestation" + "github.com/stretchr/testify/assert" +) + +// Confirm that a partial set of PCRs provided as expectation will match if their values +// align with the received values +func TestPartialPCRsMatchReceived(t *testing.T) { + t.Parallel() + + expectedPcrs := attestation.PCRs { + PCR0: "0", + PCR8: "8", + } + + receivedPcrs := attestation.PCRs { + PCR0: "0", + PCR1: "1", + PCR2: "2", + PCR8: "8", + } + + assert.True(t, expectedPcrs.SatisfiedBy(receivedPcrs), "Expect partial set of matching PCRs to result in True") +} + +// Confirm that the received PCRs are treated as non matching when any single value is unset +func TestFailureOnAnyMismatch(t *testing.T) { + t.Parallel() + + expectedPcrs := attestation.PCRs { + PCR0: "0", + PCR1: "1", + PCR2: "2", + PCR8: "1", + } + + receivedPcrs := attestation.PCRs { + PCR0: "0", + PCR1: "1", + PCR2: "2", + PCR8: "8", + } + + assert.False(t, expectedPcrs.SatisfiedBy(receivedPcrs), "Expect mismatch in any PCR value to return False") +} + +// Confirm that received PCRs are rejected if they do not contain a PCR value for which we have an expectation +func TestFailureOnAnyExpectedValueNotSet(t *testing.T) { + t.Parallel() + + expectedPcrs := attestation.PCRs { + PCR0: "0", + PCR8: "8", + } + + receivedPcrs := attestation.PCRs { + PCR0: "0", + PCR1: "1", + PCR2: "2", + } + + assert.False(t, expectedPcrs.SatisfiedBy(receivedPcrs), "Expect missing PCR in received value to return False") +} + +// Confirm that received PCRs must have at least PCRs 0, 1, and 2 set +func TestFailureOnAnyIncompleteReceivedPCRs(t *testing.T) { + t.Parallel() + + expectedPcrs := attestation.PCRs { + PCR0: "0", + PCR2: "2", + PCR8: "8", + } + + receivedPcrs := attestation.PCRs { + PCR0: "0", + PCR2: "2", + PCR8: "8", + } + + assert.False(t, expectedPcrs.SatisfiedBy(receivedPcrs), "Expect incomplete received PCRs to be rejected with False") +}
attest.go+31 −21 modified@@ -18,28 +18,35 @@ import ( const loadDocTimeout = 30 * time.Second // mapAttestationPCRs maps the attestation document's PCRs to a PCRs struct. -func mapAttestationPCRs(attestationPCRs nitrite.Document) attestation.PCRs { +// If PCR 0, 1 or 2 are empty, then this function returns an error. +func mapAttestationPCRs(attestationPCRs nitrite.Document) (attestation.PCRs, error) { // We verify a subset of non zero PCRs - PCR0 := hex.EncodeToString(attestationPCRs.PCRs[0]) - PCR1 := hex.EncodeToString(attestationPCRs.PCRs[1]) - PCR2 := hex.EncodeToString(attestationPCRs.PCRs[2]) - PCR8 := hex.EncodeToString(attestationPCRs.PCRs[8]) + PCR0, ok := attestationPCRs.PCRs[0] + if !ok { + return attestation.PCRs{}, fmt.Errorf("%w: expected PCR0 to be set", ErrMissingPCR) + } + PCR1, ok := attestationPCRs.PCRs[1] + if !ok { + return attestation.PCRs{}, fmt.Errorf("%w: expected PCR1 to be set", ErrMissingPCR) + } + PCR2, ok := attestationPCRs.PCRs[2] + if !ok { + return attestation.PCRs{}, fmt.Errorf("%w: expected PCR2 to be set", ErrMissingPCR) + } - return attestation.PCRs{PCR0: PCR0, PCR1: PCR1, PCR2: PCR2, PCR8: PCR8} + PCR8 := attestationPCRs.PCRs[8] + + return attestation.PCRs{ + PCR0: hex.EncodeToString(PCR0), + PCR1: hex.EncodeToString(PCR1), + PCR2: hex.EncodeToString(PCR2), + PCR8: hex.EncodeToString(PCR8), + }, nil } // attestCert attests the certificate against the expected PCRs. -func attestCert(certificate *x509.Certificate, expectedPCRs []attestation.PCRs, attestationDoc []byte) (bool, error) { - res, err := nitrite.Verify(attestationDoc, nitrite.VerifyOptions{CurrentTime: time.Now()}) - if err != nil { - return false, fmt.Errorf("unable to verify certificate %w", err) - } - - if !res.SignatureOK { - return false, ErrUnVerifiedSignature - } - - if verified := verifyPCRs(expectedPCRs, *res.Document); !verified { +func attestCert(certificate *x509.Certificate, expectedPCRs []attestation.PCRs, remoteAttestationDoc nitrite.Document) (bool, error) { + if verified := verifyPCRs(expectedPCRs, remoteAttestationDoc); !verified { return verified, nil } @@ -49,14 +56,17 @@ func attestCert(certificate *x509.Certificate, expectedPCRs []attestation.PCRs, return false, fmt.Errorf("failed to marshal publicKey to bytes %w", err) } - return bytes.Equal(pubKeyBytes, res.Document.UserData), nil + return bytes.Equal(pubKeyBytes, remoteAttestationDoc.UserData), nil } // verifyPCRs verifies the expected PCRs against the attestation document. -func verifyPCRs(expectedPCRs []attestation.PCRs, attestationDocument nitrite.Document) bool { - attestationPCRs := mapAttestationPCRs(attestationDocument) +func verifyPCRs(expectedPCRs []attestation.PCRs, remoteAttestationDoc nitrite.Document) bool { + attestationPCRs, err := mapAttestationPCRs(remoteAttestationDoc) + if err != nil { + return false + } for _, expectedPCR := range expectedPCRs { - if expectedPCR.Equal(attestationPCRs) { + if expectedPCR.SatisfiedBy(attestationPCRs) { return true } }
.changeset/clear-readers-start.md+7 −0 added@@ -0,0 +1,7 @@ +--- +"evervault-go": patch +--- + +In the event that a Nitro Enclave Attestation Document was returned omitting the standard set of PCRs, the expected PCRs check was unsound due to its treatment of empty values. + +This release corrects the check by validating attestation documents before storing in the cache, and replacing the naive equality checks with a new `SatisfiedBy` check. \ No newline at end of file
error.go+3 −0 modified@@ -15,6 +15,9 @@ var ErrNoPCRs = errors.New("Error: no PCRs where provided to attest with") // ErrInvalidPCRProvider is returned when an invalid PCR provider type is passed to CagesClient. var ErrInvalidPCRProvider = errors.New("unsupported type, must be array or callback: func() ([]types.PCRs, error)") +// ErrMissingPCR is retuned when an attestation document is missing an expected PCR value +var ErrMissingPCR = errors.New("missing pcr in attestation document") + // ErrAttestionFailure is retuned when a connection to a cage cannot be attested. var ErrAttestionFailure = errors.New("attestation failed")
.github/workflows/e2e.yml+3 −0 modified@@ -8,6 +8,9 @@ permissions: # Optional: allow read access to pull request. Use with `only-new-issues` option. # pull-requests: read +env: + GOEXPERIMENT: synctest + jobs: golangci: strategy:
.github/workflows/test.yml+3 −0 modified@@ -11,6 +11,9 @@ permissions: # Optional: allow read access to pull request. Use with `only-new-issues` option. # pull-requests: read +env: + GOEXPERIMENT: synctest + jobs: golangci: strategy:
go.mod+1 −1 modified@@ -1,6 +1,6 @@ module github.com/evervault/evervault-go -go 1.20 +go 1.24 require ( github.com/hf/nitrite v0.0.0-20211104000856-f9e0dcc73703
internal/attestation/attestation_cache.go+43 −6 modified@@ -11,11 +11,13 @@ import ( "net/url" "sync" "time" + + "github.com/hf/nitrite" ) type Cache struct { cageURL *url.URL - doc []byte + doc nitrite.Document mutex sync.RWMutex client http.Client ticker *time.Ticker @@ -37,7 +39,7 @@ func NewAttestationCache(cageDomain string, pollingInterval time.Duration) (*Cac cache := &Cache{ cageURL: cageURL, - doc: make([]byte, 0), + doc: nitrite.Document{}, mutex: sync.RWMutex{}, client: http.Client{}, ticker: time.NewTicker(pollingInterval), @@ -54,16 +56,15 @@ func NewAttestationCache(cageDomain string, pollingInterval time.Duration) (*Cac return cache, nil } -func (c *Cache) Set(doc []byte) { +func (c *Cache) Set(doc nitrite.Document) { c.mutex.Lock() defer c.mutex.Unlock() c.doc = doc } -func (c *Cache) Get() []byte { +func (c *Cache) Get() nitrite.Document { c.mutex.RLock() defer c.mutex.RUnlock() - return c.doc } @@ -128,14 +129,50 @@ func (c *Cache) handleError(message string, err error, attempt int) error { return fmt.Errorf("%s: %w", message, err) } +// To save on excess doc validation, the cache stores the validated document directly. +// The doc is verified using the nitrite library, and PCRs 0,1, and 2 are validated to be set and +// not empty. +// +// The document is not considered valid if: it has an invalid structure, invalid signature, or is missing an expected PCR. +// +// Further details on the verification can be found in [the nitrite docs](https://pkg.go.dev/github.com/hf/nitrite). +func validateAttestationDoc(doc []byte) (nitrite.Document, error) { + validatedDoc, err := nitrite.Verify(doc, nitrite.VerifyOptions{CurrentTime: time.Now()}) + if err != nil { + return nitrite.Document{}, fmt.Errorf("failed to verify loaded attestation doc: %v", err) + } + + if !validatedDoc.SignatureOK { + return nitrite.Document{}, fmt.Errorf("signature validation failed on attestation document") + } + + if _, ok := validatedDoc.Document.PCRs[0]; !ok { + return nitrite.Document{}, fmt.Errorf("PCR0 is required, but not set in received attestation document") + } + if _, ok := validatedDoc.Document.PCRs[1]; !ok { + return nitrite.Document{}, fmt.Errorf("PCR1 is required, but not set in received attestation document") + } + if _, ok := validatedDoc.Document.PCRs[2]; !ok { + return nitrite.Document{}, fmt.Errorf("PCR2 is required, but not set in received attestation document") + } + + return *validatedDoc.Document, nil +} + func (c *Cache) LoadDoc(ctx context.Context) { docBytes, err := c.getDoc(ctx) if err != nil { log.Printf("Could not get attestation doc: %v", err) return } - c.Set(docBytes) + validatedDoc, err := validateAttestationDoc(docBytes) + if err != nil { + log.Printf("Failed to verify loaded attestation doc: %v", err) + return + } + + c.Set(validatedDoc) } func (c *Cache) pollAPI() {
internal/attestation/attestation_cache_test.go+127 −0 added@@ -0,0 +1,127 @@ +package attestation_test + +import ( + "encoding/base64" + "fmt" + "net/http" + "os" + "testing" + "testing/synctest" + "time" + + "github.com/evervault/evervault-go/internal/attestation" + "github.com/jarcoal/httpmock" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + + +type Fixture struct { + Doc string + Timestamp string + Cert string + Digest string +} + +func NewFixture(t *testing.T, prefix string) Fixture { + doc, err := os.ReadFile(fmt.Sprintf("testdata/%s_attestation_doc.txt", prefix)) + require.NoError(t, err) + + expected_ts, err := os.ReadFile(fmt.Sprintf("testdata/%s_expected_timestamp.txt", prefix)) + require.NoError(t, err) + + expected_cert, err := os.ReadFile(fmt.Sprintf("testdata/%s_expected_cert.txt", prefix)) + require.NoError(t, err) + + loadedFixture := Fixture { + Doc: string(doc), + Timestamp: string(expected_ts), + Cert: string(expected_cert), + Digest: "SHA384", + } + return loadedFixture +} + +func TestAttestationDocCacheInit(t *testing.T) { + synctest.Run(func () { + format := "Jan 2 15:04:05 2006 MST" + fixedTime, err := time.Parse(format, "Sep 10 13:36:26 2025 UTC") // pinned time for fixture + require.NoError(t, err) + time.Sleep(time.Until(fixedTime)) + synctest.Wait() + + httpmock.Activate() + defer httpmock.DeactivateAndReset() + + assert := assert.New(t) + + firstFixture := NewFixture(t, "20250910133616") + httpmock.RegisterResponder("GET", "https://test.app-133.cage.evervault.com/.well-known/attestation", + httpmock.NewStringResponder(200, fmt.Sprintf(`{"attestation_doc": "%s"}`, firstFixture.Doc))) + + cache, err := attestation.NewAttestationCache("test.app-133.cage.evervault.com", 2700) + require.NoError(t, err) + + doc := cache.Get() + + assert.Equal(doc.Digest, firstFixture.Digest) + encodedCertificate := base64.StdEncoding.EncodeToString(doc.Certificate) + assert.Equal(encodedCertificate, firstFixture.Cert) + assert.Equal(fmt.Sprintf("%d",doc.Timestamp), firstFixture.Timestamp) + cache.StopPolling() + }) +} + +func TestAttestationDocCachePoll(t *testing.T) { + synctest.Run(func () { + format := "Jan 2 15:04:05 2006 MST" + fixedTime, err := time.Parse(format, "Sep 10 13:36:26 2025 UTC") // pinned time for fixture + require.NoError(t, err) + time.Sleep(time.Until(fixedTime)) + synctest.Wait() + + httpmock.Activate() + defer httpmock.DeactivateAndReset() + + assert := assert.New(t) + + callCount := 0 + + firstFixture := NewFixture(t, "20250910133616") + secondFixture := NewFixture(t, "20250910141940") + + responder := httpmock.Responder(func(req *http.Request) (*http.Response, error) { + callCount++ + if callCount == 1 { + return httpmock.NewStringResponse(200, fmt.Sprintf(`{"attestation_doc": "%s"}`, firstFixture.Doc)), nil + } + return httpmock.NewStringResponse(200, fmt.Sprintf(`{"attestation_doc": "%s"}`, secondFixture.Doc)), nil + }) + + httpmock.RegisterResponder("GET", "https://test.app-133.cage.evervault.com/.well-known/attestation", responder) + + duration := 60 * time.Second + cache, err := attestation.NewAttestationCache("test.app-133.cage.evervault.com", duration) + require.NoError(t, err) + + doc := cache.Get() + assert.Equal(doc.Digest, firstFixture.Digest) + encodedCertificate := base64.StdEncoding.EncodeToString(doc.Certificate) + assert.Equal(encodedCertificate, firstFixture.Cert) + assert.Equal(fmt.Sprintf("%d",doc.Timestamp), firstFixture.Timestamp) + + secondFixtureFixedTime, err := time.Parse(format, "Sep 10 14:19:40 2025 UTC") // pinned time for fixture + require.NoError(t, err) + + time.Sleep(time.Until(secondFixtureFixedTime)) + synctest.Wait() + + newDoc := cache.Get() + + assert.Equal(newDoc.Digest, secondFixture.Digest) + newDocEncodedCertificate := base64.StdEncoding.EncodeToString(newDoc.Certificate) + assert.Equal(newDocEncodedCertificate, secondFixture.Cert) + assert.Equal(fmt.Sprintf("%d",newDoc.Timestamp), secondFixture.Timestamp) + cache.StopPolling() + }) +}
internal/attestation/attestation_doc_test.go+0 −69 removed@@ -1,69 +0,0 @@ -package attestation_test - -import ( - "encoding/base64" - "net/http" - "testing" - "time" - - "github.com/evervault/evervault-go/internal/attestation" - "github.com/jarcoal/httpmock" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestAttestationDocCacheInit(t *testing.T) { - httpmock.Activate() - defer httpmock.DeactivateAndReset() - - assert := assert.New(t) - - httpmock.RegisterResponder("GET", "https://test.app-133.cage.evervault.com/.well-known/attestation", - httpmock.NewStringResponder(200, `{"attestation_doc": "1aGVsbG8gd29ybGQ"}`)) - - cache, err := attestation.NewAttestationCache("test.app-133.cage.evervault.com", 2700) - require.NoError(t, err) - doc := cache.Get() - - decodedDoc, err := base64.StdEncoding.DecodeString("1aGVsbG8gd29ybGQ") - require.NoError(t, err) - assert.Contains(string(doc), string(decodedDoc)) - cache.StopPolling() -} - -func TestAttestationDocCachePoll(t *testing.T) { - httpmock.Activate() - defer httpmock.DeactivateAndReset() - - assert := assert.New(t) - - callCount := 0 - - responder := httpmock.Responder(func(req *http.Request) (*http.Response, error) { - callCount++ - if callCount == 1 { - return httpmock.NewStringResponse(200, `{"attestation_doc": "ZnJpZGF5"}`), nil - } - return httpmock.NewStringResponse(200, `{"attestation_doc": "bW9uZGF5"}`), nil - }) - - httpmock.RegisterResponder("GET", "https://test.app-133.cage.evervault.com/.well-known/attestation", responder) - - duration := 500 * time.Millisecond - cache, err := attestation.NewAttestationCache("test.app-133.cage.evervault.com", duration) - require.NoError(t, err) - - doc := cache.Get() - decodedDoc, err := base64.StdEncoding.DecodeString("ZnJpZGF5") - require.NoError(t, err) - assert.Contains(string(doc), string(decodedDoc)) - - time.Sleep(1 * time.Second) - - newDoc := cache.Get() - newDecodedDoc, err := base64.StdEncoding.DecodeString("bW9uZGF5") - require.NoError(t, err) - - assert.Contains(string(newDoc), string(newDecodedDoc)) - cache.StopPolling() -}
internal/attestation/testdata/20250910133616_attestation_doc.txt+1 −0 added@@ -0,0 +1 @@ +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 \ No newline at end of file
internal/attestation/testdata/20250910133616_expected_cert.txt+1 −0 added@@ -0,0 +1 @@ +MIICezCCAgGgAwIBAgIQAZky8D334DcAAAAAaMFqnTAKBggqhkjOPQQDAzCBjjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxDzANBgNVBAoMBkFtYXpvbjEMMAoGA1UECwwDQVdTMTkwNwYDVQQDDDBpLTAyNTU3OTBjY2ZjOTdhZGJiLnVzLWVhc3QtMS5hd3Mubml0cm8tZW5jbGF2ZXMwHhcNMjUwOTEwMTIxMDAyWhcNMjUwOTEwMTUxMDA1WjCBkzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxDzANBgNVBAoMBkFtYXpvbjEMMAoGA1UECwwDQVdTMT4wPAYDVQQDDDVpLTAyNTU3OTBjY2ZjOTdhZGJiLWVuYzAxOTkzMmYwM2RmN2UwMzcudXMtZWFzdC0xLmF3czB2MBAGByqGSM49AgEGBSuBBAAiA2IABLMGLeNBE54dWDKmPpHIOnACghP2cDj7OuN4dbFlNhidpo+bLcRl0qYCzyM2mAKIEDgrToTsV4Yh7qeoQ/xYhhPo2zlMabpguKxcTvl0Zlzeei2++taQd7pNk3UbBkK1DKMdMBswDAYDVR0TAQH/BAIwADALBgNVHQ8EBAMCBsAwCgYIKoZIzj0EAwMDaAAwZQIxAPK7HAIfYO039MKeNDKvBTbBO10BtMRSxFD9k6H2t7V/3JtMYt1SD38cY1OUkYESYQIwbponphOwxYPZOHOqqPXcX0P/fmW2UgQ8HB58fZYXoSp4Rus9KEmlIMf+aSOGoVVG \ No newline at end of file
internal/attestation/testdata/20250910133616_expected_timestamp.txt+1 −0 added@@ -0,0 +1 @@ +1757511245681 \ No newline at end of file
internal/attestation/testdata/20250910141940_attestation_doc.txt+1 −0 added@@ -0,0 +1 @@ +hEShATgioFkSXb9pbW9kdWxlX2lkeCdpLTAyNTU3OTBjY2ZjOTdhZGJiLWVuYzAxOTkzMmYwM2RmN2UwMzdmZGlnZXN0ZlNIQTM4NGl0aW1lc3RhbXAbAAABmTP/fZBkcGNyc7AAWDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABWDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACWDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADWDCunV+tkn2JW42SbWdmFyYvzhv4vGWXcBeRIa1irTUEbyYxcBvlSMV0JlIfL75j/LAEWDDcUPz0is5J7vROB11fsXYK7KCvjBU+svX3G+cNlpekdskCjG9w5pnUp9TAGNAdI2wFWDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGWDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHWDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIWDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJWDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKWDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALWDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMWDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANWDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOWDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPWDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABrY2VydGlmaWNhdGVZAn8wggJ7MIICAaADAgECAhABmTLwPffgNwAAAABowWqdMAoGCCqGSM49BAMDMIGOMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTEPMA0GA1UECgwGQW1hem9uMQwwCgYDVQQLDANBV1MxOTA3BgNVBAMMMGktMDI1NTc5MGNjZmM5N2FkYmIudXMtZWFzdC0xLmF3cy5uaXRyby1lbmNsYXZlczAeFw0yNTA5MTAxMjEwMDJaFw0yNTA5MTAxNTEwMDVaMIGTMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTEPMA0GA1UECgwGQW1hem9uMQwwCgYDVQQLDANBV1MxPjA8BgNVBAMMNWktMDI1NTc5MGNjZmM5N2FkYmItZW5jMDE5OTMyZjAzZGY3ZTAzNy51cy1lYXN0LTEuYXdzMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEswYt40ETnh1YMqY+kcg6cAKCE/ZwOPs643h1sWU2GJ2mj5stxGXSpgLPIzaYAogQOCtOhOxXhiHup6hD/FiGE+jbOUxpumC4rFxO+XRmXN56Lb761pB3uk2TdRsGQrUMox0wGzAMBgNVHRMBAf8EAjAAMAsGA1UdDwQEAwIGwDAKBggqhkjOPQQDAwNoADBlAjEA8rscAh9g7Tf0wp40Mq8FNsE7XQG0xFLEUP2Tofa3tX/cm0xi3VIPfxxjU5SRgRJhAjBumiemE7DFg9k4c6qo9dxfQ/9+ZbZSBDwcHnx9lhehKnhG6z0oSaUgx/5pI4ahVUZoY2FidW5kbGWEWQIVMIICETCCAZagAwIBAgIRAPkxdWgbkK/hHUbMtOTn+FYwCgYIKoZIzj0EAwMwSTELMAkGA1UEBhMCVVMxDzANBgNVBAoMBkFtYXpvbjEMMAoGA1UECwwDQVdTMRswGQYDVQQDDBJhd3Mubml0cm8tZW5jbGF2ZXMwHhcNMTkxMDI4MTMyODA1WhcNNDkxMDI4MTQyODA1WjBJMQswCQYDVQQGEwJVUzEPMA0GA1UECgwGQW1hem9uMQwwCgYDVQQLDANBV1MxGzAZBgNVBAMMEmF3cy5uaXRyby1lbmNsYXZlczB2MBAGByqGSM49AgEGBSuBBAAiA2IABPwCVOumCMHzaHDimtqQvkY4MpJzbolL//Zy2YlES1BR5TSksfbb48C8WBoyt7F2Bw7eEtaaP+ohG2bnUs990d0JX28TcPQXCEPZ3BABIeTPYwEoCWZEh8l5YoQwTcU/9KNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUkCW1DdkFR+eWw5b6cp3PmanfS5YwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2kAMGYCMQCjfy+Rocm9Xue4YnwWmNJVA44fA0P5W2OpYow9OYCVRaEevL8uO1XYru5xtMPWrfMCMQCi85sWBbJwKKXdS6BptQFuZbT73o/gBh1qUxl/nNr12UO8Yfwr6wPLb+6NIwLz3/ZZAsIwggK+MIICRKADAgECAhBr5R/bTt2VF5fkzVoqimGBMAoGCCqGSM49BAMDMEkxCzAJBgNVBAYTAlVTMQ8wDQYDVQQKDAZBbWF6b24xDDAKBgNVBAsMA0FXUzEbMBkGA1UEAwwSYXdzLm5pdHJvLWVuY2xhdmVzMB4XDTI1MDkwODAxMzI1NVoXDTI1MDkyODAyMzI1NVowZDELMAkGA1UEBhMCVVMxDzANBgNVBAoMBkFtYXpvbjEMMAoGA1UECwwDQVdTMTYwNAYDVQQDDC1jOWFmNTk5NGY0Njg3YjEzLnVzLWVhc3QtMS5hd3Mubml0cm8tZW5jbGF2ZXMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQSPiCGGl1WVe81bNFkUJybrHWQfd0qqg8/Y1TgAX+cfprl+JF2KRtgHhTY/TOhSh/Rf2mY/nXRLKjewDXbntcNOcSgff+ACLpiNfkGJkUqz8QOt0itz/dCfoA0qDMzy7OjgdUwgdIwEgYDVR0TAQH/BAgwBgEB/wIBAjAfBgNVHSMEGDAWgBSQJbUN2QVH55bDlvpync+Zqd9LljAdBgNVHQ4EFgQUmKKfhAnPqAFGjBmpywtXxS60L90wDgYDVR0PAQH/BAQDAgGGMGwGA1UdHwRlMGMwYaBfoF2GW2h0dHA6Ly9hd3Mtbml0cm8tZW5jbGF2ZXMtY3JsLnMzLmFtYXpvbmF3cy5jb20vY3JsL2FiNDk2MGNjLTdkNjMtNDJiZC05ZTlmLTU5MzM4Y2I2N2Y4NC5jcmwwCgYIKoZIzj0EAwMDaAAwZQIxAOz5VLxdP8uhPkut9ACx7rZCPxZNiAkBFO3gT1l5EiL8IvvJ1k8qR3nM4Y6Y8WXotAIwA5XpsenCUXdU3AbJ+SSvyINRmSVZnNfjboIb6UuID0GU0kBDl5tnCucwkXZuXb4mWQMYMIIDFDCCApugAwIBAgIRAOrg8lanTTtsPkUTK/nurEUwCgYIKoZIzj0EAwMwZDELMAkGA1UEBhMCVVMxDzANBgNVBAoMBkFtYXpvbjEMMAoGA1UECwwDQVdTMTYwNAYDVQQDDC1jOWFmNTk5NGY0Njg3YjEzLnVzLWVhc3QtMS5hd3Mubml0cm8tZW5jbGF2ZXMwHhcNMjUwOTEwMDI1ODUzWhcNMjUwOTE1MjI1ODUzWjCBiTE8MDoGA1UEAwwzMzNiMGRmNTVmYmM0YmFlYy56b25hbC51cy1lYXN0LTEuYXdzLm5pdHJvLWVuY2xhdmVzMQwwCgYDVQQLDANBV1MxDzANBgNVBAoMBkFtYXpvbjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAldBMRAwDgYDVQQHDAdTZWF0dGxlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEnwpO5E8o3qVOIob5FD6X4gwdk3fvbBg098Fim3CbB2od66Nswb9qqzaD4N0fTBahArlDHzrzyKezf28H8urm9HOv8lF/i7Ys6K0bAPzWgFjOTeo/+cFGNNzW8jJ26KAlo4HqMIHnMBIGA1UdEwEB/wQIMAYBAf8CAQEwHwYDVR0jBBgwFoAUmKKfhAnPqAFGjBmpywtXxS60L90wHQYDVR0OBBYEFJQscYgUrWnJolXzpbkpZORCjU+3MA4GA1UdDwEB/wQEAwIBhjCBgAYDVR0fBHkwdzB1oHOgcYZvaHR0cDovL2NybC11cy1lYXN0LTEtYXdzLW5pdHJvLWVuY2xhdmVzLnMzLnVzLWVhc3QtMS5hbWF6b25hd3MuY29tL2NybC8wYmMxNWJlNy00MjEyLTQ1NDctOGIzZC03NWNjYzNmOTYxNjIuY3JsMAoGCCqGSM49BAMDA2cAMGQCMF4VVclvyhAs4YASqxgHPOQU94BcJPcbwIKdRAL5dtD0AcwOzALVi89f/CWEnPC0WQIwZmcNxAohN1TU3g6BObYh8fj2AHXcE6S4rF0CAdHn0dC4byOegKGJLUGqfeHFPbQ/WQLCMIICvjCCAkWgAwIBAgIVAPYq93dT2ULwpPG/bDYH23tPR+BJMAoGCCqGSM49BAMDMIGJMTwwOgYDVQQDDDMzM2IwZGY1NWZiYzRiYWVjLnpvbmFsLnVzLWVhc3QtMS5hd3Mubml0cm8tZW5jbGF2ZXMxDDAKBgNVBAsMA0FXUzEPMA0GA1UECgwGQW1hem9uMQswCQYDVQQGEwJVUzELMAkGA1UECAwCV0ExEDAOBgNVBAcMB1NlYXR0bGUwHhcNMjUwOTEwMDk1NzA1WhcNMjUwOTExMDk1NzA1WjCBjjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxDzANBgNVBAoMBkFtYXpvbjEMMAoGA1UECwwDQVdTMTkwNwYDVQQDDDBpLTAyNTU3OTBjY2ZjOTdhZGJiLnVzLWVhc3QtMS5hd3Mubml0cm8tZW5jbGF2ZXMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARBvWPGu3pGaqMGlX0RF/DBFkkoEhQAlbUXY7hjvjG0OsdmCMwUcQjPUr2+vQXGftgjVuvGRYbvRRJHQTuRv2BhIwXkQNyScFPj78kyh8QE+bOi8qRBGiRmzLcpUowuIYCjZjBkMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgIEMB0GA1UdDgQWBBQC9kzTRrSaBEsDU85wHkKrqqZdpzAfBgNVHSMEGDAWgBSULHGIFK1pyaJV86W5KWTkQo1PtzAKBggqhkjOPQQDAwNnADBkAjA25OnM9jnF5jy88y0mVeyGF0D76b+51k1ozOkcjtCadaDPAM7lXgmlrj1O//50GNECMCNlBoKge08BOfVH6LYcSxgFoYHSQiLq3i3nDapgvrCmo3nXyGPaa8jvYRb62qgK7WpwdWJsaWNfa2V59ml1c2VyX2RhdGFYWzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABEOqYx5g5HMtOm1JaQZ9wc8ymCw6CUUljTi+WhcGW9kNnoQLpxlRRk+ni/xlnMCogU1MR9sVUmR261UfAL2oP5Flbm9uY2VZAQAhZQ30jb6ia83oonZgHm7v4gWu+BSEFjohXg8DYLvOK5CcluYkd8Q5BOftFtdZt8ZnpDrzZefgif8RpNjZD2zhoGubVScZ2qfb0rlBDOSb/whivp8ZRZ310MSM3Q93Kr77scXot9vDw+mrz12eTc8w1sffYFqIVeONxV0X1Smn5Y9x0ahWeglC2VxP16hkgReyhbfqLXgDW+kt8fHAbBR6JFTZ0azp+xo7wcKB6yNNEVUQtNqo9mhauoC/3DiOFMnyONq8mqKSnQ6ynnxfnkDoJBf6SHutQp+yE5VPiSVpGxcFRKdUIBJhXRkauysm/SkmDI7Doj4AfYbThrfei7zK/1hg3liYMihTHY0GdOeWTsd19er8PYmezjEbs3izpGc+792knTA9m0AAr80GtiFAJcV95C8b29j8STTSxAGbjJZ4Ii4vTErLiuW8w5msTrKuh4RgJGtYQN9yxolZFJc6iskC \ No newline at end of file
internal/attestation/testdata/20250910141940_expected_cert.txt+1 −0 added@@ -0,0 +1 @@ +MIICezCCAgGgAwIBAgIQAZky8D334DcAAAAAaMFqnTAKBggqhkjOPQQDAzCBjjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxDzANBgNVBAoMBkFtYXpvbjEMMAoGA1UECwwDQVdTMTkwNwYDVQQDDDBpLTAyNTU3OTBjY2ZjOTdhZGJiLnVzLWVhc3QtMS5hd3Mubml0cm8tZW5jbGF2ZXMwHhcNMjUwOTEwMTIxMDAyWhcNMjUwOTEwMTUxMDA1WjCBkzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxDzANBgNVBAoMBkFtYXpvbjEMMAoGA1UECwwDQVdTMT4wPAYDVQQDDDVpLTAyNTU3OTBjY2ZjOTdhZGJiLWVuYzAxOTkzMmYwM2RmN2UwMzcudXMtZWFzdC0xLmF3czB2MBAGByqGSM49AgEGBSuBBAAiA2IABLMGLeNBE54dWDKmPpHIOnACghP2cDj7OuN4dbFlNhidpo+bLcRl0qYCzyM2mAKIEDgrToTsV4Yh7qeoQ/xYhhPo2zlMabpguKxcTvl0Zlzeei2++taQd7pNk3UbBkK1DKMdMBswDAYDVR0TAQH/BAIwADALBgNVHQ8EBAMCBsAwCgYIKoZIzj0EAwMDaAAwZQIxAPK7HAIfYO039MKeNDKvBTbBO10BtMRSxFD9k6H2t7V/3JtMYt1SD38cY1OUkYESYQIwbponphOwxYPZOHOqqPXcX0P/fmW2UgQ8HB58fZYXoSp4Rus9KEmlIMf+aSOGoVVG \ No newline at end of file
internal/attestation/testdata/20250910141940_expected_timestamp.txt+1 −0 added@@ -0,0 +1 @@ +1757514005904 \ No newline at end of file
README.md+1 −0 modified@@ -22,6 +22,7 @@ The list of required env vars is: - `EV_SYNTHETIC_ENDPOINT_URL` - an existing Relay destination for the given app - `EV_INITIALIZATION_ERROR_FUNCTION_NAME` - the name of a function which will fail when invoked - `EV_FUNCTION_NAME` - the name of a function which will run when invoked +- `GOEXPERIMENT=synctest` - enable synctest experiment on Go 1.24 ### Running the Tests
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-88h9-77c7-p6w4ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-64186ghsaADVISORY
- github.com/evervault/evervault-go/commit/7c824d289bba11ec0bea46a338023f5b128bbb28ghsax_refsource_MISCWEB
- github.com/evervault/evervault-go/pull/48ghsax_refsource_MISCWEB
- github.com/evervault/evervault-go/security/advisories/GHSA-88h9-77c7-p6w4ghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.