mcp-rce-guard 0.1.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.
Files changed (91) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +155 -0
  3. package/dist/audit/log.d.ts +75 -0
  4. package/dist/audit/log.d.ts.map +1 -0
  5. package/dist/audit/log.js +191 -0
  6. package/dist/audit/log.js.map +1 -0
  7. package/dist/canary/tracker.d.ts +38 -0
  8. package/dist/canary/tracker.d.ts.map +1 -0
  9. package/dist/canary/tracker.js +40 -0
  10. package/dist/canary/tracker.js.map +1 -0
  11. package/dist/cli.d.ts +14 -0
  12. package/dist/cli.d.ts.map +1 -0
  13. package/dist/cli.js +128 -0
  14. package/dist/cli.js.map +1 -0
  15. package/dist/cve/replay.d.ts +44 -0
  16. package/dist/cve/replay.d.ts.map +1 -0
  17. package/dist/cve/replay.js +221 -0
  18. package/dist/cve/replay.js.map +1 -0
  19. package/dist/egress/policy.d.ts +27 -0
  20. package/dist/egress/policy.d.ts.map +1 -0
  21. package/dist/egress/policy.js +62 -0
  22. package/dist/egress/policy.js.map +1 -0
  23. package/dist/index.d.ts +27 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +38 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/isolation/cgroups.d.ts +20 -0
  28. package/dist/isolation/cgroups.d.ts.map +1 -0
  29. package/dist/isolation/cgroups.js +33 -0
  30. package/dist/isolation/cgroups.js.map +1 -0
  31. package/dist/isolation/landlock.d.ts +42 -0
  32. package/dist/isolation/landlock.d.ts.map +1 -0
  33. package/dist/isolation/landlock.js +67 -0
  34. package/dist/isolation/landlock.js.map +1 -0
  35. package/dist/isolation/platform.d.ts +27 -0
  36. package/dist/isolation/platform.d.ts.map +1 -0
  37. package/dist/isolation/platform.js +96 -0
  38. package/dist/isolation/platform.js.map +1 -0
  39. package/dist/isolation/sandbox-exec.d.ts +17 -0
  40. package/dist/isolation/sandbox-exec.d.ts.map +1 -0
  41. package/dist/isolation/sandbox-exec.js +58 -0
  42. package/dist/isolation/sandbox-exec.js.map +1 -0
  43. package/dist/normalize.d.ts +32 -0
  44. package/dist/normalize.d.ts.map +1 -0
  45. package/dist/normalize.js +66 -0
  46. package/dist/normalize.js.map +1 -0
  47. package/dist/server.d.ts +15 -0
  48. package/dist/server.d.ts.map +1 -0
  49. package/dist/server.js +152 -0
  50. package/dist/server.js.map +1 -0
  51. package/dist/state.d.ts +34 -0
  52. package/dist/state.d.ts.map +1 -0
  53. package/dist/state.js +104 -0
  54. package/dist/state.js.map +1 -0
  55. package/dist/tools/audit.d.ts +26 -0
  56. package/dist/tools/audit.d.ts.map +1 -0
  57. package/dist/tools/audit.js +97 -0
  58. package/dist/tools/audit.js.map +1 -0
  59. package/dist/tools/getAuditLog.d.ts +34 -0
  60. package/dist/tools/getAuditLog.d.ts.map +1 -0
  61. package/dist/tools/getAuditLog.js +65 -0
  62. package/dist/tools/getAuditLog.js.map +1 -0
  63. package/dist/tools/injectEgress.d.ts +21 -0
  64. package/dist/tools/injectEgress.d.ts.map +1 -0
  65. package/dist/tools/injectEgress.js +49 -0
  66. package/dist/tools/injectEgress.js.map +1 -0
  67. package/dist/tools/register.d.ts +16 -0
  68. package/dist/tools/register.d.ts.map +1 -0
  69. package/dist/tools/register.js +44 -0
  70. package/dist/tools/register.js.map +1 -0
  71. package/dist/tools/scanCve.d.ts +14 -0
  72. package/dist/tools/scanCve.d.ts.map +1 -0
  73. package/dist/tools/scanCve.js +29 -0
  74. package/dist/tools/scanCve.js.map +1 -0
  75. package/dist/tools/trackCanary.d.ts +23 -0
  76. package/dist/tools/trackCanary.d.ts.map +1 -0
  77. package/dist/tools/trackCanary.js +44 -0
  78. package/dist/tools/trackCanary.js.map +1 -0
  79. package/dist/trust-tiers.d.ts +18 -0
  80. package/dist/trust-tiers.d.ts.map +1 -0
  81. package/dist/trust-tiers.js +73 -0
  82. package/dist/trust-tiers.js.map +1 -0
  83. package/dist/types.d.ts +187 -0
  84. package/dist/types.d.ts.map +1 -0
  85. package/dist/types.js +82 -0
  86. package/dist/types.js.map +1 -0
  87. package/dist/version.d.ts +7 -0
  88. package/dist/version.d.ts.map +1 -0
  89. package/dist/version.js +14 -0
  90. package/dist/version.js.map +1 -0
  91. package/package.json +74 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EACL,4BAA4B,EAC5B,yBAAyB,EACzB,uBAAuB,EACvB,qBAAqB,EACrB,4BAA4B,EAC5B,qBAAqB,EACtB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAQ7C,SAAS,EAAE,CAAC,MAAe;IACzB,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;KACnE,CAAC;AACJ,CAAC;AAED,SAAS,GAAG,CAAC,OAAe;IAC1B,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QAC1C,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,IAAI,CAAI,EAAoB;IACzC,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACxB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,GAAG,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACvD,OAAO,GAAG,CAAC,wBAAwB,GAAG,EAAE,CAAC,CAAC;IAC5C,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,EAChC;QACE,YAAY,EAAE;YACZ,KAAK,EAAE,EAAE;SACV;QACD,YAAY,EACV,ooBAAooB;KACvoB,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,qBAAqB,EACrB;QACE,KAAK,EAAE,yCAAyC;QAChD,WAAW,EACT,0VAA0V;QAC5V,WAAW,EAAE,4BAA4B,CAAC,KAAK;QAC/C,WAAW,EAAE;YACX,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,KAAK;YACrB,aAAa,EAAE,KAAK;SACrB;KACF,EACD,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC,CACzD,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,kBAAkB,EAClB;QACE,KAAK,EAAE,4BAA4B;QACnC,WAAW,EACT,+JAA+J;QACjK,WAAW,EAAE,yBAAyB,CAAC,KAAK;QAC5C,WAAW,EAAE;YACX,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,KAAK;SACrB;KACF,EACD,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CACtD,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,iBAAiB,EACjB;QACE,KAAK,EAAE,yBAAyB;QAChC,WAAW,EACT,4JAA4J;QAC9J,WAAW,EAAE,uBAAuB,CAAC,KAAK;QAC1C,WAAW,EAAE;YACX,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,KAAK;SACrB;KACF,EACD,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CACpD,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,cAAc,EACd;QACE,KAAK,EAAE,qCAAqC;QAC5C,WAAW,EACT,mRAAmR;QACrR,WAAW,EAAE,qBAAqB,CAAC,KAAK;QACxC,WAAW,EAAE;YACX,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,KAAK;YACrB,aAAa,EAAE,KAAK;SACrB;KACF,EACD,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAClD,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,sBAAsB,EACtB;QACE,KAAK,EAAE,+BAA+B;QACtC,WAAW,EACT,0VAA0V;QAC5V,WAAW,EAAE,4BAA4B,CAAC,KAAK;QAC/C,WAAW,EAAE;YACX,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,KAAK;SACrB;KACF,EACD,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC,CACzD,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,eAAe,EACf;QACE,KAAK,EAAE,gBAAgB;QACvB,WAAW,EACT,gGAAgG;QAClG,WAAW,EAAE,qBAAqB,CAAC,KAAK;QACxC,WAAW,EAAE;YACX,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,KAAK;SACrB;KACF,EACD,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAClD,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,IAAI;IACxB,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAE7C,sEAAsE;IACtE,MAAM,QAAQ,GAAG,KAAK,EAAE,MAAc,EAAiB,EAAE;QACvD,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACvB,CAAC;QAAC,MAAM,CAAC;YACP,cAAc;QAChB,CAAC;QACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,MAAM,aAAa,CAAC,CAAC;QACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;IACtD,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEpD,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,mBAAmB,OAAO,iCAAiC,CAC5D,CAAC;AACJ,CAAC;AAED,MAAM,QAAQ,GAAG,CAAC,GAAG,EAAE;IACrB,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,UAAU,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5C,OAAO,OAAO,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;IAC/E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC,CAAC,EAAE,CAAC;AAEL,IAAI,QAAQ,EAAE,CAAC;IACb,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;QACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA2B,CAAW,CAAC,OAAO,IAAI,CAAC,CAAC;QACzE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * In-memory subprocess registry + canary chain registry.
