CVE-2023-38695: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') (CWE-22)
value: cypress-image-snapshot shows visual regressions in Cypress with jest-image-snapshot. Prior to version 8.0.2, it's possible for a user to pass a relative file path for the snapshot name and reach outside of the project directory into the machine running the test. This issue has been patched in version 8.0.2.



CWE description: The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.
CVSS v3 base score: 6.5
Published: 2023-08-04T18:15Z
Repository: https://github.com/simonsmith/cypress-image-snapshot
Language: TypeScript
Files changed: cypress/e2e/matchImageSnapshot.cy.ts, cypress/e2e/nested/test/matchImageSnapshot.cy.ts, src/plugin.ts
Commit date: 2023-07-31 20:35:35 +0100
Commit message: fix: sanitise snapshot filenames

Prevents potential for tests to create directories/images outside of the repository
root. Makes use of the Cypress screenshot path which has already been
sanitised

Fixes #15

Diff: diff --git a/cypress/e2e/matchImageSnapshot.cy.ts b/cypress/e2e/matchImageSnapshot.cy.ts
index 32bc310..febfba9 100644
--- a/cypress/e2e/matchImageSnapshot.cy.ts
+++ b/cypress/e2e/matchImageSnapshot.cy.ts
@@ -9,10 +9,15 @@ it('no arguments', () => {
 
 it('name and selector', () => {
   cy.get('body').matchImageSnapshot('with custom name')
 })
 
+it('file name should ignore directories', () => {
+  cy.get('h1').matchImageSnapshot('../../../ignore-relative-dirs')
+  cy.get('h1').matchImageSnapshot('ignore/folders/image')
+})
+
 // next two tests use blackout to change
 // the snapshot image. Also validates options
 it('name and options', () => {
   cy.matchImageSnapshot('name and options', {
     blackout: ['.feature-v20'],
diff --git a/cypress/e2e/nested/test/matchImageSnapshot.cy.ts b/cypress/e2e/nested/test/matchImageSnapshot.cy.ts
index c66997c..40cf535 100644
--- a/cypress/e2e/nested/test/matchImageSnapshot.cy.ts
+++ b/cypress/e2e/nested/test/matchImageSnapshot.cy.ts
@@ -4,5 +4,9 @@ beforeEach(() => {
 })
 
 it('takes a snapshot of the page', () => {
   cy.matchImageSnapshot()
 })
+
+it('file name should ignore directories', () => {
+  cy.get('h1').matchImageSnapshot('../../../ignore-relative-dirs')
+})
diff --git a/cypress/snapshots/matchImageSnapshot.cy.ts/ignore-relative-dirs.snap.png b/cypress/snapshots/matchImageSnapshot.cy.ts/ignore-relative-dirs.snap.png
new file mode 100644
index 0000000..be78a30
Binary files /dev/null and b/cypress/snapshots/matchImageSnapshot.cy.ts/ignore-relative-dirs.snap.png differ
diff --git a/cypress/snapshots/matchImageSnapshot.cy.ts/image.snap.png b/cypress/snapshots/matchImageSnapshot.cy.ts/image.snap.png
new file mode 100644
index 0000000..be78a30
Binary files /dev/null and b/cypress/snapshots/matchImageSnapshot.cy.ts/image.snap.png differ
diff --git a/cypress/snapshots/nested/test/matchImageSnapshot.cy.ts/ignore-relative-dirs.snap.png b/cypress/snapshots/nested/test/matchImageSnapshot.cy.ts/ignore-relative-dirs.snap.png
new file mode 100644
index 0000000..be78a30
Binary files /dev/null and b/cypress/snapshots/nested/test/matchImageSnapshot.cy.ts/ignore-relative-dirs.snap.png differ
diff --git a/src/plugin.ts b/src/plugin.ts
index 0c28165..027a4bc 100644
--- a/src/plugin.ts
+++ b/src/plugin.ts
@@ -53,12 +53,11 @@ const runImageDiffAfterScreenshot = async (
   const {path: screenshotPath} = screenshotConfig
   if (!isSnapshotActive) {
     return {path: screenshotPath}
   }
 
-  // name of the screenshot without the Cypress suffixes for test failures
-  const snapshotName = screenshotConfig.name.replace(/ \(attempt [0-9]+\)/, '')
+  const snapshotName = path.basename(screenshotConfig.path, '.png')
 
   const receivedImageBuffer = await fs.readFile(screenshotPath)
   await fs.rm(screenshotPath)
 
   const {

Vulnerable code:   // name of the screenshot without the Cypress suffixes for test failures
  const snapshotName = screenshotConfig.name.replace(/ \(attempt [0-9]+\)/, '')
Fixed code: it('file name should ignore directories', () => {
  cy.get('h1').matchImageSnapshot('../../../ignore-relative-dirs')
  cy.get('h1').matchImageSnapshot('ignore/folders/image')
})


it('file name should ignore directories', () => {
  cy.get('h1').matchImageSnapshot('../../../ignore-relative-dirs')
})
  const snapshotName = path.basename(screenshotConfig.path, '.png')