@mcp-audit-gateway/core 0.2.0 → 0.4.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.
- package/.github/workflows/ci.yml +37 -0
- package/README.md +31 -3
- package/dist/attestation/audit-log.d.ts +34 -3
- package/dist/attestation/audit-log.d.ts.map +1 -1
- package/dist/attestation/audit-log.js +286 -10
- package/dist/attestation/audit-log.js.map +1 -1
- package/dist/attestation/checkpoint.test.d.ts +2 -0
- package/dist/attestation/checkpoint.test.d.ts.map +1 -0
- package/dist/attestation/checkpoint.test.js +870 -0
- package/dist/attestation/checkpoint.test.js.map +1 -0
- package/dist/attestation/signer.d.ts +24 -9
- package/dist/attestation/signer.d.ts.map +1 -1
- package/dist/attestation/signer.js +145 -11
- package/dist/attestation/signer.js.map +1 -1
- package/dist/attestation/signer.test.js +11 -0
- package/dist/attestation/signer.test.js.map +1 -1
- package/dist/attestation/verify.d.ts +23 -2
- package/dist/attestation/verify.d.ts.map +1 -1
- package/dist/attestation/verify.js +219 -2
- package/dist/attestation/verify.js.map +1 -1
- package/dist/integration.test.js +1 -0
- package/dist/integration.test.js.map +1 -1
- package/dist/proxy/gateway.d.ts +4 -0
- package/dist/proxy/gateway.d.ts.map +1 -1
- package/dist/proxy/gateway.js +4 -1
- package/dist/proxy/gateway.js.map +1 -1
- package/dist/proxy/gateway.test.js +19 -0
- package/dist/proxy/gateway.test.js.map +1 -1
- package/dist/proxy/mcp-server-adapter.d.ts +1 -0
- package/dist/proxy/mcp-server-adapter.d.ts.map +1 -1
- package/dist/proxy/mcp-server-adapter.js +28 -1
- package/dist/proxy/mcp-server-adapter.js.map +1 -1
- package/dist/proxy/mcp-server-adapter.test.js +1 -0
- package/dist/proxy/mcp-server-adapter.test.js.map +1 -1
- package/dist/types.d.ts +74 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +13 -0
- package/dist/types.js.map +1 -1
- package/dist/wrap/proxy.test.js +2 -2
- package/dist/wrap/proxy.test.js.map +1 -1
- package/docs/BACKLOG.md +33 -0
- package/docs/SECURITY-DESIGN.md +126 -0
- package/docs/v0.4.0-patch-audit.md +115 -0
- package/package.json +1 -1
- package/src/attestation/audit-log.ts +336 -15
- package/src/attestation/checkpoint.test.ts +956 -0
- package/src/attestation/signer.test.ts +14 -0
- package/src/attestation/signer.ts +152 -19
- package/src/attestation/verify.ts +270 -4
- package/src/integration.test.ts +1 -0
- package/src/proxy/gateway.test.ts +18 -0
- package/src/proxy/gateway.ts +4 -0
- package/src/proxy/mcp-server-adapter.test.ts +1 -0
- package/src/proxy/mcp-server-adapter.ts +26 -0
- package/src/types.ts +48 -0
- package/src/wrap/proxy.test.ts +2 -2
- package/test/vectors/aps-action-ref-v1-vectors.json +351 -0
- package/test/vectors/aps-action-ref-v1.mjs +145 -0
- package/test/vectors/canonicalization.json +182 -0
- package/test/vectors/checkpoint.json +450 -0
- package/test/vectors/verify-checkpoint.mjs +344 -0
- package/test/vectors/verify-checkpoint.py +358 -0
- package/test/vectors/verify.mjs +74 -1
- package/test/vectors/verify.py +78 -1
package/dist/types.d.ts
CHANGED
|
@@ -132,6 +132,22 @@ export declare const TelemetryConfigSchema: z.ZodObject<{
|
|
|
132
132
|
serviceName?: string | undefined;
|
|
133
133
|
sampleRate?: number | undefined;
|
|
134
134
|
}>;
|
|
135
|
+
export declare const CheckpointConfigSchema: z.ZodObject<{
|
|
136
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
137
|
+
intervalRecords: z.ZodDefault<z.ZodNumber>;
|
|
138
|
+
intervalSeconds: z.ZodDefault<z.ZodNumber>;
|
|
139
|
+
trigger: z.ZodDefault<z.ZodEnum<["records", "time", "whichever_first"]>>;
|
|
140
|
+
}, "strip", z.ZodTypeAny, {
|
|
141
|
+
enabled: boolean;
|
|
142
|
+
intervalRecords: number;
|
|
143
|
+
intervalSeconds: number;
|
|
144
|
+
trigger: "records" | "time" | "whichever_first";
|
|
145
|
+
}, {
|
|
146
|
+
enabled?: boolean | undefined;
|
|
147
|
+
intervalRecords?: number | undefined;
|
|
148
|
+
intervalSeconds?: number | undefined;
|
|
149
|
+
trigger?: "records" | "time" | "whichever_first" | undefined;
|
|
150
|
+
}>;
|
|
135
151
|
export declare const GatewayConfigSchema: z.ZodObject<{
|
|
136
152
|
name: z.ZodDefault<z.ZodString>;
|
|
137
153
|
version: z.ZodDefault<z.ZodString>;
|
|
@@ -324,6 +340,22 @@ export declare const GatewayConfigSchema: z.ZodObject<{
|
|
|
324
340
|
enabled?: boolean | undefined;
|
|
325
341
|
rotateAfterMb?: number | undefined;
|
|
326
342
|
}>>;
|
|
343
|
+
checkpoint: z.ZodDefault<z.ZodObject<{
|
|
344
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
345
|
+
intervalRecords: z.ZodDefault<z.ZodNumber>;
|
|
346
|
+
intervalSeconds: z.ZodDefault<z.ZodNumber>;
|
|
347
|
+
trigger: z.ZodDefault<z.ZodEnum<["records", "time", "whichever_first"]>>;
|
|
348
|
+
}, "strip", z.ZodTypeAny, {
|
|
349
|
+
enabled: boolean;
|
|
350
|
+
intervalRecords: number;
|
|
351
|
+
intervalSeconds: number;
|
|
352
|
+
trigger: "records" | "time" | "whichever_first";
|
|
353
|
+
}, {
|
|
354
|
+
enabled?: boolean | undefined;
|
|
355
|
+
intervalRecords?: number | undefined;
|
|
356
|
+
intervalSeconds?: number | undefined;
|
|
357
|
+
trigger?: "records" | "time" | "whichever_first" | undefined;
|
|
358
|
+
}>>;
|
|
327
359
|
}, "strip", z.ZodTypeAny, {
|
|
328
360
|
name: string;
|
|
329
361
|
version: string;
|
|
@@ -380,6 +412,12 @@ export declare const GatewayConfigSchema: z.ZodObject<{
|
|
|
380
412
|
enabled: boolean;
|
|
381
413
|
rotateAfterMb: number;
|
|
382
414
|
};
|
|
415
|
+
checkpoint: {
|
|
416
|
+
enabled: boolean;
|
|
417
|
+
intervalRecords: number;
|
|
418
|
+
intervalSeconds: number;
|
|
419
|
+
trigger: "records" | "time" | "whichever_first";
|
|
420
|
+
};
|
|
383
421
|
}, {
|
|
384
422
|
upstreams: {
|
|
385
423
|
name: string;
|
|
@@ -436,6 +474,12 @@ export declare const GatewayConfigSchema: z.ZodObject<{
|
|
|
436
474
|
enabled?: boolean | undefined;
|
|
437
475
|
rotateAfterMb?: number | undefined;
|
|
438
476
|
} | undefined;
|
|
477
|
+
checkpoint?: {
|
|
478
|
+
enabled?: boolean | undefined;
|
|
479
|
+
intervalRecords?: number | undefined;
|
|
480
|
+
intervalSeconds?: number | undefined;
|
|
481
|
+
trigger?: "records" | "time" | "whichever_first" | undefined;
|
|
482
|
+
} | undefined;
|
|
439
483
|
}>;
|
|
440
484
|
export type UpstreamConfig = z.infer<typeof UpstreamConfigSchema>;
|
|
441
485
|
export type PolicyRule = z.infer<typeof PolicyRuleSchema>;
|
|
@@ -456,6 +500,11 @@ export interface PartyAttribution {
|
|
|
456
500
|
role: "witness" | "asserter";
|
|
457
501
|
scope: string[];
|
|
458
502
|
}
|
|
503
|
+
export interface AiInvocationContext {
|
|
504
|
+
turnId?: string;
|
|
505
|
+
invocationReason?: string;
|
|
506
|
+
model?: string;
|
|
507
|
+
}
|
|
459
508
|
export interface AuditRecord {
|
|
460
509
|
id: string;
|
|
461
510
|
timestamp: string;
|
|
@@ -468,10 +517,35 @@ export interface AuditRecord {
|
|
|
468
517
|
success: boolean;
|
|
469
518
|
errorCode?: number;
|
|
470
519
|
decisionContextDigest?: string;
|
|
520
|
+
extensionsDigest?: string;
|
|
521
|
+
aiInvocation?: AiInvocationContext;
|
|
471
522
|
parties?: PartyAttribution[];
|
|
472
523
|
previousHash?: string;
|
|
473
524
|
attestation?: string;
|
|
474
525
|
}
|
|
526
|
+
export interface CheckpointRecord {
|
|
527
|
+
id: string;
|
|
528
|
+
type: "checkpoint";
|
|
529
|
+
timestamp: string;
|
|
530
|
+
sequence: number;
|
|
531
|
+
recordCount: number;
|
|
532
|
+
previousHash: string;
|
|
533
|
+
parties?: PartyAttribution[];
|
|
534
|
+
attestation?: string;
|
|
535
|
+
}
|
|
536
|
+
export interface ChainBreakRecord {
|
|
537
|
+
id: string;
|
|
538
|
+
type: "chain_break";
|
|
539
|
+
timestamp: string;
|
|
540
|
+
reason: string;
|
|
541
|
+
priorHead?: string;
|
|
542
|
+
priorSequence?: number;
|
|
543
|
+
priorRecordCount?: number;
|
|
544
|
+
attestation?: string;
|
|
545
|
+
}
|
|
546
|
+
export type ChainRecord = AuditRecord | CheckpointRecord | ChainBreakRecord;
|
|
547
|
+
export declare function isCheckpoint(record: ChainRecord): record is CheckpointRecord;
|
|
548
|
+
export declare function isChainBreak(record: ChainRecord): record is ChainBreakRecord;
|
|
475
549
|
export interface ToolEntry {
|
|
476
550
|
name: string;
|
|
477
551
|
originalName: string;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiB/B,CAAC;AAEH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAW3B,CAAC;AAEH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;EAOlC,CAAC;AAEH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;EAKhC,CAAC;AAEH,eAAO,MAAM,mBAAmB
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
CHANGED
|
@@ -43,6 +43,12 @@ export const TelemetryConfigSchema = z.object({
|
|
|
43
43
|
serviceName: z.string().default("mcp-audit-gateway"),
|
|
44
44
|
sampleRate: z.number().min(0).max(1).default(1.0),
|
|
45
45
|
});
|
|
46
|
+
export const CheckpointConfigSchema = z.object({
|
|
47
|
+
enabled: z.boolean().default(false),
|
|
48
|
+
intervalRecords: z.number().positive().default(100),
|
|
49
|
+
intervalSeconds: z.number().positive().default(60),
|
|
50
|
+
trigger: z.enum(["records", "time", "whichever_first"]).default("whichever_first"),
|
|
51
|
+
});
|
|
46
52
|
export const GatewayConfigSchema = z.object({
|
|
47
53
|
name: z.string().default("mcp-audit-gateway"),
|
|
48
54
|
version: z.string().default("0.1.0"),
|
|
@@ -64,5 +70,12 @@ export const GatewayConfigSchema = z.object({
|
|
|
64
70
|
path: z.string().default("./audit.jsonl"),
|
|
65
71
|
rotateAfterMb: z.number().positive().default(100),
|
|
66
72
|
}).default({}),
|
|
73
|
+
checkpoint: CheckpointConfigSchema.default({}),
|
|
67
74
|
});
|
|
75
|
+
export function isCheckpoint(record) {
|
|
76
|
+
return "type" in record && record.type === "checkpoint";
|
|
77
|
+
}
|
|
78
|
+
export function isChainBreak(record) {
|
|
79
|
+
return "type" in record && record.type === "chain_break";
|
|
80
|
+
}
|
|
68
81
|
//# sourceMappingURL=types.js.map
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/wrap/proxy.test.js
CHANGED
|
@@ -42,7 +42,7 @@ describe("wrap proxy", () => {
|
|
|
42
42
|
catch { }
|
|
43
43
|
}
|
|
44
44
|
});
|
|
45
|
-
it("forwards non-tool messages transparently", async () => {
|
|
45
|
+
it.skipIf(!process.env.RUN_E2E)("forwards non-tool messages transparently", async () => {
|
|
46
46
|
const proc = spawn("node", [CLI_PATH, "wrap", "--", "node", "-e", `
|
|
47
47
|
process.stdin.setEncoding('utf-8');
|
|
48
48
|
let buf = '';
|
|
@@ -74,7 +74,7 @@ describe("wrap proxy", () => {
|
|
|
74
74
|
expect(parsed[1].id).toBe(2);
|
|
75
75
|
expect(parsed[1].result.resources).toBeDefined();
|
|
76
76
|
});
|
|
77
|
-
it("logs tool calls with attestation", async () => {
|
|
77
|
+
it.skipIf(!process.env.RUN_E2E)("logs tool calls with attestation", async () => {
|
|
78
78
|
const proc = spawn("node", [CLI_PATH, "wrap", "--", "node", "-e", `
|
|
79
79
|
process.stdin.setEncoding('utf-8');
|
|
80
80
|
let buf = '';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy.test.js","sourceRoot":"","sources":["../../src/wrap/proxy.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACrE,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,YAAY,CAAC,CAAC;AAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;AAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;AAEhE,SAAS,WAAW,CAAC,IAA8B,EAAE,GAAW;IAC9D,IAAI,CAAC,KAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;AAChD,CAAC;AAED,SAAS,YAAY,CAAC,IAA8B;IAClD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,IAAI,CAAC,MAAO,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;YAChC,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YAC3E,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;QACvB,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,IAAI,WAAW,GAAkB,IAAI,CAAC;IAEtC,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,IAAI,CAAC;YACH,WAAW,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAClD,CAAC;QAAC,MAAM,CAAC;YACP,WAAW,GAAG,IAAI,CAAC;QACrB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;YACzB,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;YACvD,MAAM,SAAS,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;QACzC,CAAC;aAAM,CAAC;YACN,IAAI,CAAC;gBAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;QACtC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;
|
|
1
|
+
{"version":3,"file":"proxy.test.js","sourceRoot":"","sources":["../../src/wrap/proxy.test.ts"],"names":[],"mappings":"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"}
|
package/docs/BACKLOG.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# v0.3.x Backlog (Deferred, Non-Blocking)
|
|
2
|
+
|
|
3
|
+
Items explicitly deferred during Rounds 1-6 review. None block the v0.3.0 tag. All should become issues before fixture work begins.
|
|
4
|
+
|
|
5
|
+
## Executable verification-mode vectors
|
|
6
|
+
|
|
7
|
+
Add conformance vectors for `verifyCompleteness` covering: strict-mode pass, relative-mode pass with `absoluteCountVerified: false`, and delta-mismatch negative case. Currently tested only via unit tests, not cross-language vectors.
|
|
8
|
+
|
|
9
|
+
Deferred in: Round 3 (to the APS fixture pass).
|
|
10
|
+
|
|
11
|
+
## Relative-mode post-break segment anchoring
|
|
12
|
+
|
|
13
|
+
In relative mode, a suffix starting with `chain_break, rec1, rec2, ckpt(recordCount=2)` could verify that the first checkpoint's count matches records between the break and it. Currently skipped (relative mode can't verify absolute counts). The question is whether relative mode should verify counts *within its own suffix* while still reporting `absoluteCountVerified: false`.
|
|
14
|
+
|
|
15
|
+
Deferred in: Round 4, Q3.
|
|
16
|
+
|
|
17
|
+
## State file signing
|
|
18
|
+
|
|
19
|
+
Sign the state file with the same key used for records. Prevents fabrication by an attacker with file access but no key access. Does NOT prevent replay of an old validly-signed state file (the linkage check handles replay). Additive, non-breaking.
|
|
20
|
+
|
|
21
|
+
Deferred in: Round 4, Q2.
|
|
22
|
+
|
|
23
|
+
## Richer chainBreaks array
|
|
24
|
+
|
|
25
|
+
Replace `hasChainBreak: boolean` in verification results with `chainBreaks: Array<{index, reason, priorHead?, timestamp}>`. A consumer deciding whether to accept a broken chain needs which/why/when. Verifier-side, non-breaking.
|
|
26
|
+
|
|
27
|
+
Deferred in: Round 3, Q3.
|
|
28
|
+
|
|
29
|
+
## Python verifier for APS action-ref-v1 vectors
|
|
30
|
+
|
|
31
|
+
The 46 checkpoint conformance vectors have JS + Python parity. The 51 adapted APS action-ref-v1 vectors are JS-only (the upstream APS conformance suite is JS-only). Cross-language parity applies to our native vectors; adapted third-party fixtures match the upstream language. A Python runner would strengthen the parity story but is not blocking.
|
|
32
|
+
|
|
33
|
+
Added: Post-APS adaptation.
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Security Design
|
|
2
|
+
|
|
3
|
+
This document describes the security invariants of the attestation and checkpoint subsystem, the threat model they address, and the pitfalls discovered during adversarial design review.
|
|
4
|
+
|
|
5
|
+
## Threat Model
|
|
6
|
+
|
|
7
|
+
The attestation layer defends against three classes of attack on audit logs:
|
|
8
|
+
|
|
9
|
+
1. **Truncation**: an operator or compromised process deletes records from the tail of a log file to hide evidence of tool calls.
|
|
10
|
+
2. **Tampering**: modification of individual records (field values, ordering, or removal) after they are written.
|
|
11
|
+
3. **Planted state**: an attacker with filesystem access fabricates or replays the `.state.json` file to make the system resume from a false position, enabling silent truncation of the real log.
|
|
12
|
+
|
|
13
|
+
The system does NOT defend against an attacker who holds the signing key AND has write access to both log and state files simultaneously. At that point, the attacker can forge new valid records. Key management (KMS, HSM, or envelope encryption) is the defense for that layer.
|
|
14
|
+
|
|
15
|
+
## Security Properties
|
|
16
|
+
|
|
17
|
+
| # | Property | Mechanism | Round Introduced |
|
|
18
|
+
|---|----------|-----------|-----------------|
|
|
19
|
+
| 1 | Injective canonical form | Type-tagged containers: objects become `["M", pairs]`, arrays become `["L", values]` | Round 3 |
|
|
20
|
+
| 2 | Cross-language sort equivalence | UTF-16 code-unit sort order; Python uses `key.encode("utf-16-be")` | Round 4 |
|
|
21
|
+
| 3 | Unpaired surrogate rejection | `assertWellFormedString` at all four canonicalization entry points | Rounds 4-5 |
|
|
22
|
+
| 4 | Hash chain continuity across rotation | `rotationBoundaryHash` persisted at rotation; first record of new file chains from it | Round 5 |
|
|
23
|
+
| 5 | Planted state detection | Exact linkage check: first record's `previousHash` must equal `rotationBoundaryHash` in state file | Round 5 |
|
|
24
|
+
| 6 | No false-positive after chain break | `rotationBoundaryHash` is separate from `lastHash`; only `persistState()` (rotation) updates it | Round 5 |
|
|
25
|
+
| 7 | Fail-closed on corrupt input | Unparseable first line, oversized first line, and empty log all refuse to start | Rounds 5-6 |
|
|
26
|
+
| 8 | Segmented monotonicity | Checkpoint sequence regression checked per-segment; `chain_break` resets the segment | Round 3 |
|
|
27
|
+
| 9 | Segment-initial absolute anchor | First checkpoint in each segment verified against actual record count (strict mode) | Round 4 |
|
|
28
|
+
| 10 | Memory-bounded init | Grow-to-newline capped at 1MB; exceeding cap treated as corrupt | Round 6 |
|
|
29
|
+
|
|
30
|
+
## Canonical Form Specification
|
|
31
|
+
|
|
32
|
+
### Record Types
|
|
33
|
+
|
|
34
|
+
Three record types exist, each with a fixed canonical field ordering:
|
|
35
|
+
|
|
36
|
+
**AuditRecord**: `[id, timestamp, method, toolName, namespace, upstream, principal, durationMs, success, errorCode, previousHash]` with optional fields (`decisionContextDigest`, `extensionsDigest`, `parties`) inserted at defined positions when present.
|
|
37
|
+
|
|
38
|
+
**CheckpointRecord**: `[id, type="checkpoint", timestamp, sequence, recordCount, previousHash]` with optional `parties`.
|
|
39
|
+
|
|
40
|
+
**ChainBreakRecord**: `[id, type="chain_break", timestamp, reason, priorHead, priorSequence, priorRecordCount]`.
|
|
41
|
+
|
|
42
|
+
### canonicalizeValue (for extensions and arbitrary nested data)
|
|
43
|
+
|
|
44
|
+
Recursively transforms a value into its canonical representation:
|
|
45
|
+
|
|
46
|
+
- `null` and `undefined` map to `null`
|
|
47
|
+
- Strings pass through after surrogate validation
|
|
48
|
+
- Booleans pass through
|
|
49
|
+
- Numbers must be safe integers (floats and unsafe integers throw)
|
|
50
|
+
- Arrays become `["L", [canonicalized elements...]]`
|
|
51
|
+
- Objects become `["M", [[key, canonicalized value]...]]` with keys sorted by UTF-16 code-unit order, undefined-valued keys dropped
|
|
52
|
+
|
|
53
|
+
The type tags make the mapping injective: `{a: 1}` and `[["a", 1]]` produce distinct canonical forms because the object gets `["M", ...]` wrapping while the array gets `["L", ...]` wrapping. A bare two-element array cannot appear at any position where a value is expected.
|
|
54
|
+
|
|
55
|
+
### String Well-Formedness
|
|
56
|
+
|
|
57
|
+
All strings entering any canonicalization path (values, keys, record fields) must be well-formed: no unpaired surrogates (U+D800 through U+DFFF appearing without their pair). This eliminates a class of cross-language divergence where JavaScript can hold lone surrogates in strings but Python cannot.
|
|
58
|
+
|
|
59
|
+
### Sort Order
|
|
60
|
+
|
|
61
|
+
Object keys are sorted by UTF-16 code-unit order. In JavaScript this is the default `.sort()`. In Python, use `sorted(keys, key=lambda k: k.encode("utf-16-be"))`. These diverge for characters above the Basic Multilingual Plane (U+FFFF), where JavaScript uses surrogate pairs (two 16-bit code units) while Python uses single code points.
|
|
62
|
+
|
|
63
|
+
### Relationship to JCS (RFC 8785)
|
|
64
|
+
|
|
65
|
+
JCS canonicalizes JSON values directly and is injective over JSON without additional type tags, because the JSON grammar's own `{}`/`[]` notation already distinguishes objects from arrays. The Round-3 type-confusion collision (where `{a:1}` and `[["a",1]]` produced identical digests) was an artifact of our tuple-array representation, not something JCS would have had. Our type tags (`["M",...]`/`["L",...]`) serve the same role that JSON's native brace/bracket distinction serves in JCS.
|
|
66
|
+
|
|
67
|
+
We chose our form over JCS for three reasons. First, JCS mandates full ECMAScript number serialization (IEEE 754 double to shortest decimal), which is difficult to reproduce byte-identically in Python, Go, and Rust. Our safe-integer-only rule eliminates the entire class of float-formatting divergence by rejecting the inputs rather than specifying the output. Second, our record canonicalization uses fixed field positions (positional determinism), enabling O(1) streaming append without re-sorting the record on every write. Third, our canonical form is computed before JSON serialization, so the hash input never depends on a particular JSON library's whitespace, key-ordering, or Unicode-escape behavior.
|
|
68
|
+
|
|
69
|
+
JCS gives you a ready-made injective standard for general JSON. We needed cross-language float safety, streaming-friendly positional layout, and serialization-layer independence, and accepted the cost of building injectivity ourselves.
|
|
70
|
+
|
|
71
|
+
## State File Invariants
|
|
72
|
+
|
|
73
|
+
The `.state.json` file contains:
|
|
74
|
+
|
|
75
|
+
- `lastHash` (string): hash of the most recently written record (chain head for resume)
|
|
76
|
+
- `rotationBoundaryHash` (string, required): expected `previousHash` of the first record in the current log file
|
|
77
|
+
- `checkpointSequence` (number): monotonically increasing checkpoint counter
|
|
78
|
+
- `totalRecordCount` (number): total non-checkpoint records written
|
|
79
|
+
|
|
80
|
+
A state file missing any of these fields is treated as corrupt. The system refuses to start with a corrupt state file unless `--force-new-chain` is passed, which emits a signed `chain_break` record documenting the discontinuity.
|
|
81
|
+
|
|
82
|
+
### Two Persistence Functions
|
|
83
|
+
|
|
84
|
+
- `persistState()`: called only by `rotate()`. Sets `rotationBoundaryHash = lastHash` because the next file's first record will chain from the current chain head.
|
|
85
|
+
- `persistChainState()`: called only by `emitChainBreak()`. Preserves the existing `rotationBoundaryHash` because a mid-file chain break does not change which hash the first record of this file chains from.
|
|
86
|
+
|
|
87
|
+
## chain_break Records
|
|
88
|
+
|
|
89
|
+
A `chain_break` record is signed evidence of a discontinuity. It converts "gap in evidence" (which could be innocent or malicious) into "signed evidence of a gap" (which can be audited, attributed, and policy-gated).
|
|
90
|
+
|
|
91
|
+
`forceNewChain()` emits a chain_break and resets `lastHash`, `checkpointSequence`, `totalRecordCount`, and `recordsSinceCheckpoint`. It does NOT reset `rotationBoundaryHash`.
|
|
92
|
+
|
|
93
|
+
## Verification Modes
|
|
94
|
+
|
|
95
|
+
**Strict mode**: full chain available from genesis. Verifies absolute record counts, segment-initial anchors, adjacent deltas, and sequence monotonicity.
|
|
96
|
+
|
|
97
|
+
**Relative mode**: only a suffix of the chain available (e.g., after rotation or partial delivery). Verifies adjacent deltas and sequence monotonicity within the suffix. Reports `absoluteCountVerified: false` to signal that the consumer received an honestly-downgraded result, not a silently-incomplete one.
|
|
98
|
+
|
|
99
|
+
## Pitfalls Found During Design Review
|
|
100
|
+
|
|
101
|
+
These are the non-obvious bugs discovered across six rounds of adversarial review. Each required a design change, not just a code fix.
|
|
102
|
+
|
|
103
|
+
**Type-confusion collision (Round 3).** Without type tags, `{a: 1}` canonicalized to `[["a", 1]]`, which is indistinguishable from the array `[["a", 1]]`. An attacker controlling extension values could craft an array that produces the same digest as a different object. Type tags (`["M", ...]` vs `["L", ...]`) make the mapping injective.
|
|
104
|
+
|
|
105
|
+
**UTF-16 vs code-point sort divergence (Round 4).** JavaScript's `.sort()` compares by UTF-16 code units. Python's `sorted()` compares by code points. For characters above U+FFFF, these produce different orderings. Same object, two canonical forms, two digests. The fix mandates UTF-16 code-unit order and provides a conformance vector proving the divergence.
|
|
106
|
+
|
|
107
|
+
**Lone surrogates (Round 4).** JavaScript strings can contain unpaired surrogates. Python strings generally cannot. `JSON.stringify` behavior on lone surrogates varies across engines. Rather than specifying divergent behaviors, the design rejects lone surrogates entirely.
|
|
108
|
+
|
|
109
|
+
**Dual-purpose state field (Round 5).** `lastHash` was serving two masters: "resume base for next record" and "expected linkage of first record in this file." After a `forceNewChain`, these diverge. The solution splits them into `lastHash` (runtime chain head) and `rotationBoundaryHash` (file-boundary claim).
|
|
110
|
+
|
|
111
|
+
**Null-skip bypass (Round 6).** When `rotationBoundaryHash` was null (no rotation yet), the linkage check was skipped. An attacker planting a state file without the field could bypass detection. The fix mandates `"genesis"` as the initial value, matching the first record's natural `previousHash`.
|
|
112
|
+
|
|
113
|
+
**Fail-open on corrupt first line (Round 5).** If the first line didn't parse, `firstRecordPrevHash` remained undefined and the linkage check silently skipped. Now: corrupt first line = refuse to start.
|
|
114
|
+
|
|
115
|
+
**Fixed-size head buffer (Round 4).** A 4KB head buffer silently truncated large first records, causing parse failure that mapped to the fail-open above. The grow-to-newline approach (with 1MB cap) handles any legitimate record size.
|
|
116
|
+
|
|
117
|
+
## Conformance Testing
|
|
118
|
+
|
|
119
|
+
Cross-language conformance is verified by two independent implementations:
|
|
120
|
+
|
|
121
|
+
- `test/vectors/verify-checkpoint.mjs` (JavaScript/Node.js)
|
|
122
|
+
- `test/vectors/verify-checkpoint.py` (Python)
|
|
123
|
+
|
|
124
|
+
Both consume the same `test/vectors/checkpoint.json` vector file (46 vectors). The vectors cover: checkpoint canonicalization, chain hashing, truncation detection, canonicalizeValue (including astral-plane keys and surrogate rejection), extensions digest, rotation boundary, sequence regression, chain break, and verification modes.
|
|
125
|
+
|
|
126
|
+
Adding a new implementation requires passing all 46 vectors. The astral-plane sort vector specifically catches implementations using code-point sort instead of UTF-16 code-unit sort.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# v0.4.0 Patch Audit Document
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
This document describes the v0.4.0 patch for mcp-audit-gateway for external expert review before committing. The patch fixes two security-relevant gaps identified during adversarial design review.
|
|
6
|
+
|
|
7
|
+
## Summary
|
|
8
|
+
|
|
9
|
+
The patch modifies 7 files, adding approximately 348 lines and removing 4. It bumps the package version from 0.3.0 to 0.4.0.
|
|
10
|
+
|
|
11
|
+
## What the patch fixes
|
|
12
|
+
|
|
13
|
+
### Fix 1: Sign aiInvocation in the canonical form
|
|
14
|
+
|
|
15
|
+
**Problem:** The `aiInvocation` field (containing `turnId`, `invocationReason`, `model`) was NOT included in the per-record signing canonical form. It was only covered by the chain hash (full-JSON `hashRecord`). This means an adversary with storage access (but no signing key) could silently mutate `aiInvocation` on the most recent record until the next record lands and anchors the chain hash.
|
|
16
|
+
|
|
17
|
+
**Security impact:** The `parties` array claims `aiInvocation` is client-asserted, but the signature didn't actually cover it. This is a field claiming provenance without cryptographic backing.
|
|
18
|
+
|
|
19
|
+
**Fix:** Insert `["aiInvocation", canonicalizeValue(record.aiInvocation)]` into the signing tuple-array at position after `extensionsDigest` and before `parties`, when present. The field is canonicalized via the M/L-tagged `canonicalizeValue()` function (keys sorted by UTF-16 code units).
|
|
20
|
+
|
|
21
|
+
### Fix 2: Add extensionsDigest to verify.py (base suite)
|
|
22
|
+
|
|
23
|
+
**Problem:** The base-suite Python verifier (`verify.py`) did NOT insert `extensionsDigest` into its canonical form. The checkpoint Python verifier (`verify-checkpoint.py`) handled it correctly. No base-suite vector exercised this path, so the divergence was latent.
|
|
24
|
+
|
|
25
|
+
**Security impact:** The paper's thesis is "a divergence between independent verifiers is by definition a specification bug." Shipping a known divergence contradicts the central claim.
|
|
26
|
+
|
|
27
|
+
**Fix:** Add the `extensionsDigest` insert with proper `insert_at` bookkeeping to `verify.py`, matching the logic already present in `verify-checkpoint.py`. Add a base-suite vector that exercises this path.
|
|
28
|
+
|
|
29
|
+
## Files modified
|
|
30
|
+
|
|
31
|
+
### 1. package.json
|
|
32
|
+
- Version bump: 0.3.0 -> 0.4.0
|
|
33
|
+
|
|
34
|
+
### 2. src/attestation/signer.ts (the production signer)
|
|
35
|
+
- `canonicalizeRecord()`: Insert `aiInvocation` (via `canonicalizeValue`) after `extensionsDigest`, before `parties`
|
|
36
|
+
- Comment updated to document new 4-field insertion order
|
|
37
|
+
|
|
38
|
+
### 3. test/vectors/canonicalization.json (test vectors)
|
|
39
|
+
- All new vectors were generated by the compiled production signer (`signer.ts`), not hand-written. This means the expected digests enshrine the implementation's actual output rather than a manually computed value that could enshrine a buggy expectation.
|
|
40
|
+
- New section `ai_invocation_signing` with 3 positive vectors:
|
|
41
|
+
- `ai_invocation_full` (all 3 fields: turnId, invocationReason, model)
|
|
42
|
+
- `ai_invocation_partial_turnid_only` (only turnId present)
|
|
43
|
+
- `ai_invocation_with_all_optionals` (with decisionContextDigest + extensionsDigest + parties)
|
|
44
|
+
- New `mutation_negative` pair: proves a changed `aiInvocation.turnId` produces a different signing digest
|
|
45
|
+
- New section `extensions_digest_base` with 1 vector:
|
|
46
|
+
- `extensions_digest_with_parties` (exercises extensionsDigest insertion in base suite)
|
|
47
|
+
|
|
48
|
+
### 4. test/vectors/verify-checkpoint.mjs (JS checkpoint verifier)
|
|
49
|
+
- `canonicalizeRecord()`: Insert `aiInvocation` after `extensionsDigest`, before `parties`
|
|
50
|
+
- (This verifier already handled extensionsDigest correctly)
|
|
51
|
+
|
|
52
|
+
### 5. test/vectors/verify-checkpoint.py (Python checkpoint verifier)
|
|
53
|
+
- `canonicalize_record()`: Insert `aiInvocation` after `extensionsDigest`, before `parties`
|
|
54
|
+
- (This verifier already handled extensionsDigest correctly)
|
|
55
|
+
|
|
56
|
+
### 6. test/vectors/verify.mjs (JS base-suite verifier)
|
|
57
|
+
- New `canonicalizeValue()` function added (handles string validation, boolean, number safety, recursive M/L tagging for objects/arrays)
|
|
58
|
+
- `canonicalizeFromRecord()` rewritten with proper `insertAt` bookkeeping for all 4 conditional fields: decisionContextDigest, extensionsDigest, aiInvocation, parties
|
|
59
|
+
- New test sections for `ai_invocation_signing` vectors (canonical + digest + mutation pair)
|
|
60
|
+
- New test section for `extensions_digest_base` vectors
|
|
61
|
+
|
|
62
|
+
### 7. test/vectors/verify.py (Python base-suite verifier)
|
|
63
|
+
- New `assert_well_formed()` function (surrogate pair validation)
|
|
64
|
+
- New `canonicalize_value()` function (M/L tagging, UTF-16-BE key sort, type safety)
|
|
65
|
+
- `canonicalize()` rewritten with proper `insert_at` bookkeeping for all 4 conditional fields
|
|
66
|
+
- New test sections for `ai_invocation_signing` and `extensions_digest_base` vectors
|
|
67
|
+
|
|
68
|
+
## Validation results (post-patch)
|
|
69
|
+
|
|
70
|
+
All verifiers pass with the new vectors included:
|
|
71
|
+
|
|
72
|
+
| Verifier | Assertions | Result |
|
|
73
|
+
|----------|-----------|--------|
|
|
74
|
+
| verify.mjs (JS base) | 47 | PASS |
|
|
75
|
+
| verify.py (Python base) | 44 | PASS |
|
|
76
|
+
| verify-checkpoint.mjs (JS checkpoint) | 46 | PASS |
|
|
77
|
+
| verify-checkpoint.py (Python checkpoint) | 46 | PASS |
|
|
78
|
+
| aps-action-ref-v1.mjs (APS) | 51 | PASS |
|
|
79
|
+
| Unit tests (vitest) | 150 passed, 2 skipped | PASS |
|
|
80
|
+
| TypeScript build | Clean | PASS |
|
|
81
|
+
|
|
82
|
+
The 3-assertion difference between JS base (47) and Python base (44): the chain hash covers the record as serialized by the writer (JS's native `JSON.stringify`), so the JS verifier can natively re-serialize and compare against the stored hash. Python cannot reproduce that exact serialization and instead verifies against the stored reference string. This asymmetry is documented in the paper Section 5.1.
|
|
83
|
+
|
|
84
|
+
## Migration note
|
|
85
|
+
|
|
86
|
+
Records written BEFORE this patch that contain `aiInvocation` were signed WITHOUT it in the canonical form. Post-patch verification of those specific records will fail signature check. Since no tagged release shipped with `aiInvocation` records in production, blast radius is limited to untagged development logs only.
|
|
87
|
+
|
|
88
|
+
## How to apply
|
|
89
|
+
|
|
90
|
+
From the repo root:
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
git apply v0.4.0-aiinvocation-signing.patch
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Then validate:
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
npm run build
|
|
100
|
+
npx vitest run
|
|
101
|
+
node test/vectors/verify.mjs
|
|
102
|
+
python3 test/vectors/verify.py
|
|
103
|
+
node test/vectors/verify-checkpoint.mjs
|
|
104
|
+
python3 test/vectors/verify-checkpoint.py
|
|
105
|
+
node test/vectors/aps-action-ref-v1.mjs
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Reviewer checklist
|
|
109
|
+
|
|
110
|
+
- [ ] Does the insertion order in signer.ts match all 4 verifiers?
|
|
111
|
+
- [ ] Do the new vectors exercise both presence and absence of aiInvocation? (Presence via 3 positives + mutation pair; absence implicitly covered by all 8 pre-existing base canonicalization vectors which lack aiInvocation and still pass post-patch.)
|
|
112
|
+
- [ ] Does the mutation_negative pair prove signature coverage (different digests)?
|
|
113
|
+
- [ ] Is the canonicalizeValue() logic identical between JS and Python?
|
|
114
|
+
- [ ] Does the extensionsDigest base-suite vector pass in both languages?
|
|
115
|
+
- [ ] Is the version bump appropriate for this change? (Project is at 0.x where semver exempts breaking changes; the 0.MINOR position is the conventional breaking-change slot, so 0.4.0 is correct.)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcp-audit-gateway/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "MCP audit and attestation gateway — transparent proxy with cryptographic attestation, policy enforcement, and OTel export",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|