High severity7.3OSV Advisory· Published Aug 14, 2025· Updated Apr 15, 2026
CVE-2025-55195
CVE-2025-55195
Description
@std/toml is the Deno Standard Library. Prior to version 1.0.9, an attacker can pollute the prototype chain in Node.js runtime and Browser when parsing untrusted TOML data, thus achieving Prototype Pollution (PP) vulnerability. This is because the library is merging an untrusted object with an empty object, which by default the empty object has the prototype chain. This issue has been patched in version 1.0.9.
Affected products
1Patches
26b92bffee728chore: release 2025.08.13 (#6795)
9 files changed · +48 −13
collections/deno.json+1 −1 modified@@ -1,6 +1,6 @@ { "name": "@std/collections", - "version": "1.1.2", + "version": "1.1.3", "exports": { ".": "./mod.ts", "./aggregate-groups": "./aggregate_groups.ts",
import_map.json+6 −6 modified@@ -13,7 +13,7 @@ "@std/cache": "jsr:@std/cache@^0.2.0", "@std/cbor": "jsr:@std/cbor@^0.1.8", "@std/cli": "jsr:@std/cli@^1.0.21", - "@std/collections": "jsr:@std/collections@^1.1.2", + "@std/collections": "jsr:@std/collections@^1.1.3", "@std/crypto": "jsr:@std/crypto@^1.0.5", "@std/csv": "jsr:@std/csv@^1.0.6", "@std/data-structures": "jsr:@std/data-structures@^1.0.9", @@ -34,16 +34,16 @@ "@std/log": "jsr:@std/log@^0.224.14", "@std/media-types": "jsr:@std/media-types@^1.1.0", "@std/msgpack": "jsr:@std/msgpack@^1.0.3", - "@std/net": "jsr:@std/net@^1.0.4", - "@std/path": "jsr:@std/path@^1.1.1", + "@std/net": "jsr:@std/net@^1.0.5", + "@std/path": "jsr:@std/path@^1.1.2", "@std/regexp": "jsr:@std/regexp@^1.0.1", "@std/random": "jsr:@std/random@^0.1.2", "@std/semver": "jsr:@std/semver@^1.0.5", - "@std/streams": "jsr:@std/streams@^1.0.10", + "@std/streams": "jsr:@std/streams@^1.0.11", "@std/tar": "jsr:@std/tar@^0.1.7", "@std/testing": "jsr:@std/testing@^1.0.15", - "@std/text": "jsr:@std/text@^1.0.15", - "@std/toml": "jsr:@std/toml@^1.0.8", + "@std/text": "jsr:@std/text@^1.0.16", + "@std/toml": "jsr:@std/toml@^1.0.9", "@std/ulid": "jsr:@std/ulid@^1.0.0", "@std/uuid": "jsr:@std/uuid@^1.0.9", "@std/webgpu": "jsr:@std/webgpu@^0.224.8",
net/deno.json+1 −1 modified@@ -1,6 +1,6 @@ { "name": "@std/net", - "version": "1.0.4", + "version": "1.0.5", "exports": { ".": "./mod.ts", "./get-available-port": "./get_available_port.ts",
path/deno.json+1 −1 modified@@ -1,6 +1,6 @@ { "name": "@std/path", - "version": "1.1.1", + "version": "1.1.2", "exports": { ".": "./mod.ts", "./basename": "./basename.ts",
Releases.md+36 −0 modified@@ -1,3 +1,39 @@ +### 2025.08.13 + +#### @std/assert 1.0.14 (patch) + +- chore(assert,expect): bump assert and expect versions (#6791) + +#### @std/collections 1.1.3 (patch) + +- test(collections): fix mapValues mutation test so it actually tests mutation + (#6780) + +#### @std/expect 1.0.17 (patch) + +- chore(assert,expect): bump assert and expect versions (#6791) + +#### @std/net 1.0.5 (patch) + +- feat(net/unstable): add ip utilities (#6765) + +#### @std/path 1.1.2 (patch) + +- fix(path): improve regex in `isGlob` (#6764) + +#### @std/streams 1.0.11 (patch) + +- refactor(streams/unstable): toByteStream to make use of autoAllocateChunkSize + (#6781) + +#### @std/text 1.0.16 (patch) + +- feat(text/unstable): add `trimBy` functions (#6778) + +#### @std/toml 1.0.9 (patch) + +- fix(toml): prevent prototype pollution by table key + ### 2025.07.29 #### @std/async 1.0.14 (patch)
streams/deno.json+1 −1 modified@@ -1,6 +1,6 @@ { "name": "@std/streams", - "version": "1.0.10", + "version": "1.0.11", "exports": { ".": "./mod.ts", "./unstable-abort-stream": "./unstable_abort_stream.ts",
text/deno.json+1 −1 modified@@ -1,6 +1,6 @@ { "name": "@std/text", - "version": "1.0.15", + "version": "1.0.16", "exports": { ".": "./mod.ts", "./closest-string": "./closest_string.ts",
toml/deno.json+1 −1 modified@@ -1,6 +1,6 @@ { "name": "@std/toml", - "version": "1.0.8", + "version": "1.0.9", "exports": { ".": "./mod.ts", "./parse": "./parse.ts",
toml/parse_test.ts+0 −1 modified@@ -857,7 +857,6 @@ Deno.test({ }, }); - Deno.test({ name: "parse() doesn't pollute prototype with __proto__", async fn() {
540662cfd6d7Merge commit from fork
2 files changed · +33 −9
toml/_parser.ts+8 −8 modified@@ -154,7 +154,7 @@ function failure(): Failure { */ export function unflat( keys: string[], - values: unknown = {}, + values: unknown = { __proto__: null }, ): Record<string, unknown> { return keys.reduceRight( (acc, key) => ({ [key]: acc }), @@ -336,7 +336,7 @@ function merge( return (scanner: Scanner): ParseResult<Record<string, unknown>> => { const result = parser(scanner); if (!result.ok) return failure(); - let body = {}; + let body = { __proto__: null }; for (const record of result.body) { if (typeof record === "object" && record !== null) { body = deepMerge(body, record); @@ -744,11 +744,11 @@ export function inlineTable( scanner.nextUntilChar(); if (scanner.char(1) === "}") { scanner.next(2); - return success({}); + return success({ __proto__: null }); } const pairs = surround("{", join(pair, ","), "}")(scanner); if (!pairs.ok) return failure(); - let table = {}; + let table = { __proto__: null } as Record<string, unknown>; for (const pair of pairs.body) { table = deepMerge(table, pair); } @@ -796,7 +796,7 @@ export function table(scanner: Scanner): ParseResult<Table> { return success({ type: "Table", keys: header.body, - value: b.ok ? b.body.value : {}, + value: b.ok ? b.body.value : { __proto__: null }, }); } @@ -813,16 +813,16 @@ export function tableArray( return success({ type: "TableArray", keys: header.body, - value: b.ok ? b.body.value : {}, + value: b.ok ? b.body.value : { __proto__: null }, }); } export function toml( scanner: Scanner, ): ParseResult<Record<string, unknown>> { const blocks = repeat(or([block, tableArray, table]))(scanner); - if (!blocks.ok) return success({}); - const body = blocks.body.reduce(deepAssign, {}); + if (!blocks.ok) return success({ __proto__: null }); + const body = blocks.body.reduce(deepAssign, { __proto__: null }); return success(body); }
toml/parse_test.ts+25 −1 modified@@ -1,5 +1,5 @@ // Copyright 2018-2025 the Deno authors. MIT license. -import { assertEquals, assertThrows } from "@std/assert"; +import { assert, assertEquals, assertThrows } from "@std/assert"; import { parse } from "./mod.ts"; Deno.test({ @@ -856,3 +856,27 @@ Deno.test({ assertThrows(() => parse("value = -inf_")); }, }); + + +Deno.test({ + name: "parse() doesn't pollute prototype with __proto__", + async fn() { + const testCode = ` + import { parse } from "${import.meta.resolve("./parse.ts")}"; + import { assertEquals } from "@std/assert"; + parse('[__proto__.isAdmin]'); + assertEquals({}.isAdmin, undefined, "Prototype pollution detected"); + parse('[[__proto__.arrayTable]]\\npolluted = true'); + assertEquals({}.arrayTable, undefined, "Prototype pollution detected"); + parse('[foo]\\n[foo.__proto__.bar]'); + assertEquals({}.bar, undefined, "Prototype pollution detected"); + `; + const command = new Deno.Command(Deno.execPath(), { + stdout: "inherit", + stderr: "inherit", + args: ["eval", "--no-lock", "--unstable-unsafe-proto", testCode], + }); + const { success } = await command.output(); + assert(success); + }, +});
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
3News mentions
0No linked articles in our index yet.