CVE-2023-23939: Incorrect Permission Assignment for Critical Resource (CWE-732)
value: Azure/setup-kubectl is a GitHub Action for installing Kubectl. This vulnerability only impacts versions before version 3. An insecure temporary creation of a file allows other actors on the Actions runner to replace the Kubectl binary created by this action because it is world writable. This Kubectl tool installer runs `fs.chmodSync(kubectlPath, 777)` to set permissions on the Kubectl binary, however, this allows any local user to replace the Kubectl binary. This allows privilege escalation to the user that can also run kubectl, most likely root. This attack is only possible if an attacker somehow breached the GitHub actions runner or if a user is utilizing an Action that maliciously executes this attack. This has been fixed and released in all versions `v3` and later. 775 permissions are used instead. Users are advised to upgrade. There are no known workarounds for this issue.

CWE description: The product specifies permissions for a security-critical resource in a way that allows that resource to be read or modified by unintended actors.
CVSS v3 base score: 7
Published: 2023-03-06T19:15Z
Repository: https://github.com/Azure/setup-kubectl
Language: TypeScript
Files changed: src/run.test.ts, src/run.ts
Commit date: 2022-05-27 17:36:08 -0400
Commit message: lower permissions for chmod (#51)


Diff: diff --git a/src/run.test.ts b/src/run.test.ts
index a25dad2..e82e04a 100644
--- a/src/run.test.ts
+++ b/src/run.test.ts
@@ -104,11 +104,11 @@ describe('Testing all functions in run file.', () => {
         expect(await run.downloadKubectl('v1.15.0')).toBe(path.join('pathToCachedTool', 'kubectl.exe'));
         expect(toolCache.find).toBeCalledWith('kubectl', 'v1.15.0');
         expect(toolCache.downloadTool).toBeCalled();
         expect(toolCache.cacheFile).toBeCalled();
         expect(os.type).toBeCalled();
-        expect(fs.chmodSync).toBeCalledWith(path.join('pathToCachedTool', 'kubectl.exe'), '777');
+        expect(fs.chmodSync).toBeCalledWith(path.join('pathToCachedTool', 'kubectl.exe'), '775');
     });
 
     test('downloadKubectl() - throw DownloadKubectlFailed error when unable to download kubectl', async () => {
         jest.spyOn(toolCache, 'find').mockReturnValue('');
         jest.spyOn(toolCache, 'downloadTool').mockRejectedValue('Unable to download kubectl.');
@@ -142,11 +142,11 @@ describe('Testing all functions in run file.', () => {
         jest.spyOn(toolCache, 'downloadTool');
 
         expect(await run.downloadKubectl('v1.15.0')).toBe(path.join('pathToCachedTool', 'kubectl.exe'));
         expect(toolCache.find).toBeCalledWith('kubectl', 'v1.15.0');
         expect(os.type).toBeCalled();
-        expect(fs.chmodSync).toBeCalledWith(path.join('pathToCachedTool', 'kubectl.exe'), '777');
+        expect(fs.chmodSync).toBeCalledWith(path.join('pathToCachedTool', 'kubectl.exe'), '775');
         expect(toolCache.downloadTool).not.toBeCalled();
     });
 
     test('run() - download specified version and set output', async () => {
         jest.spyOn(core, 'getInput').mockReturnValue('v1.15.5');
diff --git a/src/run.ts b/src/run.ts
index 5a2d2f6..59ae093 100644
--- a/src/run.ts
+++ b/src/run.ts
@@ -55,10 +55,10 @@ export async function downloadKubectl(version: string): Promise<string> {
 
         cachedToolpath = await toolCache.cacheFile(kubectlDownloadPath, kubectlToolName + getExecutableExtension(), kubectlToolName, version);
     }
 
     const kubectlPath = path.join(cachedToolpath, kubectlToolName + getExecutableExtension());
-    fs.chmodSync(kubectlPath, '777');
+    fs.chmodSync(kubectlPath, '775');
     return kubectlPath;
 }
 
 run().catch(core.setFailed);

Vulnerable code:         expect(fs.chmodSync).toBeCalledWith(path.join('pathToCachedTool', 'kubectl.exe'), '777');
        expect(fs.chmodSync).toBeCalledWith(path.join('pathToCachedTool', 'kubectl.exe'), '777');
    fs.chmodSync(kubectlPath, '777');
Fixed code:         expect(fs.chmodSync).toBeCalledWith(path.join('pathToCachedTool', 'kubectl.exe'), '775');
        expect(fs.chmodSync).toBeCalledWith(path.join('pathToCachedTool', 'kubectl.exe'), '775');
    fs.chmodSync(kubectlPath, '775');