@panguard-ai/panguard-mcp-proxy 1.8.12 → 1.8.14

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.
@@ -43,6 +43,7 @@ interface RuleLike {
43
43
  * tool surface gate to skip MCP-argument rules on a native shell command. */
44
44
  readonly tags?: {
45
45
  readonly scan_target?: string;
46
+ readonly subcategory?: string;
46
47
  };
47
48
  }
48
49
  /**
package/dist/evaluator.js CHANGED
@@ -38,6 +38,20 @@ function findRulesDir() {
38
38
  * silently break the fail-open contract.
39
39
  */
40
40
  export const EVALUATION_ERROR_SENTINEL = 'evaluation-error';
41
+ /**
42
+ * The ONLY rule subcategories whose detection keys on shell METACHARACTERS
43
+ * (`;` `|` `$()` `&&`) — the grammar that is anomalous inside an MCP tool
44
+ * argument but NORMAL in the agent's own shell. Only these may degrade on the
45
+ * built-in-tool surface. Everything else scoped scan_target:mcp (credential-theft,
46
+ * env-var-harvesting, tool-poisoning, ...) detects malicious SEMANTICS that are
47
+ * illegitimate on any shell and MUST keep hard-blocking there. 1.8.12 wrongly
48
+ * gated the whole scan_target:mcp class, which silently degraded credential theft
49
+ * (`cat ~/.ssh/id_rsa`) to an advisory on the agent's own shell — a shipped hole.
50
+ */
51
+ const SHELL_METACHAR_FP_SUBCATEGORIES = new Set([
52
+ 'shell-escape',
53
+ 'parameter-injection',
54
+ ]);
41
55
  /**
42
56
  * Whether a single rule match is strong enough to HARD-DENY a live tool call
43
57
  * (vs. degrade to 'ask'). This is the proxy's false-positive control point: the
@@ -58,21 +72,22 @@ export const EVALUATION_ERROR_SENTINEL = 'evaluation-error';
58
72
  export function shouldHardDeny(rule, builtinToolSurface = false) {
59
73
  if (rule.confirm === 'embedding')
60
74
  return false;
61
- if (builtinToolSurface && rule.tags?.scan_target === 'mcp') {
75
+ if (builtinToolSurface &&
76
+ rule.tags?.scan_target === 'mcp' &&
77
+ SHELL_METACHAR_FP_SUBCATEGORIES.has(rule.tags?.subcategory ?? '')) {
62
78
  // FALSE-POSITIVE gate for the built-in-tool hook, which guards the agent's
63
- // OWN native shell (Bash/Edit/Write/WebFetch). Rules scoped scan_target:mcp
64
- // are MCP-tool-ARGUMENT rules e.g. ATR-2026-00111 "Shell Metacharacter
65
- // Injection in Tool Arguments" / ATR-2026-00066 "Parameter Injection" that
66
- // key on shell metacharacters (`;` `|` `$()`). Inside an MCP argument those
67
- // are anomalous and rightly deny; but they are the NORMAL grammar of a real
68
- // shell, so matched against the agent's own `echo x; curl localhost` they
69
- // false-block legitimate work (they only reach a tool_call event at all via
70
- // the engine's mcp-over-tool exception). On this surface an mcp-scoped rule
71
- // therefore DEGRADES to an 'ask' advisory the caller warns, never bricks
72
- // the agent. Semantic exfil/RCE rules scoped to the shell's real domain
73
- // (tool_args / skill / host / code / any) still hard-block, so credential
74
- // exfil (`cat ~/.ssh/id_rsa | curl`, `env | curl`) is caught regardless of
75
- // this gate. The MCP proxy leaves builtinToolSurface=false: on a genuine MCP
79
+ // OWN native shell (Bash/Edit/Write/WebFetch). NARROWED (1.8.13) to ONLY the
80
+ // shell-metacharacter-injection subcategories (shell-escape / parameter-
81
+ // injection ATR-2026-00111 / 00066) that key on `;` `|` `$()` grammar.
82
+ // Inside an MCP argument those are anomalous and rightly deny; but they are the
83
+ // NORMAL grammar of a real shell, so matched against the agent's own
84
+ // `echo x; curl localhost` they false-block legitimate work (they only reach a
85
+ // tool_call event via the engine's mcp-over-tool exception). On this surface
86
+ // they DEGRADE to an 'ask' advisory. CRITICAL: every OTHER scan_target:mcp
87
+ // rule still hard-blocks here 1.8.12 wrongly gated the whole class, which
88
+ // silently degraded credential theft (`cat ~/.ssh/id_rsa`, matched by the
89
+ // scan_target:mcp credential-theft rule 00113) to a non-blocking advisory on
90
+ // the agent's own shell. The MCP proxy leaves builtinToolSurface=false: on a genuine MCP
76
91
  // ARGUMENT, `; curl` really is injection. This keys on scan_target (a rule's
77
92
  // intrinsic scope), NOT maturity — so it never drifts with the daily corpus.
78
93
  return false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@panguard-ai/panguard-mcp-proxy",
3
- "version": "1.8.12",
3
+ "version": "1.8.14",
4
4
  "description": "MCP Proxy — runtime interception for AI agent tool calls using ATR rules",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -21,12 +21,12 @@
21
21
  "dependencies": {
22
22
  "@modelcontextprotocol/sdk": "^1.12.0",
23
23
  "agent-threat-rules": "^3.5.8",
24
- "@panguard-ai/atr": "1.8.12",
24
+ "@panguard-ai/atr": "1.8.14",
25
25
  "@panguard-ai/containment": "0.1.0",
26
- "@panguard-ai/panguard-guard": "1.8.12"
26
+ "@panguard-ai/panguard-guard": "1.8.14"
27
27
  },
28
28
  "peerDependencies": {
29
- "@panguard-ai/atr": "1.8.12"
29
+ "@panguard-ai/atr": "1.8.14"
30
30
  },
31
31
  "files": [
32
32
  "dist",