zone5 1.6.0 → 1.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,12 +10,8 @@ export const sourceFileHash = (sourceBaseDir, sourceFile) => {
10
10
  return hash.digest('hex');
11
11
  };
12
12
  export const ensureDirectoryExists = async (dirPath) => {
13
- try {
14
- await access(dirPath);
15
- }
16
- catch {
17
- await mkdir(dirPath, { recursive: true });
18
- }
13
+ // mkdir with recursive: true is idempotent - no need to check if dir exists first
14
+ await mkdir(dirPath, { recursive: true });
19
15
  };
20
16
  export const fileExists = async (filePath) => {
21
17
  try {
package/dist/remark.js CHANGED
@@ -125,6 +125,28 @@ function collectImageData(images, existingKeys) {
125
125
  };
126
126
  });
127
127
  }
128
+ /**
129
+ * Validate and sanitize an image URL for safe use in import statements.
130
+ * Prevents import path injection by ensuring URLs are valid relative paths.
131
+ */
132
+ function validateImageUrl(url) {
133
+ // Remove the ?z5 suffix for validation
134
+ const cleanUrl = url.replace(/\?z5$/, '');
135
+ // Block URLs with protocol schemes (http:, https:, file:, data:, javascript:, etc.)
136
+ if (cleanUrl.match(/^[a-zA-Z][a-zA-Z0-9+.-]*:/)) {
137
+ return false;
138
+ }
139
+ // Block URLs with null bytes or other control characters (ASCII 0-31 and 127)
140
+ // eslint-disable-next-line no-control-regex
141
+ if (/[\x00-\x1f\x7f]/.test(cleanUrl)) {
142
+ return false;
143
+ }
144
+ // Block URLs that could escape the import statement (quotes, backticks, newlines)
145
+ if (cleanUrl.match(/['"`\n\r]/)) {
146
+ return false;
147
+ }
148
+ return true;
149
+ }
128
150
  /**
129
151
  * Generate a unique import key for an image URL
130
152
  */
@@ -146,10 +168,18 @@ function generateImportKey(url, existingKeys) {
146
168
  return key;
147
169
  }
148
170
  /**
149
- * Check if a node is a Zone5 image (ends with ?z5)
171
+ * Check if a node is a Zone5 image (ends with ?z5) with a valid URL
150
172
  */
151
173
  function isZ5Image(node) {
152
- return node.type === 'image' && typeof node.url === 'string' && node.url.endsWith('?z5');
174
+ if (node.type !== 'image' || typeof node.url !== 'string' || !node.url.endsWith('?z5')) {
175
+ return false;
176
+ }
177
+ // Security: Validate URL to prevent import path injection
178
+ if (!validateImageUrl(node.url)) {
179
+ console.warn(`Zone5: Skipping image with invalid URL: ${node.url}`);
180
+ return false;
181
+ }
182
+ return true;
153
183
  }
154
184
  /**
155
185
  * Check if a paragraph contains only a single Z5 image
package/dist/vite.js CHANGED
@@ -3,7 +3,7 @@ import { dataToEsm } from '@rollup/pluginutils';
3
3
  import mime from 'mime';
4
4
  import { createReadStream } from 'node:fs';
5
5
  import { cp, readFile, stat } from 'node:fs/promises';
6
- import { dirname, join } from 'node:path';
6
+ import { dirname, join, resolve } from 'node:path';
7
7
  import { load } from './config.js';
8
8
  import processor, {} from './processor/index.js';
9
9
  const tracer = trace.getTracer('zone5-vite');
@@ -18,7 +18,16 @@ const serve = (basePath, cacheDir) => async (req, res, next) => {
18
18
  const [, id] = req.url.split(basePath);
19
19
  try {
20
20
  const path = decodeURIComponent(id);
21
- const src = join(cacheDir, path);
21
+ const src = resolve(cacheDir, path);
22
+ // Security: Prevent path traversal attacks by ensuring the resolved path
23
+ // is within the cache directory
24
+ const normalizedCacheDir = resolve(cacheDir);
25
+ if (!src.startsWith(normalizedCacheDir + '/') && src !== normalizedCacheDir) {
26
+ console.error(`Zone5: Blocked path traversal attempt: ${path}`);
27
+ res.statusCode = 403;
28
+ res.end('Forbidden');
29
+ return;
30
+ }
22
31
  try {
23
32
  const image = createReadStream(src);
24
33
  const stats = await stat(src);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zone5",
3
- "version": "1.6.0",
3
+ "version": "1.6.2",
4
4
  "repository": {
5
5
  "url": "https://github.com/cwygoda/zone5"
6
6
  },