@node9/proxy 1.58.3 → 1.58.5

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/dist/cli.js CHANGED
@@ -53196,8 +53196,8 @@ function promptTakesUntrusted(steps) {
53196
53196
  }
53197
53197
  function hasActorGate(wf, raw) {
53198
53198
  const on = wf.on ?? raw["on"] ?? raw[true];
53199
- const prt = on?.["pull_request_target"];
53200
- const labeled = prt && Array.isArray(prt.types) && prt.types.map(String).includes("labeled");
53199
+ const prTypes = (t) => t && Array.isArray(t.types) ? t.types.map(String) : [];
53200
+ const labeled = prTypes(on?.["pull_request_target"]).includes("labeled") || prTypes(on?.["pull_request"]).includes("labeled");
53201
53201
  const ifs = [
53202
53202
  wf.jobs ? Object.values(wf.jobs).map((j) => j.if) : [],
53203
53203
  allSteps(wf).map((s) => s.step.if)
@@ -53266,6 +53266,9 @@ function analyzeWorkflow(path70, content) {
53266
53266
  const triggers = triggerKeys(wf, raw);
53267
53267
  const secretExposed = triggers.some((t) => /pull_request_target|workflow_run/i.test(t));
53268
53268
  const forkInput = triggers.some((t) => /issue|pull_request|workflow_call/i.test(t));
53269
+ const privileged = triggers.some(
53270
+ (t) => /pull_request_target|pull_request_review|workflow_run|workflow_call|issue|discussion/i.test(t)
53271
+ );
53269
53272
  const nonWrite = str(agentSteps.map((s) => s.with?.["allowed_non_write_users"]).find(Boolean));
53270
53273
  const nonWriteStar = nonWrite === "*";
53271
53274
  const nonWriteList = !!nonWrite && nonWrite !== "*";
@@ -53303,6 +53306,7 @@ function analyzeWorkflow(path70, content) {
53303
53306
  const githubWriteTool = GH_WRITE_TOOL_RE.test(toolsBlob);
53304
53307
  const canDamage = exfilOrRce || (hasGithubWritePerm(wf, agentJobs) || pat) && githubWriteTool;
53305
53308
  if (!canDamage && severity && SEVERITY_RANK2[severity] > SEVERITY_RANK2.medium) severity = "medium";
53309
+ if (untrustedTrigger && !privileged && severity && severity !== "advisory") severity = "advisory";
53306
53310
  if (!severity) severity = "advisory";
53307
53311
  const signals = [];
53308
53312
  if (secretExposed)
@@ -53310,6 +53314,10 @@ function analyzeWorkflow(path70, content) {
53310
53314
  `runs with base-repo secrets (${triggers.filter((t) => /target|workflow_run/i.test(t)).join(", ")})`
53311
53315
  );
53312
53316
  else if (forkInput) signals.push(`triggered by untrusted input (${triggers.join(", ")})`);
53317
+ if (untrustedTrigger && !privileged)
53318
+ signals.push(
53319
+ "triggered by `pull_request` \u2014 fork PRs run with a read-only token (lower risk than pull_request_target)"
53320
+ );
53313
53321
  if (head === "root") signals.push("checks out the untrusted PR head into the workspace root");
53314
53322
  if (head === "subdir") signals.push("checks out the untrusted PR head into an isolated subdir");
53315
53323
  if (promptUntrusted) signals.push("feeds untrusted PR/issue text to the agent");
@@ -53335,7 +53343,7 @@ function analyzeWorkflow(path70, content) {
53335
53343
  file: path70,
53336
53344
  signals,
53337
53345
  mitigations: mitigations.length ? mitigations : void 0,
53338
- fix: head === "root" ? "Do not check out the PR head into the workspace root under pull_request_target \u2014 check out the base ref, or isolate the head in a subdir (--add-dir). Add an actor gate and scope the agent tools." : "Add/verify an actor gate, scope the agent tools to read-only, and env-deny secrets. See Anthropic\u2019s claude-code-action security doc."
53346
+ fix: head === "root" && privileged ? "Do not check out the untrusted PR head into the workspace root under a privileged trigger (pull_request_target/workflow_run) \u2014 check out the base ref, or isolate the head in a subdir (--add-dir). Add an actor gate and scope the agent tools." : head === "root" ? "This runs under `pull_request` (fork PRs get a read-only token), so the head checkout is low-risk today \u2014 keep it on `pull_request` (not `pull_request_target`) and keep the actor gate + scoped tools." : "Add/verify an actor gate, scope the agent tools to read-only, and env-deny secrets. See Anthropic\u2019s claude-code-action security doc."
53339
53347
  };
53340
53348
  }
53341
53349
 
@@ -53509,12 +53517,14 @@ function renderScan(res) {
53509
53517
  const head = res.worst === "critical" || res.worst === "high" ? import_chalk29.default.red.bold("\u26A0\uFE0F agent-security risk found") : res.worst ? import_chalk29.default.yellow("agent-security notes") : res.incomplete ? import_chalk29.default.yellow.bold("\u26A0\uFE0F INCOMPLETE \u2014 could not read all files") : import_chalk29.default.green("\u2705 agent-security: clean");
53510
53518
  L.push(`\u{1F6E1}\uFE0F ${import_chalk29.default.bold("node9 scan-repo")} \xB7 ${res.source} \xB7 ${head}`);
53511
53519
  L.push(import_chalk29.default.gray(` inspected ${res.inspected.length} config file(s), ${n} finding(s)`));
53512
- if (res.incomplete)
53520
+ if (res.incomplete) {
53521
+ const rateLimited = res.notes.some((nt) => /rate limit/i.test(nt));
53513
53522
  L.push(
53514
53523
  import_chalk29.default.yellow.bold(
53515
- " \u26A0\uFE0F This scan was rate-limited and is NOT a clean bill of health \u2014 set GITHUB_TOKEN and re-run."
53524
+ rateLimited ? " \u26A0\uFE0F Rate-limited \u2014 some files were unread. NOT a clean bill of health; set GITHUB_TOKEN (or run `gh auth login`) and re-run." : " \u26A0\uFE0F A network error left some files unread. NOT a clean bill of health; re-run."
53516
53525
  )
53517
53526
  );
53527
+ }
53518
53528
  L.push("");
53519
53529
  for (const f of res.findings) {
53520
53530
  L.push(
package/dist/cli.mjs CHANGED
@@ -53189,8 +53189,8 @@ function promptTakesUntrusted(steps) {
53189
53189
  }
53190
53190
  function hasActorGate(wf, raw) {
53191
53191
  const on = wf.on ?? raw["on"] ?? raw[true];
53192
- const prt = on?.["pull_request_target"];
53193
- const labeled = prt && Array.isArray(prt.types) && prt.types.map(String).includes("labeled");
53192
+ const prTypes = (t) => t && Array.isArray(t.types) ? t.types.map(String) : [];
53193
+ const labeled = prTypes(on?.["pull_request_target"]).includes("labeled") || prTypes(on?.["pull_request"]).includes("labeled");
53194
53194
  const ifs = [
53195
53195
  wf.jobs ? Object.values(wf.jobs).map((j) => j.if) : [],
53196
53196
  allSteps(wf).map((s) => s.step.if)
@@ -53259,6 +53259,9 @@ function analyzeWorkflow(path70, content) {
53259
53259
  const triggers = triggerKeys(wf, raw);
53260
53260
  const secretExposed = triggers.some((t) => /pull_request_target|workflow_run/i.test(t));
53261
53261
  const forkInput = triggers.some((t) => /issue|pull_request|workflow_call/i.test(t));
53262
+ const privileged = triggers.some(
53263
+ (t) => /pull_request_target|pull_request_review|workflow_run|workflow_call|issue|discussion/i.test(t)
53264
+ );
53262
53265
  const nonWrite = str(agentSteps.map((s) => s.with?.["allowed_non_write_users"]).find(Boolean));
53263
53266
  const nonWriteStar = nonWrite === "*";
53264
53267
  const nonWriteList = !!nonWrite && nonWrite !== "*";
@@ -53296,6 +53299,7 @@ function analyzeWorkflow(path70, content) {
53296
53299
  const githubWriteTool = GH_WRITE_TOOL_RE.test(toolsBlob);
53297
53300
  const canDamage = exfilOrRce || (hasGithubWritePerm(wf, agentJobs) || pat) && githubWriteTool;
53298
53301
  if (!canDamage && severity && SEVERITY_RANK2[severity] > SEVERITY_RANK2.medium) severity = "medium";
53302
+ if (untrustedTrigger && !privileged && severity && severity !== "advisory") severity = "advisory";
53299
53303
  if (!severity) severity = "advisory";
53300
53304
  const signals = [];
53301
53305
  if (secretExposed)
@@ -53303,6 +53307,10 @@ function analyzeWorkflow(path70, content) {
53303
53307
  `runs with base-repo secrets (${triggers.filter((t) => /target|workflow_run/i.test(t)).join(", ")})`
53304
53308
  );
53305
53309
  else if (forkInput) signals.push(`triggered by untrusted input (${triggers.join(", ")})`);
53310
+ if (untrustedTrigger && !privileged)
53311
+ signals.push(
53312
+ "triggered by `pull_request` \u2014 fork PRs run with a read-only token (lower risk than pull_request_target)"
53313
+ );
53306
53314
  if (head === "root") signals.push("checks out the untrusted PR head into the workspace root");
53307
53315
  if (head === "subdir") signals.push("checks out the untrusted PR head into an isolated subdir");
53308
53316
  if (promptUntrusted) signals.push("feeds untrusted PR/issue text to the agent");
@@ -53328,7 +53336,7 @@ function analyzeWorkflow(path70, content) {
53328
53336
  file: path70,
53329
53337
  signals,
53330
53338
  mitigations: mitigations.length ? mitigations : void 0,
53331
- fix: head === "root" ? "Do not check out the PR head into the workspace root under pull_request_target \u2014 check out the base ref, or isolate the head in a subdir (--add-dir). Add an actor gate and scope the agent tools." : "Add/verify an actor gate, scope the agent tools to read-only, and env-deny secrets. See Anthropic\u2019s claude-code-action security doc."
53339
+ fix: head === "root" && privileged ? "Do not check out the untrusted PR head into the workspace root under a privileged trigger (pull_request_target/workflow_run) \u2014 check out the base ref, or isolate the head in a subdir (--add-dir). Add an actor gate and scope the agent tools." : head === "root" ? "This runs under `pull_request` (fork PRs get a read-only token), so the head checkout is low-risk today \u2014 keep it on `pull_request` (not `pull_request_target`) and keep the actor gate + scoped tools." : "Add/verify an actor gate, scope the agent tools to read-only, and env-deny secrets. See Anthropic\u2019s claude-code-action security doc."
53332
53340
  };
53333
53341
  }
53334
53342
 
@@ -53502,12 +53510,14 @@ function renderScan(res) {
53502
53510
  const head = res.worst === "critical" || res.worst === "high" ? chalk29.red.bold("\u26A0\uFE0F agent-security risk found") : res.worst ? chalk29.yellow("agent-security notes") : res.incomplete ? chalk29.yellow.bold("\u26A0\uFE0F INCOMPLETE \u2014 could not read all files") : chalk29.green("\u2705 agent-security: clean");
53503
53511
  L.push(`\u{1F6E1}\uFE0F ${chalk29.bold("node9 scan-repo")} \xB7 ${res.source} \xB7 ${head}`);
53504
53512
  L.push(chalk29.gray(` inspected ${res.inspected.length} config file(s), ${n} finding(s)`));
53505
- if (res.incomplete)
53513
+ if (res.incomplete) {
53514
+ const rateLimited = res.notes.some((nt) => /rate limit/i.test(nt));
53506
53515
  L.push(
53507
53516
  chalk29.yellow.bold(
53508
- " \u26A0\uFE0F This scan was rate-limited and is NOT a clean bill of health \u2014 set GITHUB_TOKEN and re-run."
53517
+ rateLimited ? " \u26A0\uFE0F Rate-limited \u2014 some files were unread. NOT a clean bill of health; set GITHUB_TOKEN (or run `gh auth login`) and re-run." : " \u26A0\uFE0F A network error left some files unread. NOT a clean bill of health; re-run."
53509
53518
  )
53510
53519
  );
53520
+ }
53511
53521
  L.push("");
53512
53522
  for (const f of res.findings) {
53513
53523
  L.push(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@node9/proxy",
3
- "version": "1.58.3",
3
+ "version": "1.58.5",
4
4
  "description": "The Sudo Command for AI Agents. Execution Security for Claude Code, Codex, Gemini, Cursor, Opencode, Pi, and any MCP server.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",