From e9005f772745209f88df5406a2491964465596af Mon Sep 17 00:00:00 2001 From: bethanyj28 Date: Fri, 23 Feb 2024 10:54:12 -0500 Subject: [PATCH] ensure no path traversal --- .../__tests__/download-artifact.test.ts | 57 ++++++++++++++++++ packages/artifact/__tests__/fixtures/evil.zip | Bin 0 -> 238 bytes 2 files changed, 57 insertions(+) create mode 100644 packages/artifact/__tests__/fixtures/evil.zip diff --git a/packages/artifact/__tests__/download-artifact.test.ts b/packages/artifact/__tests__/download-artifact.test.ts index 1c0c9b0d..a593c709 100644 --- a/packages/artifact/__tests__/download-artifact.test.ts +++ b/packages/artifact/__tests__/download-artifact.test.ts @@ -121,6 +121,16 @@ const mockGetArtifactFailure = jest.fn(() => { } }) +const mockGetArtifactMalicious = jest.fn(() => { + const message = new http.IncomingMessage(new net.Socket()) + message.statusCode = 200 + message.push(fs.readFileSync(path.join(__dirname, 'fixtures', 'evil.zip'))) + message.push(null) + return { + message + } +}) + describe('download-artifact', () => { describe('public', () => { beforeEach(setup) @@ -170,6 +180,53 @@ describe('download-artifact', () => { expect(response.downloadPath).toBe(fixtures.workspaceDir) }) + it('should not allow path traversal from malicious artifacts', async () => { + const downloadArtifactMock = github.getOctokit(fixtures.token).rest + .actions.downloadArtifact as MockedDownloadArtifact + downloadArtifactMock.mockResolvedValueOnce({ + headers: { + location: fixtures.blobStorageUrl + }, + status: 302, + url: '', + data: Buffer.from('') + }) + + const mockHttpClient = (HttpClient as jest.Mock).mockImplementation( + () => { + return { + get: mockGetArtifactMalicious + } + } + ) + + const response = await downloadArtifactPublic( + fixtures.artifactID, + fixtures.repositoryOwner, + fixtures.repositoryName, + fixtures.token + ) + + expect(downloadArtifactMock).toHaveBeenCalledWith({ + owner: fixtures.repositoryOwner, + repo: fixtures.repositoryName, + artifact_id: fixtures.artifactID, + archive_format: 'zip', + request: { + redirect: 'manual' + } + }) + + expect(mockHttpClient).toHaveBeenCalledWith(getUserAgentString()) + expect(mockGetArtifactMalicious).toHaveBeenCalledWith( + fixtures.blobStorageUrl + ) + expect( + fs.readFileSync(path.join(fixtures.workspaceDir, 'etc/hosts'), 'utf8') + ).toEqual('foo') + expect(response.downloadPath).toBe(fixtures.workspaceDir) + }) + it('should successfully download an artifact to user defined path', async () => { const customPath = path.join(testDir, 'custom') diff --git a/packages/artifact/__tests__/fixtures/evil.zip b/packages/artifact/__tests__/fixtures/evil.zip new file mode 100644 index 0000000000000000000000000000000000000000..71d842b8205bf1718df485886ef30edb26e858fc GIT binary patch literal 238 zcmWIWW@Zs#U|`^22nh<0P)sfEVFmJ-ftUw~_4M>pOOo|7@{3D~y-%NKX9&QloFAeb ziw;I65oX+00JVWZ10#q+)*j%ETPMgi7-(SB2Qq;=Q8lx&ffO(SVL6aa1aTMuwt6QT literal 0 HcmV?d00001