agent-threat-rules 0.1.0 → 0.2.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.
Files changed (131) hide show
  1. package/README.md +360 -98
  2. package/dist/action-executor.d.ts +44 -0
  3. package/dist/action-executor.d.ts.map +1 -0
  4. package/dist/action-executor.js +130 -0
  5. package/dist/action-executor.js.map +1 -0
  6. package/dist/adapters/default-adapter.d.ts +24 -0
  7. package/dist/adapters/default-adapter.d.ts.map +1 -0
  8. package/dist/adapters/default-adapter.js +51 -0
  9. package/dist/adapters/default-adapter.js.map +1 -0
  10. package/dist/adapters/stdio-adapter.d.ts +30 -0
  11. package/dist/adapters/stdio-adapter.d.ts.map +1 -0
  12. package/dist/adapters/stdio-adapter.js +128 -0
  13. package/dist/adapters/stdio-adapter.js.map +1 -0
  14. package/dist/cli.js +119 -1
  15. package/dist/cli.js.map +1 -1
  16. package/dist/coverage-analyzer.d.ts +43 -0
  17. package/dist/coverage-analyzer.d.ts.map +1 -0
  18. package/dist/coverage-analyzer.js +329 -0
  19. package/dist/coverage-analyzer.js.map +1 -0
  20. package/dist/engine.d.ts +40 -5
  21. package/dist/engine.d.ts.map +1 -1
  22. package/dist/engine.js +89 -5
  23. package/dist/engine.js.map +1 -1
  24. package/dist/hook-handler.d.ts +61 -0
  25. package/dist/hook-handler.d.ts.map +1 -0
  26. package/dist/hook-handler.js +178 -0
  27. package/dist/hook-handler.js.map +1 -0
  28. package/dist/index.d.ts +19 -1
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +11 -0
  31. package/dist/index.js.map +1 -1
  32. package/dist/layer-integration.d.ts +55 -0
  33. package/dist/layer-integration.d.ts.map +1 -0
  34. package/dist/layer-integration.js +185 -0
  35. package/dist/layer-integration.js.map +1 -0
  36. package/dist/loader.js +2 -2
  37. package/dist/loader.js.map +1 -1
  38. package/dist/mcp-server.d.ts +13 -0
  39. package/dist/mcp-server.d.ts.map +1 -0
  40. package/dist/mcp-server.js +220 -0
  41. package/dist/mcp-server.js.map +1 -0
  42. package/dist/mcp-tools/coverage-gaps.d.ts +13 -0
  43. package/dist/mcp-tools/coverage-gaps.d.ts.map +1 -0
  44. package/dist/mcp-tools/coverage-gaps.js +55 -0
  45. package/dist/mcp-tools/coverage-gaps.js.map +1 -0
  46. package/dist/mcp-tools/list-rules.d.ts +17 -0
  47. package/dist/mcp-tools/list-rules.d.ts.map +1 -0
  48. package/dist/mcp-tools/list-rules.js +45 -0
  49. package/dist/mcp-tools/list-rules.js.map +1 -0
  50. package/dist/mcp-tools/scan.d.ts +24 -0
  51. package/dist/mcp-tools/scan.d.ts.map +1 -0
  52. package/dist/mcp-tools/scan.js +87 -0
  53. package/dist/mcp-tools/scan.js.map +1 -0
  54. package/dist/mcp-tools/submit-proposal.d.ts +12 -0
  55. package/dist/mcp-tools/submit-proposal.d.ts.map +1 -0
  56. package/dist/mcp-tools/submit-proposal.js +95 -0
  57. package/dist/mcp-tools/submit-proposal.js.map +1 -0
  58. package/dist/mcp-tools/threat-summary.d.ts +12 -0
  59. package/dist/mcp-tools/threat-summary.d.ts.map +1 -0
  60. package/dist/mcp-tools/threat-summary.js +74 -0
  61. package/dist/mcp-tools/threat-summary.js.map +1 -0
  62. package/dist/mcp-tools/validate.d.ts +15 -0
  63. package/dist/mcp-tools/validate.d.ts.map +1 -0
  64. package/dist/mcp-tools/validate.js +45 -0
  65. package/dist/mcp-tools/validate.js.map +1 -0
  66. package/dist/modules/index.d.ts +5 -4
  67. package/dist/modules/index.d.ts.map +1 -1
  68. package/dist/modules/index.js +6 -4
  69. package/dist/modules/index.js.map +1 -1
  70. package/dist/modules/semantic.d.ts +105 -0
  71. package/dist/modules/semantic.d.ts.map +1 -0
  72. package/dist/modules/semantic.js +283 -0
  73. package/dist/modules/semantic.js.map +1 -0
  74. package/dist/rule-scaffolder.d.ts +39 -0
  75. package/dist/rule-scaffolder.d.ts.map +1 -0
  76. package/dist/rule-scaffolder.js +184 -0
  77. package/dist/rule-scaffolder.js.map +1 -0
  78. package/dist/skill-fingerprint.d.ts +85 -0
  79. package/dist/skill-fingerprint.d.ts.map +1 -0
  80. package/dist/skill-fingerprint.js +326 -0
  81. package/dist/skill-fingerprint.js.map +1 -0
  82. package/dist/types.d.ts +59 -1
  83. package/dist/types.d.ts.map +1 -1
  84. package/dist/verdict.d.ts +26 -0
  85. package/dist/verdict.d.ts.map +1 -0
  86. package/dist/verdict.js +127 -0
  87. package/dist/verdict.js.map +1 -0
  88. package/package.json +6 -1
  89. package/rules/agent-manipulation/ATR-2026-030-cross-agent-attack.yaml +1 -1
  90. package/rules/agent-manipulation/ATR-2026-032-goal-hijacking.yaml +1 -1
  91. package/rules/agent-manipulation/ATR-2026-074-cross-agent-privilege-escalation.yaml +1 -1
  92. package/rules/agent-manipulation/ATR-2026-076-inter-agent-message-spoofing.yaml +1 -1
  93. package/rules/agent-manipulation/ATR-2026-077-human-trust-exploitation.yaml +1 -1
  94. package/rules/context-exfiltration/ATR-2026-020-system-prompt-leak.yaml +1 -1
  95. package/rules/context-exfiltration/ATR-2026-021-api-key-exposure.yaml +1 -1
  96. package/rules/context-exfiltration/ATR-2026-075-agent-memory-manipulation.yaml +1 -1
  97. package/rules/data-poisoning/ATR-2026-070-data-poisoning.yaml +1 -1
  98. package/rules/excessive-autonomy/ATR-2026-050-runaway-agent-loop.yaml +1 -1
  99. package/rules/excessive-autonomy/ATR-2026-051-resource-exhaustion.yaml +1 -1
  100. package/rules/excessive-autonomy/ATR-2026-052-cascading-failure.yaml +1 -1
  101. package/rules/model-security/ATR-2026-072-model-behavior-extraction.yaml +1 -1
  102. package/rules/model-security/ATR-2026-073-malicious-finetuning-data.yaml +1 -1
  103. package/rules/privilege-escalation/ATR-2026-040-privilege-escalation.yaml +1 -1
  104. package/rules/privilege-escalation/ATR-2026-041-scope-creep.yaml +1 -1
  105. package/rules/prompt-injection/ATR-2026-001-direct-prompt-injection.yaml +3 -3
  106. package/rules/prompt-injection/ATR-2026-002-indirect-prompt-injection.yaml +1 -1
  107. package/rules/prompt-injection/ATR-2026-003-jailbreak-attempt.yaml +1 -1
  108. package/rules/prompt-injection/ATR-2026-004-system-prompt-override.yaml +1 -1
  109. package/rules/prompt-injection/ATR-2026-005-multi-turn-injection.yaml +1 -1
  110. package/rules/prompt-injection/ATR-2026-080-encoding-evasion.yaml +80 -0
  111. package/rules/prompt-injection/ATR-2026-081-semantic-multi-turn.yaml +77 -0
  112. package/rules/prompt-injection/ATR-2026-082-fingerprint-evasion.yaml +76 -0
  113. package/rules/prompt-injection/ATR-2026-083-indirect-tool-injection.yaml +76 -0
  114. package/rules/prompt-injection/ATR-2026-084-structured-data-injection.yaml +78 -0
  115. package/rules/prompt-injection/ATR-2026-085-audit-evasion.yaml +76 -0
  116. package/rules/prompt-injection/ATR-2026-086-visual-spoofing.yaml +80 -0
  117. package/rules/prompt-injection/ATR-2026-087-rule-probing.yaml +74 -0
  118. package/rules/prompt-injection/ATR-2026-088-adaptive-countermeasure.yaml +76 -0
  119. package/rules/prompt-injection/ATR-2026-089-polymorphic-skill.yaml +77 -0
  120. package/rules/prompt-injection/ATR-2026-090-threat-intel-exfil.yaml +76 -0
  121. package/rules/prompt-injection/ATR-2026-091-nested-payload.yaml +80 -0
  122. package/rules/prompt-injection/ATR-2026-092-consensus-poisoning.yaml +84 -0
  123. package/rules/prompt-injection/ATR-2026-093-gradual-escalation.yaml +78 -0
  124. package/rules/prompt-injection/ATR-2026-094-audit-bypass.yaml +78 -0
  125. package/rules/skill-compromise/ATR-2026-060-skill-impersonation.yaml +1 -1
  126. package/rules/tool-poisoning/ATR-2026-010-mcp-malicious-response.yaml +1 -1
  127. package/rules/tool-poisoning/ATR-2026-011-tool-output-injection.yaml +3 -3
  128. package/rules/tool-poisoning/ATR-2026-012-unauthorized-tool-call.yaml +1 -1
  129. package/rules/tool-poisoning/ATR-2026-013-tool-ssrf.yaml +1 -1
  130. package/rules/tool-poisoning/ATR-2026-095-supply-chain-poisoning.yaml +82 -0
  131. package/rules/tool-poisoning/ATR-2026-096-registry-poisoning.yaml +84 -0
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Action Executor - Executes ATR response actions via platform adapters.
3
+ *
4
+ * Deduplicates actions, sorts by priority, and delegates execution
5
+ * to a PlatformAdapter. Handles per-action errors so one failure
6
+ * does not block the rest.
7
+ *
8
+ * @module agent-threat-rules/action-executor
9
+ */
10
+ /** Priority order: lower number = higher priority (executed first) */
11
+ const ACTION_PRIORITY = {
12
+ kill_agent: 0,
13
+ block_input: 1,
14
+ block_output: 2,
15
+ block_tool: 3,
16
+ quarantine_session: 4,
17
+ reduce_permissions: 5,
18
+ reset_context: 6,
19
+ alert: 7,
20
+ escalate: 8,
21
+ snapshot: 9,
22
+ };
23
+ /** Map action names to PlatformAdapter method names */
24
+ const ACTION_METHOD_MAP = {
25
+ block_input: 'blockInput',
26
+ block_output: 'blockOutput',
27
+ block_tool: 'blockTool',
28
+ quarantine_session: 'quarantineSession',
29
+ reset_context: 'resetContext',
30
+ alert: 'alert',
31
+ snapshot: 'snapshot',
32
+ escalate: 'escalate',
33
+ reduce_permissions: 'reducePermissions',
34
+ kill_agent: 'killAgent',
35
+ };
36
+ export class ActionExecutor {
37
+ adapter;
38
+ dryRun;
39
+ onActionComplete;
40
+ constructor(config) {
41
+ this.adapter = config.adapter;
42
+ this.dryRun = config.dryRun ?? false;
43
+ this.onActionComplete = config.onActionComplete;
44
+ }
45
+ /**
46
+ * Execute all actions from the verdict context.
47
+ *
48
+ * Actions are deduplicated, sorted by priority, and executed
49
+ * sequentially. Each action is wrapped in try/catch so a single
50
+ * failure does not prevent subsequent actions from running.
51
+ *
52
+ * Returns a frozen array of ActionResult.
53
+ */
54
+ async execute(context) {
55
+ const actions = this.deduplicateAndSort(context.verdict.actions);
56
+ const results = [];
57
+ for (const action of actions) {
58
+ const result = await this.executeOne(action, context);
59
+ results.push(result);
60
+ if (this.onActionComplete) {
61
+ this.onActionComplete(result);
62
+ }
63
+ }
64
+ return Object.freeze(results);
65
+ }
66
+ /**
67
+ * Deduplicate actions and sort by priority (highest priority first).
68
+ */
69
+ deduplicateAndSort(actions) {
70
+ const unique = [...new Set(actions)];
71
+ return unique.sort((a, b) => {
72
+ const pa = ACTION_PRIORITY[a] ?? 99;
73
+ const pb = ACTION_PRIORITY[b] ?? 99;
74
+ return pa - pb;
75
+ });
76
+ }
77
+ /**
78
+ * Execute a single action, returning a result even on failure.
79
+ */
80
+ async executeOne(action, context) {
81
+ const timestamp = new Date().toISOString();
82
+ if (this.dryRun) {
83
+ return Object.freeze({
84
+ action,
85
+ success: true,
86
+ message: `[dry-run] Would execute: ${action}`,
87
+ timestamp,
88
+ });
89
+ }
90
+ try {
91
+ const methodName = ACTION_METHOD_MAP[action];
92
+ if (!methodName) {
93
+ return Object.freeze({
94
+ action,
95
+ success: false,
96
+ message: `Unknown action: ${action}`,
97
+ timestamp,
98
+ });
99
+ }
100
+ const method = this.adapter[methodName];
101
+ if (typeof method !== 'function') {
102
+ return Object.freeze({
103
+ action,
104
+ success: false,
105
+ message: `Adapter "${this.adapter.name}" does not implement: ${methodName}`,
106
+ timestamp,
107
+ });
108
+ }
109
+ return await method.call(this.adapter, context);
110
+ }
111
+ catch (err) {
112
+ const message = err instanceof Error ? err.message : String(err);
113
+ return Object.freeze({
114
+ action,
115
+ success: false,
116
+ message: `Action "${action}" failed: ${message}`,
117
+ timestamp,
118
+ });
119
+ }
120
+ }
121
+ /** Get the adapter name for diagnostics */
122
+ getAdapterName() {
123
+ return this.adapter.name;
124
+ }
125
+ /** Check if dry-run mode is enabled */
126
+ isDryRun() {
127
+ return this.dryRun;
128
+ }
129
+ }
130
+ //# sourceMappingURL=action-executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-executor.js","sourceRoot":"","sources":["../src/action-executor.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AASH,sEAAsE;AACtE,MAAM,eAAe,GAAwC;IAC3D,UAAU,EAAE,CAAC;IACb,WAAW,EAAE,CAAC;IACd,YAAY,EAAE,CAAC;IACf,UAAU,EAAE,CAAC;IACb,kBAAkB,EAAE,CAAC;IACrB,kBAAkB,EAAE,CAAC;IACrB,aAAa,EAAE,CAAC;IAChB,KAAK,EAAE,CAAC;IACR,QAAQ,EAAE,CAAC;IACX,QAAQ,EAAE,CAAC;CACZ,CAAC;AAEF,uDAAuD;AACvD,MAAM,iBAAiB,GAAuD;IAC5E,WAAW,EAAE,YAAY;IACzB,YAAY,EAAE,aAAa;IAC3B,UAAU,EAAE,WAAW;IACvB,kBAAkB,EAAE,mBAAmB;IACvC,aAAa,EAAE,cAAc;IAC7B,KAAK,EAAE,OAAO;IACd,QAAQ,EAAE,UAAU;IACpB,QAAQ,EAAE,UAAU;IACpB,kBAAkB,EAAE,mBAAmB;IACvC,UAAU,EAAE,WAAW;CACxB,CAAC;AAQF,MAAM,OAAO,cAAc;IACR,OAAO,CAAkB;IACzB,MAAM,CAAU;IAChB,gBAAgB,CAAkC;IAEnE,YAAY,MAA4B;QACtC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;QAC9B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,KAAK,CAAC;QACrC,IAAI,CAAC,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,CAAC;IAClD,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,OAAO,CAAC,OAAyB;QACrC,MAAM,OAAO,GAAG,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACjE,MAAM,OAAO,GAAmB,EAAE,CAAC;QAEnC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YACtD,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAErB,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBAC1B,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;IAED;;OAEG;IACK,kBAAkB,CACxB,OAA6B;QAE7B,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;QACrC,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YAC1B,MAAM,EAAE,GAAG,eAAe,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACpC,MAAM,EAAE,GAAG,eAAe,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACpC,OAAO,EAAE,GAAG,EAAE,CAAC;QACjB,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,UAAU,CACtB,MAAiB,EACjB,OAAyB;QAEzB,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAE3C,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,OAAO,MAAM,CAAC,MAAM,CAAC;gBACnB,MAAM;gBACN,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,4BAA4B,MAAM,EAAE;gBAC7C,SAAS;aACV,CAAC,CAAC;QACL,CAAC;QAED,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;YAC7C,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,OAAO,MAAM,CAAC,MAAM,CAAC;oBACnB,MAAM;oBACN,OAAO,EAAE,KAAK;oBACd,OAAO,EAAE,mBAAmB,MAAM,EAAE;oBACpC,SAAS;iBACV,CAAC,CAAC;YACL,CAAC;YAED,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAEzB,CAAC;YAEd,IAAI,OAAO,MAAM,KAAK,UAAU,EAAE,CAAC;gBACjC,OAAO,MAAM,CAAC,MAAM,CAAC;oBACnB,MAAM;oBACN,OAAO,EAAE,KAAK;oBACd,OAAO,EAAE,YAAY,IAAI,CAAC,OAAO,CAAC,IAAI,yBAAyB,UAAU,EAAE;oBAC3E,SAAS;iBACV,CAAC,CAAC;YACL,CAAC;YAED,OAAO,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAClD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,OAAO,MAAM,CAAC,MAAM,CAAC;gBACnB,MAAM;gBACN,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,WAAW,MAAM,aAAa,OAAO,EAAE;gBAChD,SAAS;aACV,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,2CAA2C;IAC3C,cAAc;QACZ,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;IAED,uCAAuC;IACvC,QAAQ;QACN,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;CACF"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Default Platform Adapter - No-op implementation for CLI and testing.
3
+ *
4
+ * Every method logs the action and returns a success result.
5
+ * This adapter is safe to use in any environment as it performs
6
+ * no actual enforcement.
7
+ *
8
+ * @module agent-threat-rules/adapters/default-adapter
9
+ */
10
+ import type { ActionResult, ExecutionContext, PlatformAdapter } from '../types.js';
11
+ export declare class DefaultAdapter implements PlatformAdapter {
12
+ readonly name = "default";
13
+ blockInput(ctx: ExecutionContext): Promise<ActionResult>;
14
+ blockOutput(ctx: ExecutionContext): Promise<ActionResult>;
15
+ blockTool(ctx: ExecutionContext): Promise<ActionResult>;
16
+ quarantineSession(ctx: ExecutionContext): Promise<ActionResult>;
17
+ resetContext(ctx: ExecutionContext): Promise<ActionResult>;
18
+ alert(ctx: ExecutionContext): Promise<ActionResult>;
19
+ snapshot(ctx: ExecutionContext): Promise<ActionResult>;
20
+ escalate(ctx: ExecutionContext): Promise<ActionResult>;
21
+ reducePermissions(ctx: ExecutionContext): Promise<ActionResult>;
22
+ killAgent(ctx: ExecutionContext): Promise<ActionResult>;
23
+ }
24
+ //# sourceMappingURL=default-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"default-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/default-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,gBAAgB,EAChB,eAAe,EAChB,MAAM,aAAa,CAAC;AAcrB,qBAAa,cAAe,YAAW,eAAe;IACpD,QAAQ,CAAC,IAAI,aAAa;IAEpB,UAAU,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;IAIxD,WAAW,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;IAIzD,SAAS,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;IAIvD,iBAAiB,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;IAI/D,YAAY,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;IAI1D,KAAK,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;IAInD,QAAQ,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;IAItD,QAAQ,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;IAItD,iBAAiB,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;IAI/D,SAAS,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;CAG9D"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Default Platform Adapter - No-op implementation for CLI and testing.
3
+ *
4
+ * Every method logs the action and returns a success result.
5
+ * This adapter is safe to use in any environment as it performs
6
+ * no actual enforcement.
7
+ *
8
+ * @module agent-threat-rules/adapters/default-adapter
9
+ */
10
+ function createResult(action, ctx) {
11
+ return Object.freeze({
12
+ action,
13
+ success: true,
14
+ message: `[${action}] logged (no-op) for verdict: ${ctx.verdict.outcome}`,
15
+ timestamp: new Date().toISOString(),
16
+ });
17
+ }
18
+ export class DefaultAdapter {
19
+ name = 'default';
20
+ async blockInput(ctx) {
21
+ return createResult('block_input', ctx);
22
+ }
23
+ async blockOutput(ctx) {
24
+ return createResult('block_output', ctx);
25
+ }
26
+ async blockTool(ctx) {
27
+ return createResult('block_tool', ctx);
28
+ }
29
+ async quarantineSession(ctx) {
30
+ return createResult('quarantine_session', ctx);
31
+ }
32
+ async resetContext(ctx) {
33
+ return createResult('reset_context', ctx);
34
+ }
35
+ async alert(ctx) {
36
+ return createResult('alert', ctx);
37
+ }
38
+ async snapshot(ctx) {
39
+ return createResult('snapshot', ctx);
40
+ }
41
+ async escalate(ctx) {
42
+ return createResult('escalate', ctx);
43
+ }
44
+ async reducePermissions(ctx) {
45
+ return createResult('reduce_permissions', ctx);
46
+ }
47
+ async killAgent(ctx) {
48
+ return createResult('kill_agent', ctx);
49
+ }
50
+ }
51
+ //# sourceMappingURL=default-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"default-adapter.js","sourceRoot":"","sources":["../../src/adapters/default-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAQH,SAAS,YAAY,CACnB,MAA8B,EAC9B,GAAqB;IAErB,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,MAAM;QACN,OAAO,EAAE,IAAI;QACb,OAAO,EAAE,IAAI,MAAM,iCAAiC,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE;QACzE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,OAAO,cAAc;IAChB,IAAI,GAAG,SAAS,CAAC;IAE1B,KAAK,CAAC,UAAU,CAAC,GAAqB;QACpC,OAAO,YAAY,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;IAC1C,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,GAAqB;QACrC,OAAO,YAAY,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,GAAqB;QACnC,OAAO,YAAY,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,GAAqB;QAC3C,OAAO,YAAY,CAAC,oBAAoB,EAAE,GAAG,CAAC,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,GAAqB;QACtC,OAAO,YAAY,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,GAAqB;QAC/B,OAAO,YAAY,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACpC,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,GAAqB;QAClC,OAAO,YAAY,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,GAAqB;QAClC,OAAO,YAAY,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,GAAqB;QAC3C,OAAO,YAAY,CAAC,oBAAoB,EAAE,GAAG,CAAC,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,GAAqB;QACnC,OAAO,YAAY,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;IACzC,CAAC;CACF"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Stdio Platform Adapter - Adapter for Claude Code hook integration.
3
+ *
4
+ * Block actions write JSON responses to an internal buffer that can
5
+ * be flushed to stdout. Alert and snapshot actions log to stderr
6
+ * to avoid interfering with the JSON protocol on stdout.
7
+ *
8
+ * @module agent-threat-rules/adapters/stdio-adapter
9
+ */
10
+ import type { ActionResult, ExecutionContext, PlatformAdapter } from '../types.js';
11
+ export declare class StdioAdapter implements PlatformAdapter {
12
+ readonly name = "stdio";
13
+ private readonly responseBuffer;
14
+ /**
15
+ * Get buffered responses and clear the buffer.
16
+ * Returns a frozen copy.
17
+ */
18
+ flushResponses(): readonly unknown[];
19
+ blockInput(ctx: ExecutionContext): Promise<ActionResult>;
20
+ blockOutput(ctx: ExecutionContext): Promise<ActionResult>;
21
+ blockTool(ctx: ExecutionContext): Promise<ActionResult>;
22
+ quarantineSession(ctx: ExecutionContext): Promise<ActionResult>;
23
+ resetContext(ctx: ExecutionContext): Promise<ActionResult>;
24
+ alert(ctx: ExecutionContext): Promise<ActionResult>;
25
+ snapshot(ctx: ExecutionContext): Promise<ActionResult>;
26
+ escalate(ctx: ExecutionContext): Promise<ActionResult>;
27
+ reducePermissions(ctx: ExecutionContext): Promise<ActionResult>;
28
+ killAgent(ctx: ExecutionContext): Promise<ActionResult>;
29
+ }
30
+ //# sourceMappingURL=stdio-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdio-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/stdio-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,gBAAgB,EAChB,eAAe,EAChB,MAAM,aAAa,CAAC;AAcrB,qBAAa,YAAa,YAAW,eAAe;IAClD,QAAQ,CAAC,IAAI,WAAW;IACxB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;IAEhD;;;OAGG;IACH,cAAc,IAAI,SAAS,OAAO,EAAE;IAM9B,UAAU,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;IAUxD,WAAW,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;IAUzD,SAAS,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;IAWvD,iBAAiB,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;IAU/D,YAAY,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;IAS1D,KAAK,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;IAWnD,QAAQ,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;IAetD,QAAQ,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;IAWtD,iBAAiB,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;IAU/D,SAAS,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;CAS9D"}
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Stdio Platform Adapter - Adapter for Claude Code hook integration.
3
+ *
4
+ * Block actions write JSON responses to an internal buffer that can
5
+ * be flushed to stdout. Alert and snapshot actions log to stderr
6
+ * to avoid interfering with the JSON protocol on stdout.
7
+ *
8
+ * @module agent-threat-rules/adapters/stdio-adapter
9
+ */
10
+ function makeResult(action, message) {
11
+ return Object.freeze({
12
+ action,
13
+ success: true,
14
+ message,
15
+ timestamp: new Date().toISOString(),
16
+ });
17
+ }
18
+ export class StdioAdapter {
19
+ name = 'stdio';
20
+ responseBuffer = [];
21
+ /**
22
+ * Get buffered responses and clear the buffer.
23
+ * Returns a frozen copy.
24
+ */
25
+ flushResponses() {
26
+ const copy = Object.freeze([...this.responseBuffer]);
27
+ this.responseBuffer.length = 0;
28
+ return copy;
29
+ }
30
+ async blockInput(ctx) {
31
+ const entry = {
32
+ action: 'block_input',
33
+ verdict: ctx.verdict.outcome,
34
+ reason: ctx.verdict.reason,
35
+ };
36
+ this.responseBuffer.push(entry);
37
+ return makeResult('block_input', 'Input blocked via stdio protocol');
38
+ }
39
+ async blockOutput(ctx) {
40
+ const entry = {
41
+ action: 'block_output',
42
+ verdict: ctx.verdict.outcome,
43
+ reason: ctx.verdict.reason,
44
+ };
45
+ this.responseBuffer.push(entry);
46
+ return makeResult('block_output', 'Output blocked via stdio protocol');
47
+ }
48
+ async blockTool(ctx) {
49
+ const entry = {
50
+ action: 'block_tool',
51
+ verdict: ctx.verdict.outcome,
52
+ reason: ctx.verdict.reason,
53
+ tool: ctx.event.fields?.['tool_name'] ?? 'unknown',
54
+ };
55
+ this.responseBuffer.push(entry);
56
+ return makeResult('block_tool', 'Tool blocked via stdio protocol');
57
+ }
58
+ async quarantineSession(ctx) {
59
+ const entry = {
60
+ action: 'quarantine_session',
61
+ verdict: ctx.verdict.outcome,
62
+ sessionId: ctx.sessionId ?? 'unknown',
63
+ };
64
+ this.responseBuffer.push(entry);
65
+ return makeResult('quarantine_session', 'Session quarantined via stdio protocol');
66
+ }
67
+ async resetContext(ctx) {
68
+ const entry = {
69
+ action: 'reset_context',
70
+ verdict: ctx.verdict.outcome,
71
+ };
72
+ this.responseBuffer.push(entry);
73
+ return makeResult('reset_context', 'Context reset via stdio protocol');
74
+ }
75
+ async alert(ctx) {
76
+ const alertMsg = {
77
+ type: 'alert',
78
+ severity: ctx.verdict.highestSeverity,
79
+ reason: ctx.verdict.reason,
80
+ matchCount: ctx.verdict.matchCount,
81
+ };
82
+ process.stderr.write(JSON.stringify(alertMsg) + '\n');
83
+ return makeResult('alert', 'Alert written to stderr');
84
+ }
85
+ async snapshot(ctx) {
86
+ const snapshotData = {
87
+ type: 'snapshot',
88
+ event: {
89
+ type: ctx.event.type,
90
+ contentPreview: ctx.event.content.slice(0, 200),
91
+ },
92
+ verdict: ctx.verdict.outcome,
93
+ matchCount: ctx.verdict.matchCount,
94
+ timestamp: new Date().toISOString(),
95
+ };
96
+ process.stderr.write(JSON.stringify(snapshotData) + '\n');
97
+ return makeResult('snapshot', 'Snapshot written to stderr');
98
+ }
99
+ async escalate(ctx) {
100
+ const escalation = {
101
+ type: 'escalation',
102
+ severity: ctx.verdict.highestSeverity,
103
+ reason: ctx.verdict.reason,
104
+ matchCount: ctx.verdict.matchCount,
105
+ };
106
+ process.stderr.write(JSON.stringify(escalation) + '\n');
107
+ return makeResult('escalate', 'Escalation written to stderr');
108
+ }
109
+ async reducePermissions(ctx) {
110
+ const entry = {
111
+ action: 'reduce_permissions',
112
+ verdict: ctx.verdict.outcome,
113
+ reason: ctx.verdict.reason,
114
+ };
115
+ this.responseBuffer.push(entry);
116
+ return makeResult('reduce_permissions', 'Permissions reduced via stdio protocol');
117
+ }
118
+ async killAgent(ctx) {
119
+ const entry = {
120
+ action: 'kill_agent',
121
+ verdict: ctx.verdict.outcome,
122
+ reason: ctx.verdict.reason,
123
+ };
124
+ this.responseBuffer.push(entry);
125
+ return makeResult('kill_agent', 'Agent kill requested via stdio protocol');
126
+ }
127
+ }
128
+ //# sourceMappingURL=stdio-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdio-adapter.js","sourceRoot":"","sources":["../../src/adapters/stdio-adapter.ts"],"names":[],"mappings":"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"}
package/dist/cli.js CHANGED
@@ -38,11 +38,17 @@ ${BOLD}Usage:${RESET}
38
38
  atr validate <rule.yaml|dir> Validate rule file(s)