3
+ *
4
+ * Process-local state. The persistent audit-log lives in audit/log.ts (NDJSON).
5
+ *
6
+ * v0.1 trade-off: registry is in-memory and resets on server restart. v0.2 will
7
+ * persist to ~/.mcp-rce-guard/registry.json with optional Pillar-1 signing.
8
+ */
9
+ import type { EgressMode, IsolationProfile, RegisteredSubprocess } from "./types.js";
10
+ interface CanaryChain {
11
+ chainId: string;
12
+ sourceServerId: string;
13
+ downstreamServerIds: string[];
14
+ canaryToken: string;
15
+ canaryPattern: string;
16
+ createdAt: string;
17
+ }
18
+ /**
19
+ * Compute a stable fingerprint for a profile. Two registrations with the
20
+ * same effective profile must produce the same fingerprint.
21
+ */
22
+ export declare function profileFingerprint(profile: IsolationProfile): string;
23
+ export declare function generateHandle(prefix?: string): string;
24
+ export declare function registerSubprocess(serverId: string, binary: string, args: string[], trustTier: RegisteredSubprocess["trustTier"], profile: IsolationProfile): RegisteredSubprocess;
25
+ export declare function getSubprocess(handle: string): RegisteredSubprocess | undefined;
26
+ export declare function listSubprocesses(): readonly RegisteredSubprocess[];
27
+ export declare function updateEgressPolicy(handle: string, allowlist: string[], mode: EgressMode): RegisteredSubprocess | undefined;
28
+ export declare function bumpBlockedEgress(handle: string, by?: number): void;
29
+ export declare function clearRegistry(): void;
30
+ export declare function generateCanaryToken(): string;
31
+ export declare function registerCanaryChain(chainId: string, sourceServerId: string, downstreamServerIds: string[], canaryPattern: string, canaryToken: string): CanaryChain;
32
+ export declare function getCanaryChain(chainId: string): CanaryChain | undefined;
33
+ export {};
34
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EACV,UAAU,EACV,gBAAgB,EAChB,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAIpB,UAAU,WAAW;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAID;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAUpE;AAED,wBAAgB,cAAc,CAAC,MAAM,SAAO,GAAG,MAAM,CAEpD;AAED,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EAAE,EACd,SAAS,EAAE,oBAAoB,CAAC,WAAW,CAAC,EAC5C,OAAO,EAAE,gBAAgB,GACxB,oBAAoB,CAkBtB;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS,CAE9E;AAED,wBAAgB,gBAAgB,IAAI,SAAS,oBAAoB,EAAE,CAElE;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EAAE,EACnB,IAAI,EAAE,UAAU,GACf,oBAAoB,GAAG,SAAS,CAgBlC;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,SAAI,GAAG,IAAI,CAI9D;AAED,wBAAgB,aAAa,IAAI,IAAI,CAGpC;AAID,wBAAgB,mBAAmB,IAAI,MAAM,CAI5C;AAED,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,MAAM,EACtB,mBAAmB,EAAE,MAAM,EAAE,EAC7B,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,MAAM,GAClB,WAAW,CAWb;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAEvE"}
package/dist/state.js ADDED
@@ -0,0 +1,104 @@
1
+ /**
2
+ * In-memory subprocess registry + canary chain registry.
3
+ *
4
+ * Process-local state. The persistent audit-log lives in audit/log.ts (NDJSON).
5
+ *
6
+ * v0.1 trade-off: registry is in-memory and resets on server restart. v0.2 will
7
+ * persist to ~/.mcp-rce-guard/registry.json with optional Pillar-1 signing.
8
+ */
9
+ import { createHash, randomBytes } from "node:crypto";
10
+ const subprocesses = new Map();
11
+ const canaryChains = new Map();
12
+ /**
13
+ * Compute a stable fingerprint for a profile. Two registrations with the
14
+ * same effective profile must produce the same fingerprint.
15
+ */
16
+ export function profileFingerprint(profile) {
17
+ const canonical = JSON.stringify({
18
+ fsReadOnly: [...profile.fsReadOnly].sort(),
19
+ fsWritable: [...profile.fsWritable].sort(),
20
+ cpuMs: profile.cpuMs ?? null,
21
+ memMB: profile.memMB ?? null,
22
+ pidMax: profile.pidMax ?? null,
23
+ egressAllowlist: [...profile.egressAllowlist].sort()
24
+ });
25
+ return createHash("sha256").update(canonical).digest("hex").slice(0, 32);
26
+ }
27
+ export function generateHandle(prefix = "sp") {
28
+ return `${prefix}_${randomBytes(12).toString("hex")}`;
29
+ }
30
+ export function registerSubprocess(serverId, binary, args, trustTier, profile) {
31
+ const subprocessHandle = generateHandle();
32
+ const now = new Date().toISOString();
33
+ const record = {
34
+ subprocessHandle,
35
+ serverId,
36
+ binary,
37
+ args: [...args],
38
+ trustTier,
39
+ profile,
40
+ profileFingerprint: profileFingerprint(profile),
41
+ egressMode: "default-deny",
42
+ egressModeSetAt: now,
43
+ blockedEgressAttempts: 0,
44
+ registeredAt: now
45
+ };
46
+ subprocesses.set(subprocessHandle, record);
47
+ return record;
48
+ }
49
+ export function getSubprocess(handle) {
50
+ return subprocesses.get(handle);
51
+ }
52
+ export function listSubprocesses() {
53
+ return Array.from(subprocesses.values());
54
+ }
55
+ export function updateEgressPolicy(handle, allowlist, mode) {
56
+ const record = subprocesses.get(handle);
57
+ if (!record)
58
+ return undefined;
59
+ record.profile = {
60
+ ...record.profile,
61
+ egressAllowlist: [...allowlist]
62
+ };
63
+ record.profileFingerprint = profileFingerprint(record.profile);
64
+ // Only bump egressModeSetAt when the mode actually transitions. Pure
65
+ // allowlist edits without mode-change keep the original timestamp so the
66
+ // staleness WARN measures actual mode-dwell time, not edit churn.
67
+ if (record.egressMode !== mode) {
68
+ record.egressMode = mode;
69
+ record.egressModeSetAt = new Date().toISOString();
70
+ }
71
+ return record;
72
+ }
73
+ export function bumpBlockedEgress(handle, by = 1) {
74
+ const record = subprocesses.get(handle);
75
+ if (!record)
76
+ return;
77
+ record.blockedEgressAttempts += by;
78
+ }
79
+ export function clearRegistry() {
80
+ subprocesses.clear();
81
+ canaryChains.clear();
82
+ }
83
+ /* canary chains */
84
+ export function generateCanaryToken() {
85
+ // 32-byte high-entropy hex; prefix marks it as a canary so legitimate
86
+ // tools can detect + redact in their logs.
87
+ return `__MCP_CANARY_${randomBytes(32).toString("hex")}__`;
88
+ }
89
+ export function registerCanaryChain(chainId, sourceServerId, downstreamServerIds, canaryPattern, canaryToken) {
90
+ const chain = {
91
+ chainId,
92
+ sourceServerId,
93
+ downstreamServerIds: [...downstreamServerIds],
94
+ canaryToken,
95
+ canaryPattern,
96
+ createdAt: new Date().toISOString()
97
+ };
98
+ canaryChains.set(chainId, chain);
99
+ return chain;
100
+ }
101
+ export function getCanaryChain(chainId) {
102
+ return canaryChains.get(chainId);
103
+ }
104
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Tool: audit_subprocess
3
+ *
4
+ * Verifies a candidate args set against the registered subprocess profile.
5
+ * Returns approve | block | quarantine + reason.
6
+ *
7
+ * Layer-2 (Pillar 8) interaction: args are normalized via the shared
8
+ * normalize.ts pipeline (NFKC + ZWC + Bidi) before any comparison.
9
+ *
10
+ * Layer-1 (Pillar 1) interaction: when MCP_RCE_GUARD_PILLAR1_FINGERPRINT is
11
+ * set in the environment, the tool reflects that into pillar1Fingerprint
12
+ * for cross-pillar audit traceability. v0.1 trust-on-first-use, v0.2 will
13
+ * verify against a Sigstore key.
14
+ *
15
+ * Anti-Pattern provenance: MCP-SDK-RCE 22.04.2026 (Tool-Args ungesanitized
16
+ * in subprocess command-strings).
17
+ */
18
+ import { type AuditVerdictType } from "../types.js";
19
+ export interface AuditSubprocessResult {
20
+ verdict: AuditVerdictType;
21
+ reason: string;
22
+ pillar1Fingerprint?: string;
23
+ pillar8Allowlist: "pass" | "fail";
24
+ }
25
+ export declare function auditSubprocessTool(rawArgs: unknown): Promise<AuditSubprocessResult>;
26
+ //# sourceMappingURL=audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/tools/audit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,aAAa,CAAC;AAKrB,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,gBAAgB,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAAC;CACnC;AAED,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,qBAAqB,CAAC,CAgFhC"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Tool: audit_subprocess
3
+ *
4
+ * Verifies a candidate args set against the registered subprocess profile.
5
+ * Returns approve | block | quarantine + reason.
6
+ *
7
+ * Layer-2 (Pillar 8) interaction: args are normalized via the shared
8
+ * normalize.ts pipeline (NFKC + ZWC + Bidi) before any comparison.
9
+ *
10
+ * Layer-1 (Pillar 1) interaction: when MCP_RCE_GUARD_PILLAR1_FINGERPRINT is
11
+ * set in the environment, the tool reflects that into pillar1Fingerprint
12
+ * for cross-pillar audit traceability. v0.1 trust-on-first-use, v0.2 will
13
+ * verify against a Sigstore key.
14
+ *
15
+ * Anti-Pattern provenance: MCP-SDK-RCE 22.04.2026 (Tool-Args ungesanitized
16
+ * in subprocess command-strings).
17
+ */
18
+ import { AuditSubprocessArgsSchema } from "../types.js";
19
+ import { getSubprocess } from "../state.js";
20
+ import { normalizeArgs, hasInvisibleCodepoints } from "../normalize.js";
21
+ import { appendAudit } from "../audit/log.js";
22
+ export async function auditSubprocessTool(rawArgs) {
23
+ const args = AuditSubprocessArgsSchema.parse(rawArgs);
24
+ const record = getSubprocess(args.subprocessHandle);
25
+ if (!record) {
26
+ const result = {
27
+ verdict: "block",
28
+ reason: `unknown subprocess handle: ${args.subprocessHandle}`,
29
+ pillar8Allowlist: "fail"
30
+ };
31
+ await appendAudit({
32
+ subprocessHandle: args.subprocessHandle,
33
+ action: "audit_subprocess",
34
+ verdict: "block",
35
+ reason: result.reason
36
+ });
37
+ return result;
38
+ }
39
+ // Pillar 8: normalize + allowlist check.
40
+ const normalizedRequested = normalizeArgs(args.requestedArgs);
41
+ const normalizedRegistered = normalizeArgs(record.args);
42
+ // Detection signal: any invisible codepoint in requested args raises
43
+ // suspicion even if normalization makes the args comparable.
44
+ const suspicious = args.requestedArgs.some(hasInvisibleCodepoints);
45
+ // Allowlist semantics: requested args must be a prefix/exact-match of
46
+ // registered args (the registered args are the *trusted invocation*).
47
+ let pillar8 = "pass";
48
+ let mismatchReason = "";
49
+ if (normalizedRequested.length !== normalizedRegistered.length) {
50
+ pillar8 = "fail";
51
+ mismatchReason = `arg-count mismatch: requested=${normalizedRequested.length}, registered=${normalizedRegistered.length}`;
52
+ }
53
+ else {
54
+ for (let i = 0; i < normalizedRequested.length; i++) {
55
+ if (normalizedRequested[i] !== normalizedRegistered[i]) {
56
+ pillar8 = "fail";
57
+ mismatchReason = `arg[${i}] mismatch: requested=${JSON.stringify(normalizedRequested[i])}, registered=${JSON.stringify(normalizedRegistered[i])}`;
58
+ break;
59
+ }
60
+ }
61
+ }
62
+ let verdict;
63
+ let reason;
64
+ if (pillar8 === "fail") {
65
+ verdict = "block";
66
+ reason = `Pillar-8 allowlist fail: ${mismatchReason}`;
67
+ }
68
+ else if (suspicious) {
69
+ verdict = "quarantine";
70
+ reason = "args contain invisible/bidi codepoints; quarantine for human review";
71
+ }
72
+ else {
73
+ verdict = "approve";
74
+ reason = "Pillar-8 allowlist pass + no suspicious codepoints";
75
+ }
76
+ const pillar1 = process.env["MCP_RCE_GUARD_PILLAR1_FINGERPRINT"];
77
+ const result = {
78
+ verdict,
79
+ reason,
80
+ pillar8Allowlist: pillar8,
81
+ ...(pillar1 ? { pillar1Fingerprint: pillar1 } : {})
82
+ };
83
+ await appendAudit({
84
+ subprocessHandle: record.subprocessHandle,
85
+ serverId: record.serverId,
86
+ action: "audit_subprocess",
87
+ verdict,
88
+ reason,
89
+ meta: {
90
+ pillar8: pillar8,
91
+ suspicious,
92
+ profileFingerprint: record.profileFingerprint
93
+ }
94
+ });
95
+ return result;
96
+ }
97
+ //# sourceMappingURL=audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/tools/audit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Tool: get_audit_log
3
+ *
4
+ * Read-only access to the NDJSON audit log. Filterable by subprocessHandle,
5
+ * since-timestamp, and limit.
6
+ *
7
+ * Additionally emits a `staleEgressModeWarnings` array: every currently-
8
+ * registered subprocess that has been left in egressMode="audit-only" longer
9
+ * than `staleEgressModeThresholdDays` (default 7) is surfaced as a WARN.
10
+ * This implements the PLAN.md §Predicted-Impact §inject_egress_policy
11
+ * at-risk-regression-mitigation ("Reviewer-Pass im Pillar-9-Audit-Tool
12
+ * flaggt 'Mode: audit-only seit >7d' als WARN") so operators do not
13
+ * silently sit on a soft policy.
14
+ *
15
+ * Log rotation lives in audit/log.ts (auto-rotate on 100MB threshold,
16
+ * 10 backups, `mcp-rce-guard cleanup` CLI for manual purge).
17
+ */
18
+ import { type AuditLogEntry, type StaleEgressModeWarning } from "../types.js";
19
+ export interface GetAuditLogResult {
20
+ entries: AuditLogEntry[];
21
+ staleEgressModeWarnings: StaleEgressModeWarning[];
22
+ }
23
+ /**
24
+ * Build the staleness-WARN list. A subprocess is stale if:
25
+ * - egressMode === "audit-only", AND
26
+ * - now() - egressModeSetAt > thresholdDays
27
+ *
28
+ * Threshold 0 disables the check (returns empty array). Subprocesses with
29
+ * an unparseable egressModeSetAt are skipped silently — better to under-warn
30
+ * than to false-positive on a malformed timestamp.
31
+ */
32
+ export declare function computeStaleEgressModeWarnings(thresholdDays: number, now?: Date): StaleEgressModeWarning[];
33
+ export declare function getAuditLogTool(rawArgs: unknown): Promise<GetAuditLogResult>;
34
+ //# sourceMappingURL=getAuditLog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getAuditLog.d.ts","sourceRoot":"","sources":["../../src/tools/getAuditLog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,sBAAsB,EAC5B,MAAM,aAAa,CAAC;AAIrB,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,uBAAuB,EAAE,sBAAsB,EAAE,CAAC;CACnD;AAID;;;;;;;;GAQG;AACH,wBAAgB,8BAA8B,CAC5C,aAAa,EAAE,MAAM,EACrB,GAAG,GAAE,IAAiB,GACrB,sBAAsB,EAAE,CAmB1B;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAiBlF"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Tool: get_audit_log
3
+ *
4
+ * Read-only access to the NDJSON audit log. Filterable by subprocessHandle,
5
+ * since-timestamp, and limit.
6
+ *
7
+ * Additionally emits a `staleEgressModeWarnings` array: every currently-
8
+ * registered subprocess that has been left in egressMode="audit-only" longer
9
+ * than `staleEgressModeThresholdDays` (default 7) is surfaced as a WARN.
10
+ * This implements the PLAN.md §Predicted-Impact §inject_egress_policy
11
+ * at-risk-regression-mitigation ("Reviewer-Pass im Pillar-9-Audit-Tool
12
+ * flaggt 'Mode: audit-only seit >7d' als WARN") so operators do not
13
+ * silently sit on a soft policy.
14
+ *
15
+ * Log rotation lives in audit/log.ts (auto-rotate on 100MB threshold,
16
+ * 10 backups, `mcp-rce-guard cleanup` CLI for manual purge).
17
+ */
18
+ import { GetAuditLogArgsSchema } from "../types.js";
19
+ import { readAudit } from "../audit/log.js";
20
+ import { listSubprocesses } from "../state.js";
21
+ const MS_PER_DAY = 24 * 60 * 60 * 1000;
22
+ /**
23
+ * Build the staleness-WARN list. A subprocess is stale if:
24
+ * - egressMode === "audit-only", AND
25
+ * - now() - egressModeSetAt > thresholdDays
26
+ *
27
+ * Threshold 0 disables the check (returns empty array). Subprocesses with
28
+ * an unparseable egressModeSetAt are skipped silently — better to under-warn
29
+ * than to false-positive on a malformed timestamp.
30
+ */
31
+ export function computeStaleEgressModeWarnings(thresholdDays, now = new Date()) {
32
+ if (thresholdDays <= 0)
33
+ return [];
34
+ const warnings = [];
35
+ for (const sp of listSubprocesses()) {
36
+ if (sp.egressMode !== "audit-only")
37
+ continue;
38
+ const setAt = Date.parse(sp.egressModeSetAt);
39
+ if (!Number.isFinite(setAt))
40
+ continue;
41
+ const ageDays = (now.getTime() - setAt) / MS_PER_DAY;
42
+ if (ageDays > thresholdDays) {
43
+ warnings.push({
44
+ subprocessHandle: sp.subprocessHandle,
45
+ serverId: sp.serverId,
46
+ egressMode: sp.egressMode,
47
+ egressModeSetAt: sp.egressModeSetAt,
48
+ ageDays: Math.round(ageDays * 100) / 100
49
+ });
50
+ }
51
+ }
52
+ return warnings;
53
+ }
54
+ export async function getAuditLogTool(rawArgs) {
55
+ const args = GetAuditLogArgsSchema.parse(rawArgs);
56
+ const filter = { limit: args.limit };
57
+ if (args.subprocessHandle !== undefined)
58
+ filter.subprocessHandle = args.subprocessHandle;
59
+ if (args.since !== undefined)
60
+ filter.since = args.since;
61
+ const entries = await readAudit(filter);
62
+ const staleEgressModeWarnings = computeStaleEgressModeWarnings(args.staleEgressModeThresholdDays);
63
+ return { entries, staleEgressModeWarnings };
64
+ }
65
+ //# sourceMappingURL=getAuditLog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getAuditLog.js","sourceRoot":"","sources":["../../src/tools/getAuditLog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EACL,qBAAqB,EAItB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAO/C,MAAM,UAAU,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAEvC;;;;;;;;GAQG;AACH,MAAM,UAAU,8BAA8B,CAC5C,aAAqB,EACrB,MAAY,IAAI,IAAI,EAAE;IAEtB,IAAI,aAAa,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IAClC,MAAM,QAAQ,GAA6B,EAAE,CAAC;IAC9C,KAAK,MAAM,EAAE,IAAI,gBAAgB,EAAE,EAAE,CAAC;QACpC,IAAI,EAAE,CAAC,UAAU,KAAK,YAAY;YAAE,SAAS;QAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC;QAC7C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,SAAS;QACtC,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,KAAK,CAAC,GAAG,UAAU,CAAC;QACrD,IAAI,OAAO,GAAG,aAAa,EAAE,CAAC;YAC5B,QAAQ,CAAC,IAAI,CAAC;gBACZ,gBAAgB,EAAE,EAAE,CAAC,gBAAgB;gBACrC,QAAQ,EAAE,EAAE,CAAC,QAAQ;gBACrB,UAAU,EAAE,EAAE,CAAC,UAAU;gBACzB,eAAe,EAAE,EAAE,CAAC,eAAe;gBACnC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,GAAG,CAAC,GAAG,GAAG;aACzC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAAgB;IACpD,MAAM,IAAI,GAAoB,qBAAqB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAEnE,MAAM,MAAM,GAIR,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;IAC1B,IAAI,IAAI,CAAC,gBAAgB,KAAK,SAAS;QAAE,MAAM,CAAC,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,CAAC;IACzF,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;QAAE,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;IAExD,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,uBAAuB,GAAG,8BAA8B,CAC5D,IAAI,CAAC,4BAA4B,CAClC,CAAC;IAEF,OAAO,EAAE,OAAO,EAAE,uBAAuB,EAAE,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Tool: inject_egress_policy
3
+ *
4
+ * Updates a registered subprocess's egress allowlist + mode. Destructive:
5
+ * modifies runtime policy. Returns applied + cumulative blocked-attempts
6
+ * counter (since registration).
7
+ *
8
+ * Anti-Pattern provenance: Nginx-MCP RCE CVSS 9.8 (subprocess kann beliebig
9
+ * egress → exfiltration via curl/wget/raw-socket vom kompromittierten
10
+ * subprocess).
11
+ *
12
+ * Mode trade-off: audit-only erlaubt Operators die Policy zu bauen ohne
13
+ * Production-Traffic zu brechen, aber ist eine "soft policy" — get_audit_log
14
+ * markiert mode prominent damit Operator nicht in audit-only haengen bleiben.
15
+ */
16
+ export interface InjectEgressPolicyResult {
17
+ applied: boolean;
18
+ blockedAttempts: number;
19
+ }
20
+ export declare function injectEgressPolicyTool(rawArgs: unknown): Promise<InjectEgressPolicyResult>;
21
+ //# sourceMappingURL=injectEgress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"injectEgress.d.ts","sourceRoot":"","sources":["../../src/tools/injectEgress.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AASH,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,wBAAwB,CAAC,CAgCnC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Tool: inject_egress_policy
3
+ *
4
+ * Updates a registered subprocess's egress allowlist + mode. Destructive:
5
+ * modifies runtime policy. Returns applied + cumulative blocked-attempts
6
+ * counter (since registration).
7
+ *
8
+ * Anti-Pattern provenance: Nginx-MCP RCE CVSS 9.8 (subprocess kann beliebig
9
+ * egress → exfiltration via curl/wget/raw-socket vom kompromittierten
10
+ * subprocess).
11
+ *
12
+ * Mode trade-off: audit-only erlaubt Operators die Policy zu bauen ohne
13
+ * Production-Traffic zu brechen, aber ist eine "soft policy" — get_audit_log
14
+ * markiert mode prominent damit Operator nicht in audit-only haengen bleiben.
15
+ */
16
+ import { InjectEgressPolicyArgsSchema } from "../types.js";
17
+ import { updateEgressPolicy, getSubprocess } from "../state.js";
18
+ import { appendAudit } from "../audit/log.js";
19
+ export async function injectEgressPolicyTool(rawArgs) {
20
+ const args = InjectEgressPolicyArgsSchema.parse(rawArgs);
21
+ const updated = updateEgressPolicy(args.subprocessHandle, args.allowlist, args.mode);
22
+ if (!updated) {
23
+ await appendAudit({
24
+ subprocessHandle: args.subprocessHandle,
25
+ action: "inject_egress_policy",
26
+ verdict: "block",
27
+ reason: "unknown subprocess handle"
28
+ });
29
+ return { applied: false, blockedAttempts: 0 };
30
+ }
31
+ await appendAudit({
32
+ subprocessHandle: updated.subprocessHandle,
33
+ serverId: updated.serverId,
34
+ action: "inject_egress_policy",
35
+ verdict: "approve",
36
+ meta: {
37
+ mode: updated.egressMode,
38
+ allowlistSize: args.allowlist.length,
39
+ profileFingerprint: updated.profileFingerprint
40
+ }
41
+ });
42
+ // Re-read counter (could have been bumped by a concurrent egress evaluator).
43
+ const fresh = getSubprocess(updated.subprocessHandle);
44
+ return {
45
+ applied: true,
46
+ blockedAttempts: fresh?.blockedEgressAttempts ?? 0
47
+ };
48
+ }
49
+ //# sourceMappingURL=injectEgress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"injectEgress.js","sourceRoot":"","sources":["../../src/tools/injectEgress.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EACL,4BAA4B,EAE7B,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAO9C,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,OAAgB;IAEhB,MAAM,IAAI,GAA2B,4BAA4B,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAEjF,MAAM,OAAO,GAAG,kBAAkB,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACrF,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,WAAW,CAAC;YAChB,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;YACvC,MAAM,EAAE,sBAAsB;YAC9B,OAAO,EAAE,OAAO;YAChB,MAAM,EAAE,2BAA2B;SACpC,CAAC,CAAC;QACH,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC,EAAE,CAAC;IAChD,CAAC;IAED,MAAM,WAAW,CAAC;QAChB,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;QAC1C,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,MAAM,EAAE,sBAAsB;QAC9B,OAAO,EAAE,SAAS;QAClB,IAAI,EAAE;YACJ,IAAI,EAAE,OAAO,CAAC,UAAU;YACxB,aAAa,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM;YACpC,kBAAkB,EAAE,OAAO,CAAC,kBAAkB;SAC/C;KACF,CAAC,CAAC;IAEH,6EAA6E;IAC7E,MAAM,KAAK,GAAG,aAAa,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACtD,OAAO;QACL,OAAO,EAAE,IAAI;QACb,eAAe,EAAE,KAAK,EAAE,qBAAqB,IAAI,CAAC;KACnD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Tool: register_subprocess
3
+ *
4
+ * Registers a subprocess spec + isolation profile and returns a handle.
5
+ * Profile defaults are filled in from the trust tier; caller-supplied
6
+ * fields override the tier defaults.
7
+ *
8
+ * Anti-Pattern provenance: Nginx-MCP RCE CVSS 9.8 (subprocess inheritert
9
+ * volle parent-permissions weil keine Profile-Defaults existieren).
10
+ */
11
+ export interface RegisterSubprocessResult {
12
+ subprocessHandle: string;
13
+ profileFingerprint: string;
14
+ }
15
+ export declare function registerSubprocessTool(rawArgs: unknown): Promise<RegisterSubprocessResult>;
16
+ //# sourceMappingURL=register.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../src/tools/register.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAWH,MAAM,WAAW,wBAAwB;IACvC,gBAAgB,EAAE,MAAM,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,wBAAwB,CAAC,CAqCnC"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Tool: register_subprocess
3
+ *
4
+ * Registers a subprocess spec + isolation profile and returns a handle.
5
+ * Profile defaults are filled in from the trust tier; caller-supplied
6
+ * fields override the tier defaults.
7
+ *
8
+ * Anti-Pattern provenance: Nginx-MCP RCE CVSS 9.8 (subprocess inheritert
9
+ * volle parent-permissions weil keine Profile-Defaults existieren).
10
+ */
11
+ import { RegisterSubprocessArgsSchema } from "../types.js";
12
+ import { resolveProfile } from "../trust-tiers.js";
13
+ import { registerSubprocess } from "../state.js";
14
+ import { appendAudit } from "../audit/log.js";
15
+ import { normalizeArg, normalizeArgs } from "../normalize.js";
16
+ export async function registerSubprocessTool(rawArgs) {
17
+ const args = RegisterSubprocessArgsSchema.parse(rawArgs);
18
+ // Pre-Publish-Audit F6: NFKC + ZWC-strip + Bidi-block on binary + args at
19
+ // registration time so the stored allowlist is already in canonical form.
20
+ // audit_subprocess normalizes the candidate args the same way; storing the
21
+ // canonical form here removes a fullwidth-unicode bypass class where an
22
+ // attacker registers a "binary" that includes invisible codepoints and
23
+ // later spawns a normalized lookalike that compares equal.
24
+ const normalizedBinary = normalizeArg(args.binary);
25
+ const normalizedArgs = normalizeArgs(args.args);
26
+ const profile = resolveProfile(args.trustTier, args.isolationProfile);
27
+ const record = registerSubprocess(args.serverId, normalizedBinary, normalizedArgs, args.trustTier, profile);
28
+ await appendAudit({
29
+ subprocessHandle: record.subprocessHandle,
30
+ serverId: record.serverId,
31
+ action: "register_subprocess",
32
+ verdict: "approve",
33
+ meta: {
34
+ binary: record.binary,
35
+ trustTier: record.trustTier,
36
+ profileFingerprint: record.profileFingerprint
37
+ }
38
+ });
39
+ return {
40
+ subprocessHandle: record.subprocessHandle,
41
+ profileFingerprint: record.profileFingerprint
42
+ };
43
+ }
44
+ //# sourceMappingURL=register.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.js","sourceRoot":"","sources":["../../src/tools/register.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EACL,4BAA4B,EAE7B,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAO9D,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,OAAgB;IAEhB,MAAM,IAAI,GAA2B,4BAA4B,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAEjF,0EAA0E;IAC1E,0EAA0E;IAC1E,2EAA2E;IAC3E,wEAAwE;IACxE,uEAAuE;IACvE,2DAA2D;IAC3D,MAAM,gBAAgB,GAAG,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnD,MAAM,cAAc,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEhD,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC;IACtE,MAAM,MAAM,GAAG,kBAAkB,CAC/B,IAAI,CAAC,QAAQ,EACb,gBAAgB,EAChB,cAAc,EACd,IAAI,CAAC,SAAS,EACd,OAAO,CACR,CAAC;IAEF,MAAM,WAAW,CAAC;QAChB,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;QACzC,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,MAAM,EAAE,qBAAqB;QAC7B,OAAO,EAAE,SAAS;QAClB,IAAI,EAAE;YACJ,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,kBAAkB,EAAE,MAAM,CAAC,kBAAkB;SAC9C;KACF,CAAC,CAAC;IAEH,OAAO;QACL,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;QACzC,kBAAkB,EAAE,MAAM,CAAC,kBAAkB;KAC9C,CAAC;AACJ,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Tool: scan_cve_replay
3
+ *
4
+ * Runs the built-in CVE replay fixtures against a target server command.
5
+ * Returns overall pass/fail + per-CVE detail.
6
+ *
7
+ * Anti-Pattern provenance: alle 3 frischen 2026-CVEs (MCP-SDK-RCE
8
+ * 22.04.2026, CVE-2026-27124 FastMCP Confused Deputy, Nginx-MCP RCE
9
+ * CVSS 9.8). Predicates leben in src/cve/replay.ts und sind als
10
+ * behavioral predicates designed (kein exploit payload).
11
+ */
12
+ import { type ReplayResult } from "../cve/replay.js";
13
+ export declare function scanCveReplayTool(rawArgs: unknown): Promise<ReplayResult>;
14
+ //# sourceMappingURL=scanCve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanCve.d.ts","sourceRoot":"","sources":["../../src/tools/scanCve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,OAAO,EAAa,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGhE,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC,CAgB/E"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Tool: scan_cve_replay
3
+ *
4
+ * Runs the built-in CVE replay fixtures against a target server command.
5
+ * Returns overall pass/fail + per-CVE detail.
6
+ *
7
+ * Anti-Pattern provenance: alle 3 frischen 2026-CVEs (MCP-SDK-RCE
8
+ * 22.04.2026, CVE-2026-27124 FastMCP Confused Deputy, Nginx-MCP RCE
9
+ * CVSS 9.8). Predicates leben in src/cve/replay.ts und sind als
10
+ * behavioral predicates designed (kein exploit payload).
11
+ */
12
+ import { ScanCveReplayArgsSchema } from "../types.js";
13
+ import { runReplay } from "../cve/replay.js";
14
+ import { appendAudit } from "../audit/log.js";
15
+ export async function scanCveReplayTool(rawArgs) {
16
+ const args = ScanCveReplayArgsSchema.parse(rawArgs);
17
+ const result = runReplay(args.targetServerCommand, args.cveSet, args.timeoutMs);
18
+ await appendAudit({
19
+ subprocessHandle: "n/a",
20
+ action: "scan_cve_replay",
21
+ verdict: result.overall,
22
+ meta: {
23
+ targetServerCommand: args.targetServerCommand,
24
+ perCve: result.perCve.map((r) => ({ id: r.id, status: r.status }))
25
+ }
26
+ });
27
+ return result;
28
+ }
29
+ //# sourceMappingURL=scanCve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanCve.js","sourceRoot":"","sources":["../../src/tools/scanCve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EACL,uBAAuB,EAExB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,SAAS,EAAqB,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE9C,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,OAAgB;IACtD,MAAM,IAAI,GAAsB,uBAAuB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAEvE,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,mBAAmB,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IAEhF,MAAM,WAAW,CAAC;QAChB,gBAAgB,EAAE,KAAK;QACvB,MAAM,EAAE,iBAAiB;QACzB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,IAAI,EAAE;YACJ,mBAAmB,EAAE,IAAI,CAAC,mBAAmB;YAC7C,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;SACnE;KACF,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Tool: track_canary
3
+ *
4
+ * Issues a canary token + registers a chain. v0.1 returns the token + a
5
+ * pre-evaluated leakDetected=false because actual leak detection requires
6
+ * the calling MCP-aware controller to feed downstream-server output back
7
+ * via a corpus parameter (added in v0.2).
8
+ *
9
+ * Pattern provenance: arXiv 2604.27819 (MCPHunt, April 2026) — taint
10
+ * tracking via canary-token injection across MCP server boundaries.
11
+ *
12
+ * Confused-Deputy defense (CVE-2026-27124): if the chain controller pipes
13
+ * downstream output back to detect_leaks, a leak via egress channel will
14
+ * be flagged.
15
+ */
16
+ import { type LeakLocation } from "../canary/tracker.js";
17
+ export interface TrackCanaryResult {
18
+ canaryToken: string;
19
+ leakDetected: boolean;
20
+ leakLocations: LeakLocation[];
21
+ }
22
+ export declare function trackCanaryTool(rawArgs: unknown): Promise<TrackCanaryResult>;
23
+ //# sourceMappingURL=trackCanary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trackCanary.d.ts","sourceRoot":"","sources":["../../src/tools/trackCanary.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAOH,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGrE,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB,aAAa,EAAE,YAAY,EAAE,CAAC;CAC/B;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAgClF"}