git-watchtower 1.11.2 → 1.11.3
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.
- package/bin/git-watchtower.js +16 -3
- package/package.json +1 -1
package/bin/git-watchtower.js
CHANGED
|
@@ -2110,10 +2110,23 @@ function createStaticServer() {
|
|
|
2110
2110
|
pathname = path.normalize(pathname).replace(/^(\.\.[\/\\])+/, '');
|
|
2111
2111
|
let filePath = path.join(STATIC_DIR, pathname);
|
|
2112
2112
|
|
|
2113
|
-
// Security: ensure resolved path stays within STATIC_DIR to prevent path traversal
|
|
2114
|
-
|
|
2113
|
+
// Security: ensure resolved path stays within STATIC_DIR to prevent path traversal.
|
|
2114
|
+
// Use realpath to follow symlinks — without this, a symlink inside STATIC_DIR
|
|
2115
|
+
// pointing outside would bypass the startsWith check.
|
|
2115
2116
|
const resolvedStaticDir = path.resolve(STATIC_DIR);
|
|
2116
|
-
|
|
2117
|
+
let resolvedPath = path.resolve(filePath);
|
|
2118
|
+
try {
|
|
2119
|
+
resolvedPath = fs.realpathSync(resolvedPath);
|
|
2120
|
+
} catch {
|
|
2121
|
+
// File doesn't exist — path.resolve is sufficient since there's no symlink to follow.
|
|
2122
|
+
}
|
|
2123
|
+
let realStaticDir;
|
|
2124
|
+
try {
|
|
2125
|
+
realStaticDir = fs.realpathSync(resolvedStaticDir);
|
|
2126
|
+
} catch {
|
|
2127
|
+
realStaticDir = resolvedStaticDir;
|
|
2128
|
+
}
|
|
2129
|
+
if (!resolvedPath.startsWith(realStaticDir + path.sep) && resolvedPath !== realStaticDir) {
|
|
2117
2130
|
res.writeHead(403, { 'Content-Type': 'text/html' });
|
|
2118
2131
|
res.end('<h1>403 Forbidden</h1>');
|
|
2119
2132
|
addServerLog(`GET ${logPath} → 403 (path traversal blocked)`, true);
|
package/package.json
CHANGED