CVE-2025-47934 Overview
CVE-2025-47934 is a signature verification spoofing vulnerability in OpenPGP.js, a JavaScript implementation of the OpenPGP protocol. The flaw allows attackers to craft maliciously modified messages that pass signature verification while containing data that was never actually signed. This enables complete forgery of inline-signed messages and signed-and-encrypted messages, undermining the fundamental integrity guarantees that cryptographic signatures are designed to provide.
Critical Impact
Attackers can spoof signature verifications, causing openpgp.verify and openpgp.decrypt to return valid verification results for data that was never legitimately signed, enabling complete message forgery.
Affected Products
- OpenPGP.js versions 5.0.1 through 5.11.2
- OpenPGP.js versions 6.0.0 through 6.1.0
- Applications using openpgp.verify for inline-signed message verification
- Applications using openpgp.decrypt with verificationKeys for signed-and-encrypted messages
Discovery Timeline
- 2025-05-19 - CVE-2025-47934 published to NVD
- 2025-05-21 - Last updated in NVD database
Technical Details for CVE-2025-47934
Vulnerability Analysis
This vulnerability represents a critical flaw in the cryptographic message verification pipeline of OpenPGP.js. The library's openpgp.verify and openpgp.decrypt functions can be manipulated to return data that differs from what was originally signed while still reporting a valid signature verification result. This breaks the fundamental non-repudiation and integrity properties that digital signatures are meant to guarantee.
The attack requires the adversary to possess a single valid message signature (either inline or detached) along with the plaintext data that was legitimately signed. With these components, an attacker can construct a new inline-signed message or signed-and-encrypted message containing arbitrary data of their choosing. The affected OpenPGP.js functions will incorrectly validate these forged messages as legitimately signed.
Detached signature verifications are not affected by this vulnerability since no signed data is returned in that verification mode.
Root Cause
The root cause is classified as CWE-347: Improper Verification of Cryptographic Signature. The vulnerability stems from improper message mutation during the signature verification process. The original code directly mutated the message packets object (msg.packets) during stream processing, which allowed the returned data to become desynchronized from the data that was actually verified by the cryptographic signature.
The vulnerable code pushed packets directly to msg.packets using msg.packets.push(...), which modified the original message object. This mutation created a window where the signature verification could be performed against one set of data while the function returned different data to the caller.
Attack Vector
The attack is network-accessible and requires no authentication or user interaction. An attacker with knowledge of a valid signature and its corresponding signed plaintext can:
- Obtain a legitimate inline-signed or detached signature along with the original signed data
- Construct a new message containing attacker-controlled content
- Package the malicious content with the valid signature in a way that exploits the verification desynchronization
- Submit the crafted message to an application using vulnerable OpenPGP.js versions
- The application's verification returns success while exposing the attacker's forged data
The security patch addresses this by creating an immutable copy of the packets during verification:
// Security patch in src/message.js - Don't mutate message during verification
if (literalDataList.length !== 1) {
throw new Error('Can only verify message with one literal data packet.');
}
- if (stream.isArrayStream(msg.packets.stream)) {
- msg.packets.push(...await stream.readToEnd(msg.packets.stream, _ => _ || []));
+ let packets = msg.packets;
+ if (stream.isArrayStream(packets.stream)) {
+ packets = packets.concat(await streamReadToEnd(packets.stream, _ => _ || []));
}
- const onePassSigList = msg.packets.filterByTag(enums.packet.onePassSignature).reverse();
- const signatureList = msg.packets.filterByTag(enums.packet.signature);
- if (onePassSigList.length && !signatureList.length && util.isStream(msg.packets.stream) && !stream.isArrayStream(msg.packets.stream)) {
+ const onePassSigList = packets.filterByTag(enums.packet.onePassSignature).reverse();
+ const signatureList = packets.filterByTag(enums.packet.signature);
+ if (onePassSigList.length && !signatureList.length && util.isStream(packets.stream) && !isArrayStream(packets.stream)) {
await Promise.all(onePassSigList.map(async onePassSig => {
onePassSig.correspondingSig = new Promise((resolve, reject) => {
onePassSig.correspondingSigResolve = resolve;
Source: GitHub Commit 43f5f4e
Detection Methods for CVE-2025-47934
Indicators of Compromise
- Messages passing signature verification where the extracted content differs from expected signed data
- Unusual patterns in inline-signed messages with mismatched literal data packets
- Applications accepting signed messages from untrusted sources that exhibit unexpected content
- Cryptographic verification logs showing successful validations for messages with anomalous packet structures
Detection Strategies
- Audit application dependencies for OpenPGP.js versions between 5.0.1 and 5.11.2 or 6.0.0 and 6.1.0
- Implement secondary verification by manually extracting and re-verifying signatures using detached verification mode
- Monitor for discrepancies between signed message content and expected payload formats
- Review application logs for patterns indicating message tampering or unexpected signature verification successes
Monitoring Recommendations
- Enable verbose logging for OpenPGP.js signature verification operations in production environments
- Implement application-level integrity checks that validate message content against expected schemas or formats after signature verification
- Monitor package manager update notifications for OpenPGP.js security releases
- Consider implementing canary messages to detect signature verification tampering in high-security environments
How to Mitigate CVE-2025-47934
Immediate Actions Required
- Upgrade OpenPGP.js to version 5.11.3 or 6.1.1 immediately
- Audit all applications using openpgp.verify with inline-signed messages for potential compromise
- Review applications using openpgp.decrypt with verificationKeys parameter
- Implement the workarounds described below if immediate patching is not possible
Patch Information
Security patches are available in OpenPGP.js versions 5.11.3 and 6.1.1. The fix ensures that message packets are not mutated during verification by using immutable copies. Organizations should update to these versions through their package management systems. The patches are available via:
For additional technical details, refer to the GitHub Security Advisory GHSA-8qff-qr5q-5pr8.
Workarounds
- For inline-signed messages: Extract the message and signature(s) from the message returned by openpgp.readMessage, then verify each signature as a detached signature by passing it along with a new message created using openpgp.createMessage containing only the data to openpgp.verify
- For signed-and-encrypted messages: Perform decryption and verification as two separate steps by first calling openpgp.decrypt without the verificationKeys parameter, then passing the returned signature(s) and a new message containing the decrypted data (created via openpgp.createMessage) to openpgp.verify
- Consider temporarily blocking acceptance of inline-signed messages from untrusted sources until patching is complete
- Implement application-level content validation as a defense-in-depth measure
# Update OpenPGP.js via npm
npm update openpgp@5.11.3
# or for version 6.x
npm update openpgp@6.1.1
# Verify installed version
npm list openpgp
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