39
39
  atr test <rule.yaml|dir> Run embedded test cases
40
40
  atr stats [--rules <dir>] Show rule collection statistics
41
+ atr guard [--rules <dir>] [--dry-run] Start as Claude Code hook (stdio)
42
+ atr mcp Start MCP server (stdio transport)
43
+ atr scaffold Interactive rule scaffolding
41
44
 
42
45
  ${BOLD}Options:${RESET}
43
46
  --rules <dir> Custom rules directory (default: bundled rules)
44
47
  --json Output results as JSON
45
48
  --severity <s> Minimum severity to report (critical|high|medium|low|informational)
49
+ --dry-run Log actions without executing (guard mode)
50
+ --fail-open Default to allow on errors (guard mode, default: true)
51
+ --timeout <ms> Evaluation timeout in ms (guard mode, default: 5000)
46
52
  --help Show this help message
47
53
 
48
54
  ${BOLD}Examples:${RESET}
@@ -57,6 +63,15 @@ ${BOLD}Examples:${RESET}
57
63
 
58
64
  ${DIM}# Show stats for bundled rules${RESET}
59
65
  atr stats
66
+
67
+ ${DIM}# Run as a Claude Code guard hook${RESET}
68
+ atr guard --rules ./my-rules
69
+
70
+ ${DIM}# Start MCP server for AI agent integration${RESET}
71
+ atr mcp
72
+
73
+ ${DIM}# Interactively scaffold a new rule${RESET}
74
+ atr scaffold
60
75
  `);
61
76
  }
62
77
  function parseArgs(argv) {
@@ -67,7 +82,7 @@ function parseArgs(argv) {
67
82
  for (let i = 1; i < args.length; i++) {
68
83
  if (args[i].startsWith('--')) {
69
84
  const key = args[i].slice(2);
70
- if (key === 'json' || key === 'help') {
85
+ if (key === 'json' || key === 'help' || key === 'dry-run' || key === 'fail-open') {
71
86
  options[key] = 'true';
72
87
  }
73
88
  else {
@@ -511,6 +526,100 @@ function cmdStats(options) {
511
526
  }
512
527
  console.log('');
513
528
  }
529
+ // --- GUARD command ---
530
+ async function cmdGuard(options) {
531
+ const rulesDir = options['rules'] ? resolve(options['rules']) : RULES_DIR;
532
+ const dryRun = options['dry-run'] === 'true';
533
+ const failOpen = options['fail-open'] !== 'false';
534
+ const timeoutMs = options['timeout'] ? parseInt(options['timeout'], 10) : 5000;
535
+ const { ActionExecutor } = await import('./action-executor.js');
536
+ const { StdioAdapter } = await import('./adapters/stdio-adapter.js');
537
+ const { HookHandler } = await import('./hook-handler.js');
538
+ const engine = new ATREngine({ rulesDir });
539
+ const ruleCount = await engine.loadRules();
540
+ const adapter = new StdioAdapter();
541
+ const executor = new ActionExecutor({ adapter, dryRun });
542
+ const handler = new HookHandler({ engine, executor, timeoutMs, failOpen });
543
+ process.stderr.write(`[atr-guard] Loaded ${ruleCount} rules from ${rulesDir}` +
544
+ `${dryRun ? ' (dry-run)' : ''}\n`);
545
+ await handler.startStdioLoop();
546
+ }
547
+ // --- MCP command ---
548
+ async function cmdMcp() {
549
+ const { startMCPServer } = await import('./mcp-server.js');
550
+ await startMCPServer();
551
+ }
552
+ // --- SCAFFOLD command ---
553
+ async function cmdScaffold() {
554
+ const { createInterface } = await import('node:readline');
555
+ const { RuleScaffolder } = await import('./rule-scaffolder.js');
556
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
557
+ const ask = (question) => new Promise((resolve) => rl.question(question, resolve));
558
+ console.log(`\n${BOLD}ATR Rule Scaffolder${RESET}`);
559
+ console.log(`${DIM}Generate a draft ATR detection rule interactively.${RESET}\n`);
560
+ const title = await ask('Rule title: ');
561
+ if (!title.trim()) {
562
+ console.error(`${RED}Error: Title is required.${RESET}`);
563
+ rl.close();
564
+ process.exit(1);
565
+ }
566
+ const categories = [
567
+ 'prompt-injection', 'tool-poisoning', 'context-exfiltration',
568
+ 'agent-manipulation', 'privilege-escalation', 'excessive-autonomy',
569
+ 'data-poisoning', 'model-abuse', 'skill-compromise',
570
+ ];
571
+ console.log(`\nCategories: ${categories.join(', ')}`);
572
+ const category = await ask('Category: ');
573
+ if (!categories.includes(category.trim())) {
574
+ console.error(`${RED}Error: Invalid category.${RESET}`);
575
+ rl.close();
576
+ process.exit(1);
577
+ }
578
+ const attackDescription = await ask('Attack description: ');
579
+ if (!attackDescription.trim()) {
580
+ console.error(`${RED}Error: Description is required.${RESET}`);
581
+ rl.close();
582
+ process.exit(1);
583
+ }
584
+ console.log('\nEnter example payloads (one per line, empty line to finish):');
585
+ const payloads = [];
586
+ while (true) {
587
+ const payload = await ask(` Payload ${payloads.length + 1}: `);
588
+ if (!payload.trim())
589
+ break;
590
+ payloads.push(payload.trim());
591
+ }
592
+ if (payloads.length === 0) {
593
+ console.error(`${RED}Error: At least one example payload is required.${RESET}`);
594
+ rl.close();
595
+ process.exit(1);
596
+ }
597
+ const severities = ['critical', 'high', 'medium', 'low', 'informational'];
598
+ const severity = await ask(`Severity [${severities.join('/')}] (default: medium): `);
599
+ const finalSeverity = severity.trim() && severities.includes(severity.trim())
600
+ ? severity.trim()
601
+ : 'medium';
602
+ rl.close();
603
+ const scaffolder = new RuleScaffolder();
604
+ const result = scaffolder.scaffold({
605
+ title: title.trim(),
606
+ category: category.trim(),
607
+ attackDescription: attackDescription.trim(),
608
+ examplePayloads: payloads,
609
+ severity: finalSeverity,
610
+ });
611
+ console.log(`\n${GREEN}Generated rule ${result.id}:${RESET}\n`);
612
+ console.log(`${DIM}${'─'.repeat(60)}${RESET}`);
613
+ console.log(result.yaml);
614
+ console.log(`${DIM}${'─'.repeat(60)}${RESET}`);
615
+ if (result.warnings.length > 0) {
616
+ console.log(`\n${BOLD}Warnings:${RESET}`);
617
+ for (const w of result.warnings) {
618
+ console.log(` - ${w}`);
619
+ }
620
+ }
621
+ console.log(`\n${DIM}Copy this YAML to a .yaml file in rules/${category.trim()}/ and validate with: atr validate <file>${RESET}\n`);
622
+ }
514
623
  // --- Main ---
515
624
  async function main() {
516
625
  const { command, target, options } = parseArgs(process.argv);
@@ -531,6 +640,15 @@ async function main() {
531
640
  case 'stats':
532
641
  cmdStats(options);
533
642
  break;
643
+ case 'guard':
644
+ await cmdGuard(options);
645
+ break;
646
+ case 'mcp':
647
+ await cmdMcp();
648
+ break;
649
+ case 'scaffold':
650
+ await cmdScaffold();
651
+ break;
534
652
  default:
535
653
  console.error(`${RED}Unknown command: ${command}${RESET}`);
536
654
  printUsage();