diff --git a/lib/modules/manager/gradle-wrapper/artifacts.spec.ts b/lib/modules/manager/gradle-wrapper/artifacts.spec.ts
index 9551f9d27e6ffd67a23b4d811e3157d6ce705a83..70b7231865ac426ee2e3161dc1fad3ac0a3d7955 100644
--- a/lib/modules/manager/gradle-wrapper/artifacts.spec.ts
+++ b/lib/modules/manager/gradle-wrapper/artifacts.spec.ts
@@ -1,4 +1,5 @@
-import { readFile, stat } from 'fs-extra';
+import type { Stats } from 'fs';
+import { readFile } from 'fs-extra';
 import { resolve } from 'upath';
 import { envMock, exec, mockExecAll } from '../../../../test/exec-util';
 import * as httpMock from '../../../../test/http-mock';
@@ -54,7 +55,12 @@ describe('modules/manager/gradle-wrapper/artifacts', () => {
     resetPrefetchedImages();
 
     fs.readLocalFile.mockResolvedValue('test');
-    fs.stat.mockImplementation((p) => stat(p));
+    fs.statLocalFile.mockResolvedValue(
+      partial<Stats>({
+        isFile: () => true,
+        mode: 0o555,
+      })
+    );
   });
 
   afterEach(() => {
@@ -98,6 +104,12 @@ describe('modules/manager/gradle-wrapper/artifacts', () => {
   });
 
   it('gradlew not found', async () => {
+    fs.statLocalFile.mockResolvedValue(
+      partial<Stats>({
+        isFile: () => false,
+        mode: 0o555,
+      })
+    );
     GlobalConfig.set({ ...adminConfig, localDir: 'some-dir' });
     const res = await gradleWrapper.updateArtifacts({
       packageFileName: 'gradle-wrapper.properties',
diff --git a/lib/modules/manager/gradle-wrapper/artifacts.ts b/lib/modules/manager/gradle-wrapper/artifacts.ts
index d3da5a3d55dcd308894e19f1c5c03373a6d2c664..220edc5eb36a8b594d3bea60830bf2d3cbff111a 100644
--- a/lib/modules/manager/gradle-wrapper/artifacts.ts
+++ b/lib/modules/manager/gradle-wrapper/artifacts.ts
@@ -1,12 +1,10 @@
 import is from '@sindresorhus/is';
 import { quote } from 'shlex';
-import upath from 'upath';
-import { GlobalConfig } from '../../../config/global';
 import { TEMPORARY_ERROR } from '../../../constants/error-messages';
 import { logger } from '../../../logger';
 import { exec } from '../../../util/exec';
 import type { ExecOptions } from '../../../util/exec/types';
-import { readLocalFile, stat, writeLocalFile } from '../../../util/fs';
+import { readLocalFile, writeLocalFile } from '../../../util/fs';
 import { getRepoStatus } from '../../../util/git';
 import type { StatusResult } from '../../../util/git/types';
 import { Http } from '../../../util/http';
@@ -62,16 +60,9 @@ export async function updateArtifacts({
   config,
 }: UpdateArtifact): Promise<UpdateArtifactsResult[] | null> {
   try {
-    const projectDir = GlobalConfig.get('localDir');
     logger.debug({ updatedDeps }, 'gradle-wrapper.updateArtifacts()');
-    const gradlew = gradleWrapperFileName();
-    const gradlewPath = upath.resolve(projectDir, `./${gradlew}`);
-    let cmd = await prepareGradleCommand(
-      gradlew,
-      projectDir!,
-      await stat(gradlewPath).catch(() => null),
-      `wrapper`
-    );
+    const gradlewFile = gradleWrapperFileName();
+    let cmd = await prepareGradleCommand(gradlewFile, `wrapper`);
     if (!cmd) {
       logger.info('No gradlew found - skipping Artifacts update');
       return null;
diff --git a/lib/modules/manager/gradle-wrapper/utils.ts b/lib/modules/manager/gradle-wrapper/utils.ts
index c990f20819f9e491fe98276a4a16f5a707c86627..8fb41e5753ff73afe625d03025c4d5f19677f016 100644
--- a/lib/modules/manager/gradle-wrapper/utils.ts
+++ b/lib/modules/manager/gradle-wrapper/utils.ts
@@ -1,9 +1,7 @@
-import type { Stats } from 'fs';
 import os from 'os';
-import upath from 'upath';
 import { GlobalConfig } from '../../../config/global';
 import { logger } from '../../../logger';
-import { chmod } from '../../../util/fs';
+import { chmodLocalFile, statLocalFile } from '../../../util/fs';
 import { newlineRegex, regEx } from '../../../util/regex';
 import gradleVersioning from '../../versioning/gradle';
 import { id as npmVersioning } from '../../versioning/npm';
@@ -27,16 +25,16 @@ export function gradleWrapperFileName(): string {
 
 export async function prepareGradleCommand(
   gradlewName: string,
-  cwd: string,
-  gradlew: Stats | null,
   args: string | null
 ): Promise<string | null> {
+  const gradlewFile = gradleWrapperFileName();
+  const gradlewStat = await statLocalFile(gradlewFile);
   // istanbul ignore if
-  if (gradlew?.isFile() === true) {
+  if (gradlewStat?.isFile() === true) {
     // if the file is not executable by others
-    if ((gradlew.mode & 0o1) === 0) {
+    if ((gradlewStat.mode & 0o1) === 0) {
       // add the execution permission to the owner, group and others
-      await chmod(upath.join(cwd, gradlewName), gradlew.mode | 0o111);
+      await chmodLocalFile(gradlewName, gradlewStat.mode | 0o111);
     }
     if (args === null) {
       return gradlewName;
diff --git a/lib/util/fs/index.spec.ts b/lib/util/fs/index.spec.ts
index 09b66be3efd876726d14934a8db68f85a7d0dfaa..31c2dc4ecfe503bfa7546b76e594c63c153cc1f6 100644
--- a/lib/util/fs/index.spec.ts
+++ b/lib/util/fs/index.spec.ts
@@ -6,6 +6,7 @@ import { envMock } from '../../../test/exec-util';
 import { env, mockedFunction } from '../../../test/util';
 import { GlobalConfig } from '../../config/global';
 import {
+  chmodLocalFile,
   ensureCacheDir,
   ensureLocalDir,
   findLocalSiblingOrParent,
@@ -15,6 +16,7 @@ import {
   localPathIsFile,
   readLocalDirectory,
   readLocalFile,
+  statLocalFile,
   writeLocalFile,
 } from '.';
 
@@ -240,4 +242,40 @@ describe('util/fs/index', () => {
       expect(res).toBeNull();
     });
   });
+
+  describe('chmodLocalFile', () => {
+    it('works', async () => {
+      await withDir(
+        async (tmpDir) => {
+          GlobalConfig.set({ localDir: tmpDir.path });
+          await writeLocalFile('foo', 'bar');
+          await chmodLocalFile('foo', 0o000);
+          expect(await readLocalFile('foo')).toBeNull();
+          await chmodLocalFile('foo', 0o444);
+          expect((await readLocalFile('foo'))!.toString()).toBe('bar');
+        },
+        { unsafeCleanup: true }
+      );
+    });
+  });
+
+  describe('statLocalFile', () => {
+    it('works', async () => {
+      await withDir(
+        async (tmpDir) => {
+          GlobalConfig.set({ localDir: tmpDir.path });
+
+          expect(await statLocalFile('foo')).toBeNull();
+
+          await writeLocalFile('foo', 'bar');
+          await chmodLocalFile('foo', 0o123);
+
+          const res = await statLocalFile('foo');
+          expect(res!.isFile()).toBeTrue();
+          expect(res!.mode & 0o777).toBe(0o123);
+        },
+        { unsafeCleanup: true }
+      );
+    });
+  });
 });
diff --git a/lib/util/fs/index.ts b/lib/util/fs/index.ts
index ad7076bf6e50aa2a25aa868b22ac8fe5b74f477b..2b1f5a3bc5a068ab668b8458c50f23edde9bf17a 100644
--- a/lib/util/fs/index.ts
+++ b/lib/util/fs/index.ts
@@ -195,3 +195,24 @@ export async function findUpLocal(
   // Return null if found file is outside of localDir
   return null;
 }
+
+export function chmodLocalFile(
+  fileName: string,
+  mode: string | number
+): Promise<void> {
+  const localDir = GlobalConfig.get('localDir');
+  const fullFileName = upath.join(localDir, fileName);
+  return fs.chmod(fullFileName, mode);
+}
+
+export async function statLocalFile(
+  fileName: string
+): Promise<fs.Stats | null> {
+  const localDir = GlobalConfig.get('localDir');
+  const fullFileName = upath.join(localDir, fileName);
+  try {
+    return await fs.stat(fullFileName);
+  } catch (_) {
+    return null;
+  }
+}
diff --git a/lib/util/fs/proxies.ts b/lib/util/fs/proxies.ts
index f291ff1e572f0c7f1dc1122c8bf31424a7fa2f1a..3c4e42d330bef07c8e60bb640ae9dfe935bfed85 100644
--- a/lib/util/fs/proxies.ts
+++ b/lib/util/fs/proxies.ts
@@ -6,14 +6,6 @@ export function stat(path: string | Buffer): Promise<fs.Stats> {
   return fs.stat(path);
 }
 
-// istanbul ignore next
-export function chmod(
-  path: string | Buffer,
-  mode: string | number
-): Promise<void> {
-  return fs.chmod(path, mode);
-}
-
 export async function readFile(fileName: string): Promise<Buffer>;
 export async function readFile(
   fileName: string,