iterate-skill-installer 2.5.0 → 2.7.0
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/lib/installer.js +41 -0
- package/package.json +1 -1
package/lib/installer.js
CHANGED
|
@@ -194,6 +194,31 @@ function runCommand(bin, args, options = {}) {
|
|
|
194
194
|
});
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
+
async function rejectLinkEntries(tarballPath) {
|
|
198
|
+
// Inspect the verbose listing and reject any symbolic ("l") or hard ("h")
|
|
199
|
+
// link entry. We deliberately reject *all* links rather than validating
|
|
200
|
+
// their targets: the release tarball contains none, so any link is a sign
|
|
201
|
+
// of a tampered archive and refusing it outright is the safest response to
|
|
202
|
+
// a symlink-escape attempt (see extractTarball above).
|
|
203
|
+
const verbose = await runCommand('tar', ['-tvzf', tarballPath]);
|
|
204
|
+
for (const line of verbose.split(/\r?\n/)) {
|
|
205
|
+
if (!line) {
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
const type = line[0];
|
|
209
|
+
if (type === 'l') {
|
|
210
|
+
throw new InstallerError(
|
|
211
|
+
'Refusing to extract tarball: archive contains a symbolic link, which the release never ships.',
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
if (type === 'h') {
|
|
215
|
+
throw new InstallerError(
|
|
216
|
+
'Refusing to extract tarball: archive contains a hard link, which the release never ships.',
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
197
222
|
async function extractTarball(tarballPath, destDir) {
|
|
198
223
|
// Use the system tar command (available on macOS, Linux, and Windows 10+),
|
|
199
224
|
// but defend against path-traversal tarballs: before extracting we list the
|
|
@@ -205,6 +230,13 @@ async function extractTarball(tarballPath, destDir) {
|
|
|
205
230
|
// exactly one top-level directory (see README "Release tarball structure").
|
|
206
231
|
// Archives that violate that contract — multiple top-level directories, or
|
|
207
232
|
// entries with no path left after stripping — are rejected outright.
|
|
233
|
+
//
|
|
234
|
+
// A name-based `../` check alone is not enough: a tarball can smuggle a
|
|
235
|
+
// symlink whose in-archive name looks safe but whose target points outside
|
|
236
|
+
// destDir, then place files "through" that symlink (e.g. `link/passwd` where
|
|
237
|
+
// `link -> /etc`). Because extraction happens with a system `tar`, the write
|
|
238
|
+
// would follow the link before we could validate — so any symbolic or hard
|
|
239
|
+
// link is rejected *before* extraction. The release tarball never uses links.
|
|
208
240
|
const absoluteDest = path.resolve(destDir);
|
|
209
241
|
fs.mkdirSync(absoluteDest, { recursive: true });
|
|
210
242
|
|
|
@@ -215,6 +247,13 @@ async function extractTarball(tarballPath, destDir) {
|
|
|
215
247
|
throw new InstallerError('Refusing to extract tarball: archive contains no entries.');
|
|
216
248
|
}
|
|
217
249
|
|
|
250
|
+
// 1b. Reject any symbolic or hard link entry before touching the tree.
|
|
251
|
+
// The verbose listing's first character is the entry type for both GNU tar
|
|
252
|
+
// and bsdtar (macOS): '-' regular, 'd' directory, 'l' symbolic link, 'h'
|
|
253
|
+
// hard link. We only need to detect links, so a cheap first-char scan is
|
|
254
|
+
// sufficient and avoids relying on the rest of the format.
|
|
255
|
+
await rejectLinkEntries(tarballPath);
|
|
256
|
+
|
|
218
257
|
// 2. Enforce the single-top-level-directory contract required by
|
|
219
258
|
// --strip-components=1.
|
|
220
259
|
const topLevelComponents = new Set(entries.map((entry) => entry.split('/')[0]));
|
|
@@ -659,4 +698,6 @@ module.exports = {
|
|
|
659
698
|
resolveInstallMode,
|
|
660
699
|
askYesNo,
|
|
661
700
|
parseChecksums,
|
|
701
|
+
extractTarball,
|
|
702
|
+
rejectLinkEntries,
|
|
662
703
|
};
|