ccs-mcp-server 1.2.1 → 1.2.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccs-mcp-server",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "description": "CCS Runtime Evidence MCP Server — verify AI agent tool calls, issue Ed25519-signed evidence receipts, audit MCP configs, and bind execution to declared intent (cross-model amount drift protection). For Claude Desktop, Cursor, Windsurf, and any MCP client.",
5
5
  "type": "commonjs",
6
6
  "bin": {
package/src/index.js CHANGED
@@ -32,7 +32,7 @@ const receipts = require("./receipts");
32
32
  // CCS Verifier Core (pure stdlib Node.js)
33
33
  // ---------------------------------------------------------------------------
34
34
 
35
- const CCS_VERSION = "1.2.1";
35
+ const CCS_VERSION = "1.2.2";
36
36
 
37
37
  const DEFAULT_POLICY = {
38
38
  mode: "block",
@@ -111,9 +111,12 @@ function deepMerge(base, override) {
111
111
  return result;
112
112
  }
113
113
 
114
- function canonical(obj) {
115
- return JSON.stringify(obj, Object.keys(obj).sort());
116
- }
114
+ // Use the receipt module's recursive canonical serializer. The previous
115
+ // JSON.stringify(obj, Object.keys(obj).sort()) implementation dropped all
116
+ // nested object fields because the top-level key array acts as a recursive
117
+ // whitelist; that made content/evidence hashes omit dimensions and other
118
+ // nested data. Fixed in 1.2.2.
119
+ const canonical = receipts.canonical;
117
120
 
118
121
  function sha256(s) {
119
122
  return "sha256:" + crypto.createHash("sha256").update(s).digest("hex");
package/src/receipts.js CHANGED
@@ -29,7 +29,24 @@ const ALG_INTERNAL = "ed25519";
29
29
  const SIGNATURE_FIELDS = ["signer_public_key", "signature_alg", "signature", "verified"];
30
30
 
31
31
  function canonical(obj) {
32
- return JSON.stringify(obj, Object.keys(obj).sort());
32
+ // Recursive JCS-style deterministic JSON: sort object keys at EVERY nesting
33
+ // level, preserve array order. NOTE: a previous implementation used
34
+ // JSON.stringify(obj, Object.keys(obj).sort()) which applies the top-level
35
+ // key list as a recursive whitelist and silently drops all nested fields
36
+ // from the serialized output — meaning signatures/hashes did not cover
37
+ // dimensions, semantic_analysis, etc. That was a security bug fixed in
38
+ // 1.2.2. Receipts issued by <=1.2.1 do not cover nested fields and must be
39
+ // re-issued.
40
+ if (Array.isArray(obj)) {
41
+ return "[" + obj.map(canonical).join(",") + "]";
42
+ }
43
+ if (obj !== null && typeof obj === "object") {
44
+ const keys = Object.keys(obj).sort();
45
+ return "{" + keys
46
+ .map((k) => JSON.stringify(k) + ":" + canonical(obj[k]))
47
+ .join(",") + "}";
48
+ }
49
+ return JSON.stringify(obj);
33
50
  }
34
51
 
35
52
  function defaultKeyDir() {