Monitor vulnerabilities like this one.
Sign up free to get alerted when software you use is affected.
8.3
Deno's AES GCM encryption fails to verify authentication tags
JLSEC-2026-108
Summary
Deno's AES encryption doesn't check if encrypted data has been tampered with, which can lead to data being compromised. This affects Deno's AES-256-GCM and AES-128-GCM encryption. To protect your data, update to a version that fixes this issue.
What to do
- Update deno_jll to version 2.2.6+0.
Affected software
| Vendor | Product | Affected versions | Fix available |
|---|---|---|---|
| – | deno_jll | > 2.0.0+0 , <= 2.2.6+0 | 2.2.6+0 |
Original title
Deno's AES GCM authentication tags are not verified
Original description
### Summary
This affects AES-256-GCM and AES-128-GCM in Deno, introduced by commit [0d1beed](https://github.com/denoland/deno/commit/0d1beed). Specifically, the authentication tag is not being validated. This means tampered ciphertexts or incorrect keys might not be detected, which breaks the guarantees expected from AES-GCM. Older versions of Deno correctly threw errors in such cases, as does Node.js.
Without authentication tag verification, AES-GCM degrades to essentially CTR mode, removing integrity protection. Authenticated data set with set_aad is also affected, as it is incorporated into the GCM hash (ghash) but this too is not validated, rendering AAD checks ineffective.
### PoC
```ts
import { Buffer } from "node:buffer";
import {
createCipheriv,
createDecipheriv,
randomBytes,
scrypt,
} from "node:crypto";
type Encrypted = {
salt: string;
iv: string;
enc: string;
authTag: string;
};
const deriveKey = (key: string, salt: Buffer) =>
new Promise<Buffer>((res, rej) =>
scrypt(key, salt, 32, (err, k) => {
if (err) rej(err);
else res(k);
})
);
async function encrypt(text: string, key: string): Promise<Encrypted> {
const salt = randomBytes(32);
const k = await deriveKey(key, salt);
const iv = randomBytes(16);
const enc = createCipheriv("aes-256-gcm", k, iv);
const ciphertext = enc.update(text, "binary", "binary") + enc.final("binary");
return {
salt: salt.toString("binary"),
iv: iv.toString("binary"),
enc: ciphertext,
authTag: enc.getAuthTag().toString("binary"),
};
}
async function decrypt(enc: Encrypted, key: string) {
const k = await deriveKey(key, Buffer.from(enc.salt, "binary"));
const dec = createDecipheriv("aes-256-gcm", k, Buffer.from(enc.iv, "binary"));
const out = dec.update(enc.enc, "binary", "binary");
dec.setAuthTag(Buffer.from(enc.authTag, "binary"));
return out + dec.final("binary");
}
const test = await encrypt("abcdefghi", "key");
test.enc = "";
console.log(await decrypt(test, "")); // no error
```
### Impact
While discovered through experimentation, authentication failures that should raise errors may be silently ignored.
This affects AES-256-GCM and AES-128-GCM in Deno, introduced by commit [0d1beed](https://github.com/denoland/deno/commit/0d1beed). Specifically, the authentication tag is not being validated. This means tampered ciphertexts or incorrect keys might not be detected, which breaks the guarantees expected from AES-GCM. Older versions of Deno correctly threw errors in such cases, as does Node.js.
Without authentication tag verification, AES-GCM degrades to essentially CTR mode, removing integrity protection. Authenticated data set with set_aad is also affected, as it is incorporated into the GCM hash (ghash) but this too is not validated, rendering AAD checks ineffective.
### PoC
```ts
import { Buffer } from "node:buffer";
import {
createCipheriv,
createDecipheriv,
randomBytes,
scrypt,
} from "node:crypto";
type Encrypted = {
salt: string;
iv: string;
enc: string;
authTag: string;
};
const deriveKey = (key: string, salt: Buffer) =>
new Promise<Buffer>((res, rej) =>
scrypt(key, salt, 32, (err, k) => {
if (err) rej(err);
else res(k);
})
);
async function encrypt(text: string, key: string): Promise<Encrypted> {
const salt = randomBytes(32);
const k = await deriveKey(key, salt);
const iv = randomBytes(16);
const enc = createCipheriv("aes-256-gcm", k, iv);
const ciphertext = enc.update(text, "binary", "binary") + enc.final("binary");
return {
salt: salt.toString("binary"),
iv: iv.toString("binary"),
enc: ciphertext,
authTag: enc.getAuthTag().toString("binary"),
};
}
async function decrypt(enc: Encrypted, key: string) {
const k = await deriveKey(key, Buffer.from(enc.salt, "binary"));
const dec = createDecipheriv("aes-256-gcm", k, Buffer.from(enc.iv, "binary"));
const out = dec.update(enc.enc, "binary", "binary");
dec.setAuthTag(Buffer.from(enc.authTag, "binary"));
return out + dec.final("binary");
}
const test = await encrypt("abcdefghi", "key");
test.enc = "";
console.log(await decrypt(test, "")); // no error
```
### Impact
While discovered through experimentation, authentication failures that should raise errors may be silently ignored.
osv CVSS4.0
8.3
- https://github.com/denoland/deno/commit/0d1beed URL
- https://github.com/denoland/deno/commit/4f27d7cdc02e3edfb9d36275341fb8185d6e99ed URL
- https://github.com/denoland/deno/commit/a4003a5292bd0affefad3ecb24a8732886900f67 URL
- https://github.com/denoland/deno/security/advisories/GHSA-2x3r-hwv5-p32x URL
- https://nvd.nist.gov/vuln/detail/CVE-2025-24015 URL
- https://github.com/denoland/deno/commit/0d1beed2e3633d71d5e288e0382b85be361ec13d URL
- https://github.com/advisories/GHSA-2x3r-hwv5-p32x URL
Published: 14 Apr 2026 · Updated: 14 Apr 2026 · First seen: 14 Apr 2026