Summary
The module-level cachedPolicyData variable is checked before each policy fetch, but multiple concurrent callers can all pass the null check before any of them has resolved and written the cache, triggering redundant parallel downloads.
Root Cause
icp-brasil.ts:145-147:
if (cachedPolicyData) {
return cachedPolicyData;
}
// ... await fetch(...) ← multiple callers reach here simultaneously
cachedPolicyData = { ... };
JavaScript's event loop means the await fetch(...) yields control. Two concurrent calls both read cachedPolicyData === null, both proceed to fetch, and both write the result. Not a data-corruption bug (last write wins with same data), but causes unnecessary network traffic.
Affected Files
libraries/e-signature/src/icp-brasil.ts:145-201 — unguarded concurrent fetch
Evidence
// Concurrent batch signing with pades-icp-brasil:
await Promise.all([
signPdf(pdf1, { policy: "pades-icp-brasil", ... }),
signPdf(pdf2, { policy: "pades-icp-brasil", ... }),
]);
// Both calls reach downloadAndParsePolicyDocument simultaneously
// Both see cachedPolicyData === null
// Both fetch the policy document
Suggested Fix
Summary
The module-level
cachedPolicyDatavariable is checked before each policy fetch, but multiple concurrent callers can all pass thenullcheck before any of them has resolved and written the cache, triggering redundant parallel downloads.Root Cause
icp-brasil.ts:145-147:JavaScript's event loop means the
await fetch(...)yields control. Two concurrent calls both readcachedPolicyData === null, both proceed to fetch, and both write the result. Not a data-corruption bug (last write wins with same data), but causes unnecessary network traffic.Affected Files
libraries/e-signature/src/icp-brasil.ts:145-201— unguarded concurrent fetchEvidence
Suggested Fix