@socketsecurity/lib 5.17.0 → 5.18.1

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/CHANGELOG.md CHANGED
@@ -5,6 +5,23 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [5.18.1](https://github.com/SocketDev/socket-lib/releases/tag/v5.18.1) - 2026-04-14
9
+
10
+ ### Changed — build
11
+
12
+ - Dedup npm-pack.js bundle via pnpm overrides: pacote 21.5.0, make-fetch-happen 15.0.5, and 7 transitive npm packages (npm-bundled, npm-normalize-package-bin, json-parse-even-better-errors, @npmcli/installed-package-contents, @npmcli/name-from-folder, @npmcli/promise-spawn, @npmcli/redact)
13
+ - npm-pack.js: 69,738 → 66,443 lines (2.59MB → 2.46MB), 22 duplicate packages removed
14
+
15
+ ## [5.18.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.18.0) - 2026-04-14
16
+
17
+ ### Added — dlx
18
+
19
+ - Socket Firewall API check before package downloads — resolves dependency tree via `buildIdealTree`, checks all packages against `firewall-api.socket.dev/purl` in parallel, blocks on critical/high severity alerts
20
+
21
+ ### Changed — http-request
22
+
23
+ - Default `User-Agent` header updated from `socket-registry/1.0` to `socketsecurity-lib/{version}`
24
+
8
25
  ## [5.17.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.17.0) - 2026-04-14
9
26
 
10
27
  ### Added — paths
@@ -30,6 +30,11 @@ export declare const SOCKET_DLX_APP_NAME = "dlx";
30
30
  export declare const SOCKET_FIREWALL_APP_NAME = "sfw";
31
31
  export declare const SOCKET_REGISTRY_APP_NAME = "registry";
32
32
  export declare const SOCKET_APP_PREFIX = "_";
33
+ // Socket.dev lib.
34
+ export declare const SOCKET_LIB_NAME = "@socketsecurity/lib";
35
+ export declare const SOCKET_LIB_VERSION: string;
36
+ export declare const SOCKET_LIB_URL = "https://github.com/SocketDev/socket-lib";
37
+ export declare const SOCKET_LIB_USER_AGENT: string;
33
38
  // Socket.dev IPC.
34
39
  export declare const SOCKET_IPC_HANDSHAKE = "SOCKET_IPC_HANDSHAKE";
35
40
  // Socket.dev cache and registry.
@@ -34,6 +34,10 @@ __export(socket_exports, {
34
34
  SOCKET_FIREWALL_APP_NAME: () => SOCKET_FIREWALL_APP_NAME,
35
35
  SOCKET_GITHUB_ORG: () => SOCKET_GITHUB_ORG,
36
36
  SOCKET_IPC_HANDSHAKE: () => SOCKET_IPC_HANDSHAKE,
37
+ SOCKET_LIB_NAME: () => SOCKET_LIB_NAME,
38
+ SOCKET_LIB_URL: () => SOCKET_LIB_URL,
39
+ SOCKET_LIB_USER_AGENT: () => SOCKET_LIB_USER_AGENT,
40
+ SOCKET_LIB_VERSION: () => SOCKET_LIB_VERSION,
37
41
  SOCKET_OVERRIDE_SCOPE: () => SOCKET_OVERRIDE_SCOPE,
38
42
  SOCKET_PRICING_URL: () => SOCKET_PRICING_URL,
39
43
  SOCKET_PUBLIC_API_KEY: () => SOCKET_PUBLIC_API_KEY,
@@ -71,6 +75,10 @@ const SOCKET_DLX_APP_NAME = "dlx";
71
75
  const SOCKET_FIREWALL_APP_NAME = "sfw";
72
76
  const SOCKET_REGISTRY_APP_NAME = "registry";
73
77
  const SOCKET_APP_PREFIX = "_";
78
+ const SOCKET_LIB_NAME = "@socketsecurity/lib";
79
+ const SOCKET_LIB_VERSION = "5.18.1";
80
+ const SOCKET_LIB_URL = "https://github.com/SocketDev/socket-lib";
81
+ const SOCKET_LIB_USER_AGENT = `socketsecurity-lib/${SOCKET_LIB_VERSION} (${SOCKET_LIB_URL})`;
74
82
  const SOCKET_IPC_HANDSHAKE = "SOCKET_IPC_HANDSHAKE";
75
83
  const CACHE_SOCKET_API_DIR = "socket-api";
76
84
  const REGISTRY = "registry";
@@ -92,6 +100,10 @@ const REGISTRY_SCOPE_DELIMITER = "__";
92
100
  SOCKET_FIREWALL_APP_NAME,
93
101
  SOCKET_GITHUB_ORG,
94
102
  SOCKET_IPC_HANDSHAKE,
103
+ SOCKET_LIB_NAME,
104
+ SOCKET_LIB_URL,
105
+ SOCKET_LIB_USER_AGENT,
106
+ SOCKET_LIB_VERSION,
95
107
  SOCKET_OVERRIDE_SCOPE,
96
108
  SOCKET_PRICING_URL,
97
109
  SOCKET_PUBLIC_API_KEY,
@@ -181,6 +181,14 @@ export declare function findBinaryPath(packageDir: string, packageName: string,
181
181
  * ```
182
182
  */
183
183
  export declare function makePackageBinsExecutable(packageDir: string, packageName: string): void;
184
+ /**
185
+ * Build a PURL string for an npm package.
186
+ * Follows the PURL spec for the npm type:
187
+ * - Scoped: `@scope/pkg` → `pkg:npm/%40scope/pkg@version`
188
+ * - Unscoped: `pkg` → `pkg:npm/pkg@version`
189
+ *
190
+ */
191
+ export declare function npmPurl(name: string, version: string): string;
184
192
  /**
185
193
  * Parse package spec into name and version using npm-package-arg.
186
194
  * Examples:
@@ -35,18 +35,21 @@ __export(package_exports, {
35
35
  executePackage: () => executePackage,
36
36
  findBinaryPath: () => findBinaryPath,
37
37
  makePackageBinsExecutable: () => makePackageBinsExecutable,
38
+ npmPurl: () => npmPurl,
38
39
  parsePackageSpec: () => parsePackageSpec,
39
40
  resolveBinaryPath: () => resolveBinaryPath
40
41
  });
41
42
  module.exports = __toCommonJS(package_exports);
42
43
  var import_platform = require("../constants/platform");
44
+ var import_socket = require("../constants/socket");
43
45
  var import_cache = require("./cache");
44
46
  var import_arborist = __toESM(require("../external/@npmcli/arborist"));
45
47
  var import_libnpmexec = __toESM(require("../external/libnpmexec"));
46
48
  var import_npm_package_arg = __toESM(require("../external/npm-package-arg"));
47
49
  var import_fs = require("../fs");
50
+ var import_http_request = require("../http-request");
48
51
  var import_normalize = require("../paths/normalize");
49
- var import_socket = require("../paths/socket");
52
+ var import_socket2 = require("../paths/socket");
50
53
  var import_process_lock = require("../process-lock");
51
54
  var import_spawn = require("../spawn");
52
55
  let _fs;
@@ -110,7 +113,7 @@ async function ensurePackageInstalled(packageName, packageSpec, force) {
110
113
  const fs = /* @__PURE__ */ getFs();
111
114
  const path = /* @__PURE__ */ getPath();
112
115
  const cacheKey = (0, import_cache.generateCacheKey)(packageSpec);
113
- const packageDir = (0, import_normalize.normalizePath)(path.join((0, import_socket.getSocketDlxDir)(), cacheKey));
116
+ const packageDir = (0, import_normalize.normalizePath)(path.join((0, import_socket2.getSocketDlxDir)(), cacheKey));
114
117
  const installedDir = (0, import_normalize.normalizePath)(
115
118
  path.join(packageDir, "node_modules", packageName)
116
119
  );
@@ -150,7 +153,7 @@ Ensure the filesystem is writable or set SOCKET_DLX_DIR to a writable location.`
150
153
  const arb = new import_arborist.default({
151
154
  path: packageDir,
152
155
  // Use Socket's shared cacache directory (~/.socket/_cacache).
153
- cache: (0, import_socket.getSocketCacacheDir)(),
156
+ cache: (0, import_socket2.getSocketCacacheDir)(),
154
157
  // Skip devDependencies (production-only like npx).
155
158
  omit: ["dev"],
156
159
  // Security: Skip install/preinstall/postinstall scripts to prevent arbitrary code execution.
@@ -164,8 +167,13 @@ Ensure the filesystem is writable or set SOCKET_DLX_DIR to a writable location.`
164
167
  // Suppress output (unneeded for ephemeral dlx installs).
165
168
  silent: true
166
169
  });
167
- await arb.reify({ save: true, add: [packageSpec] });
170
+ await arb.buildIdealTree({ add: [packageSpec] });
171
+ await checkFirewallPurls(arb, packageName);
172
+ await arb.reify({ save: true });
168
173
  } catch (e) {
174
+ if (e instanceof Error && e.message.startsWith("Socket Firewall blocked")) {
175
+ throw e;
176
+ }
169
177
  const code = e.code;
170
178
  if (code === "E404" || code === "ETARGET") {
171
179
  throw new Error(
@@ -295,6 +303,76 @@ function makePackageBinsExecutable(packageDir, packageName) {
295
303
  } catch {
296
304
  }
297
305
  }
306
+ const FIREWALL_API_URL = "https://firewall-api.socket.dev/purl";
307
+ const FIREWALL_TIMEOUT = 1e4;
308
+ const FIREWALL_BLOCK_SEVERITIES = /* @__PURE__ */ new Set([
309
+ "critical",
310
+ "high"
311
+ ]);
312
+ function npmPurl(name, version) {
313
+ const encoded = name.startsWith("@") ? `%40${name.slice(1)}` : name;
314
+ const encodedVersion = version.replace(/\+/g, "%2B");
315
+ return `pkg:npm/${encoded}@${encodedVersion}`;
316
+ }
317
+ async function checkFirewallPurls(arb, requestedPackage) {
318
+ const idealTree = arb.idealTree;
319
+ if (!idealTree) {
320
+ return;
321
+ }
322
+ const purls = [];
323
+ for (const node of idealTree.inventory.values()) {
324
+ if (node.isProjectRoot) {
325
+ continue;
326
+ }
327
+ const { name, version } = node.package;
328
+ if (!name || !version) {
329
+ continue;
330
+ }
331
+ purls.push({ purl: npmPurl(name, version), name, version });
332
+ }
333
+ if (purls.length === 0) {
334
+ return;
335
+ }
336
+ const blocked = [];
337
+ await Promise.allSettled(
338
+ purls.map(async ({ name, purl, version }) => {
339
+ try {
340
+ const data = await (0, import_http_request.httpJson)(
341
+ `${FIREWALL_API_URL}/${encodeURIComponent(purl)}`,
342
+ {
343
+ headers: { "User-Agent": import_socket.SOCKET_LIB_USER_AGENT },
344
+ timeout: FIREWALL_TIMEOUT,
345
+ retries: 1,
346
+ retryDelay: 500
347
+ }
348
+ );
349
+ const blocking = (data.alerts ?? []).filter(
350
+ (a) => a.severity && FIREWALL_BLOCK_SEVERITIES.has(a.severity)
351
+ );
352
+ if (blocking.length > 0) {
353
+ blocked.push({
354
+ name,
355
+ version,
356
+ alerts: blocking.map(
357
+ (a) => `${a.severity}: ${a.type ?? a.key ?? "unknown"}`
358
+ )
359
+ });
360
+ }
361
+ } catch {
362
+ }
363
+ })
364
+ );
365
+ if (blocked.length > 0) {
366
+ const details = blocked.map((b) => ` ${b.name}@${b.version}: ${b.alerts.join(", ")}`).join("\n");
367
+ throw new Error(
368
+ `Socket Firewall blocked installation of "${requestedPackage}".
369
+ The following dependencies have security alerts:
370
+ ${details}
371
+
372
+ Visit https://socket.dev for more information.`
373
+ );
374
+ }
375
+ }
298
376
  function parsePackageSpec(spec) {
299
377
  try {
300
378
  const parsed = (0, import_npm_package_arg.default)(spec);
@@ -345,6 +423,7 @@ function resolveBinaryPath(basePath) {
345
423
  executePackage,
346
424
  findBinaryPath,
347
425
  makePackageBinsExecutable,
426
+ npmPurl,
348
427
  parsePackageSpec,
349
428
  resolveBinaryPath
350
429
  });
@@ -10,9 +10,9 @@ var __commonJS = (cb, mod) => function __require() {
10
10
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
11
11
  };
12
12
 
13
- // node_modules/.pnpm/json-parse-even-better-errors@4.0.0/node_modules/json-parse-even-better-errors/lib/index.js
13
+ // node_modules/.pnpm/json-parse-even-better-errors@5.0.0/node_modules/json-parse-even-better-errors/lib/index.js
14
14
  var require_lib = __commonJS({
15
- "node_modules/.pnpm/json-parse-even-better-errors@4.0.0/node_modules/json-parse-even-better-errors/lib/index.js"(exports2, module2) {
15
+ "node_modules/.pnpm/json-parse-even-better-errors@5.0.0/node_modules/json-parse-even-better-errors/lib/index.js"(exports2, module2) {
16
16
  "use strict";
17
17
  var INDENT = Symbol.for("indent");
18
18
  var NEWLINE = Symbol.for("newline");
@@ -11,9 +11,9 @@ var __commonJS = (cb, mod) => function __require() {
11
11
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
12
12
  };
13
13
 
14
- // node_modules/.pnpm/json-parse-even-better-errors@4.0.0/node_modules/json-parse-even-better-errors/lib/index.js
14
+ // node_modules/.pnpm/json-parse-even-better-errors@5.0.0/node_modules/json-parse-even-better-errors/lib/index.js
15
15
  var require_lib = __commonJS({
16
- "node_modules/.pnpm/json-parse-even-better-errors@4.0.0/node_modules/json-parse-even-better-errors/lib/index.js"(exports2, module2) {
16
+ "node_modules/.pnpm/json-parse-even-better-errors@5.0.0/node_modules/json-parse-even-better-errors/lib/index.js"(exports2, module2) {
17
17
  "use strict";
18
18
  var INDENT = Symbol.for("indent");
19
19
  var NEWLINE = Symbol.for("newline");
@@ -10315,9 +10315,9 @@ var require_lib4 = __commonJS({
10315
10315
  }
10316
10316
  });
10317
10317
 
10318
- // node_modules/.pnpm/@npmcli+promise-spawn@8.0.3/node_modules/@npmcli/promise-spawn/lib/escape.js
10318
+ // node_modules/.pnpm/@npmcli+promise-spawn@9.0.1/node_modules/@npmcli/promise-spawn/lib/escape.js
10319
10319
  var require_escape2 = __commonJS({
10320
- "node_modules/.pnpm/@npmcli+promise-spawn@8.0.3/node_modules/@npmcli/promise-spawn/lib/escape.js"(exports2, module2) {
10320
+ "node_modules/.pnpm/@npmcli+promise-spawn@9.0.1/node_modules/@npmcli/promise-spawn/lib/escape.js"(exports2, module2) {
10321
10321
  "use strict";
10322
10322
  var cmd = /* @__PURE__ */ __name((input, doubleEscape) => {
10323
10323
  if (!input.length) {
@@ -10371,9 +10371,9 @@ var require_escape2 = __commonJS({
10371
10371
  }
10372
10372
  });
10373
10373
 
10374
- // node_modules/.pnpm/@npmcli+promise-spawn@8.0.3/node_modules/@npmcli/promise-spawn/lib/index.js
10374
+ // node_modules/.pnpm/@npmcli+promise-spawn@9.0.1/node_modules/@npmcli/promise-spawn/lib/index.js
10375
10375
  var require_lib5 = __commonJS({
10376
- "node_modules/.pnpm/@npmcli+promise-spawn@8.0.3/node_modules/@npmcli/promise-spawn/lib/index.js"(exports2, module2) {
10376
+ "node_modules/.pnpm/@npmcli+promise-spawn@9.0.1/node_modules/@npmcli/promise-spawn/lib/index.js"(exports2, module2) {
10377
10377
  "use strict";
10378
10378
  var { spawn } = require("child_process");
10379
10379
  var os = require("os");
@@ -13653,9 +13653,9 @@ var require_lib7 = __commonJS({
13653
13653
  }
13654
13654
  });
13655
13655
 
13656
- // node_modules/.pnpm/npm-normalize-package-bin@4.0.0/node_modules/npm-normalize-package-bin/lib/index.js
13656
+ // node_modules/.pnpm/npm-normalize-package-bin@5.0.0/node_modules/npm-normalize-package-bin/lib/index.js
13657
13657
  var require_lib8 = __commonJS({
13658
- "node_modules/.pnpm/npm-normalize-package-bin@4.0.0/node_modules/npm-normalize-package-bin/lib/index.js"(exports2, module2) {
13658
+ "node_modules/.pnpm/npm-normalize-package-bin@5.0.0/node_modules/npm-normalize-package-bin/lib/index.js"(exports2, module2) {
13659
13659
  var { join, basename } = require("path");
13660
13660
  var normalize = /* @__PURE__ */ __name((pkg) => !pkg.bin ? removeBin(pkg) : typeof pkg.bin === "string" ? normalizeString(pkg) : Array.isArray(pkg.bin) ? normalizeArray(pkg) : typeof pkg.bin === "object" ? normalizeObject(pkg) : removeBin(pkg), "normalize");
13661
13661
  var normalizeString = /* @__PURE__ */ __name((pkg) => {
@@ -259,9 +259,9 @@ var require_lib = __commonJS({
259
259
  }
260
260
  });
261
261
 
262
- // node_modules/.pnpm/@npmcli+promise-spawn@8.0.3/node_modules/@npmcli/promise-spawn/lib/escape.js
262
+ // node_modules/.pnpm/@npmcli+promise-spawn@9.0.1/node_modules/@npmcli/promise-spawn/lib/escape.js
263
263
  var require_escape = __commonJS({
264
- "node_modules/.pnpm/@npmcli+promise-spawn@8.0.3/node_modules/@npmcli/promise-spawn/lib/escape.js"(exports2, module2) {
264
+ "node_modules/.pnpm/@npmcli+promise-spawn@9.0.1/node_modules/@npmcli/promise-spawn/lib/escape.js"(exports2, module2) {
265
265
  "use strict";
266
266
  var cmd = /* @__PURE__ */ __name((input, doubleEscape) => {
267
267
  if (!input.length) {
@@ -315,9 +315,9 @@ var require_escape = __commonJS({
315
315
  }
316
316
  });
317
317
 
318
- // node_modules/.pnpm/@npmcli+promise-spawn@8.0.3/node_modules/@npmcli/promise-spawn/lib/index.js
318
+ // node_modules/.pnpm/@npmcli+promise-spawn@9.0.1/node_modules/@npmcli/promise-spawn/lib/index.js
319
319
  var require_lib2 = __commonJS({
320
- "node_modules/.pnpm/@npmcli+promise-spawn@8.0.3/node_modules/@npmcli/promise-spawn/lib/index.js"(exports2, module2) {
320
+ "node_modules/.pnpm/@npmcli+promise-spawn@9.0.1/node_modules/@npmcli/promise-spawn/lib/index.js"(exports2, module2) {
321
321
  "use strict";
322
322
  var { spawn } = require("child_process");
323
323
  var os = require("os");