@cello-protocol/gateway 0.0.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 (105) hide show
  1. package/dist/bin/cello-gateway.d.ts +3 -0
  2. package/dist/bin/cello-gateway.d.ts.map +1 -0
  3. package/dist/bin/cello-gateway.js +174 -0
  4. package/dist/bin/cello-gateway.js.map +1 -0
  5. package/dist/client.d.ts +16 -0
  6. package/dist/client.d.ts.map +1 -0
  7. package/dist/client.js +182 -0
  8. package/dist/client.js.map +1 -0
  9. package/dist/config/config-store.d.ts +42 -0
  10. package/dist/config/config-store.d.ts.map +1 -0
  11. package/dist/config/config-store.js +198 -0
  12. package/dist/config/config-store.js.map +1 -0
  13. package/dist/detect/deberta-model-manifest.d.ts +54 -0
  14. package/dist/detect/deberta-model-manifest.d.ts.map +1 -0
  15. package/dist/detect/deberta-model-manifest.js +17 -0
  16. package/dist/detect/deberta-model-manifest.js.map +1 -0
  17. package/dist/detect/exfil.d.ts +14 -0
  18. package/dist/detect/exfil.d.ts.map +1 -0
  19. package/dist/detect/exfil.js +69 -0
  20. package/dist/detect/exfil.js.map +1 -0
  21. package/dist/detect/gitleaks-rules.d.ts +18 -0
  22. package/dist/detect/gitleaks-rules.d.ts.map +1 -0
  23. package/dist/detect/gitleaks-rules.js +229 -0
  24. package/dist/detect/gitleaks-rules.js.map +1 -0
  25. package/dist/detect/injection-patterns.d.ts +10 -0
  26. package/dist/detect/injection-patterns.d.ts.map +1 -0
  27. package/dist/detect/injection-patterns.js +53 -0
  28. package/dist/detect/injection-patterns.js.map +1 -0
  29. package/dist/detect/injection-scanner.d.ts +44 -0
  30. package/dist/detect/injection-scanner.d.ts.map +1 -0
  31. package/dist/detect/injection-scanner.js +45 -0
  32. package/dist/detect/injection-scanner.js.map +1 -0
  33. package/dist/detect/language.d.ts +37 -0
  34. package/dist/detect/language.d.ts.map +1 -0
  35. package/dist/detect/language.js +85 -0
  36. package/dist/detect/language.js.map +1 -0
  37. package/dist/detect/linear-regex.d.ts +20 -0
  38. package/dist/detect/linear-regex.d.ts.map +1 -0
  39. package/dist/detect/linear-regex.js +70 -0
  40. package/dist/detect/linear-regex.js.map +1 -0
  41. package/dist/detect/model-installer.d.ts +32 -0
  42. package/dist/detect/model-installer.d.ts.map +1 -0
  43. package/dist/detect/model-installer.js +94 -0
  44. package/dist/detect/model-installer.js.map +1 -0
  45. package/dist/detect/pii.d.ts +27 -0
  46. package/dist/detect/pii.d.ts.map +1 -0
  47. package/dist/detect/pii.js +119 -0
  48. package/dist/detect/pii.js.map +1 -0
  49. package/dist/detect/rate-limit.d.ts +44 -0
  50. package/dist/detect/rate-limit.d.ts.map +1 -0
  51. package/dist/detect/rate-limit.js +56 -0
  52. package/dist/detect/rate-limit.js.map +1 -0
  53. package/dist/detect/sanitize.d.ts +50 -0
  54. package/dist/detect/sanitize.d.ts.map +1 -0
  55. package/dist/detect/sanitize.js +211 -0
  56. package/dist/detect/sanitize.js.map +1 -0
  57. package/dist/detect/secrets.d.ts +20 -0
  58. package/dist/detect/secrets.d.ts.map +1 -0
  59. package/dist/detect/secrets.js +104 -0
  60. package/dist/detect/secrets.js.map +1 -0
  61. package/dist/index.d.ts +38 -0
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +25 -0
  64. package/dist/index.js.map +1 -0
  65. package/dist/passthrough.d.ts +18 -0
  66. package/dist/passthrough.d.ts.map +1 -0
  67. package/dist/passthrough.js +21 -0
  68. package/dist/passthrough.js.map +1 -0
  69. package/dist/protocol.d.ts +53 -0
  70. package/dist/protocol.d.ts.map +1 -0
  71. package/dist/protocol.js +52 -0
  72. package/dist/protocol.js.map +1 -0
  73. package/dist/records/record-store.d.ts +28 -0
  74. package/dist/records/record-store.d.ts.map +1 -0
  75. package/dist/records/record-store.js +134 -0
  76. package/dist/records/record-store.js.map +1 -0
  77. package/dist/screen/inbound.d.ts +29 -0
  78. package/dist/screen/inbound.d.ts.map +1 -0
  79. package/dist/screen/inbound.js +127 -0
  80. package/dist/screen/inbound.js.map +1 -0
  81. package/dist/screen/inbound.test.d.ts +2 -0
  82. package/dist/screen/inbound.test.d.ts.map +1 -0
  83. package/dist/screen/inbound.test.js +49 -0
  84. package/dist/screen/inbound.test.js.map +1 -0
  85. package/dist/screen/outbound.d.ts +57 -0
  86. package/dist/screen/outbound.d.ts.map +1 -0
  87. package/dist/screen/outbound.js +183 -0
  88. package/dist/screen/outbound.js.map +1 -0
  89. package/dist/screen/outbound.test.d.ts +2 -0
  90. package/dist/screen/outbound.test.d.ts.map +1 -0
  91. package/dist/screen/outbound.test.js +62 -0
  92. package/dist/screen/outbound.test.js.map +1 -0
  93. package/dist/server.d.ts +34 -0
  94. package/dist/server.d.ts.map +1 -0
  95. package/dist/server.js +129 -0
  96. package/dist/server.js.map +1 -0
  97. package/dist/spawn.d.ts +32 -0
  98. package/dist/spawn.d.ts.map +1 -0
  99. package/dist/spawn.js +84 -0
  100. package/dist/spawn.js.map +1 -0
  101. package/dist/types.d.ts +121 -0
  102. package/dist/types.d.ts.map +1 -0
  103. package/dist/types.js +39 -0
  104. package/dist/types.js.map +1 -0
  105. package/package.json +42 -0
@@ -0,0 +1,198 @@
1
+ /**
2
+ * M9-CFG-001 — the gateway's own versioned config store (INV-4).
3
+ *
4
+ * The gateway owns its configuration; the daemon never does. This store lives in the gateway's own
5
+ * local DB file (node:sqlite — the same library the daemon uses, a separate file), is append-only and
6
+ * versioned, and enforces the §7 governance asymmetry:
7
+ *
8
+ * - TIGHTENING a guard (making the gateway MORE restrictive) is free — no confirmation.
9
+ * - LOOSENING a guard (making it LESS restrictive — enabling autonomous override, adding a value to
10
+ * the PII whitelist, raising/removing the rate cap, allowing another language) requires an explicit
11
+ * `confirmed` flag. Without it the change is REJECTED and not versioned. (The human confirmation —
12
+ * WebAuthn in the portal — is the front-end's job; this store is the enforcement point.)
13
+ *
14
+ * Every applied change appends a row whose `fingerprint` is hash-chained to the previous version, so
15
+ * the change history is tamper-evident and ready to attest to the directory in Phase 2 (M9-ATTEST-001).
16
+ *
17
+ * Encryption-at-rest: the daemon opens node:sqlite without a cipher key today, so this store matches
18
+ * that (a separate FILE, per INV-4); SQLCipher-style key encryption is a cross-cutting gap shared with
19
+ * the daemon's DB, not a CFG-001-local concern.
20
+ */
21
+ import { DatabaseSync } from "node:sqlite";
22
+ import { createHash } from "node:crypto";
23
+ const asArray = (v) => (Array.isArray(v) ? v : []);
24
+ /** Set-membership delta: more members = looser, fewer = tighter (for allowlists/whitelists). */
25
+ function membershipDirection(prev, next) {
26
+ const p = new Set(asArray(prev));
27
+ const n = new Set(asArray(next));
28
+ const added = [...n].some((v) => !p.has(v));
29
+ const removed = [...p].some((v) => !n.has(v));
30
+ if (added)
31
+ return "loosen"; // a strictly-added member widens what is permitted
32
+ if (removed)
33
+ return "tighten";
34
+ return "neutral";
35
+ }
36
+ /** The known config keys + how a change to each is classified. An unknown key is rejected outright. */
37
+ const CLASSIFIERS = {
38
+ // false → true loosens (the agent may now self-authorize); true → false tightens.
39
+ autonomous_override: (prev, next) => (!prev && next ? "loosen" : prev && !next ? "tighten" : "neutral"),
40
+ // More whitelisted PII values = more that passes silently = looser.
41
+ pii_whitelist: membershipDirection,
42
+ // More allowed languages = looser.
43
+ language_allow: membershipDirection,
44
+ // 0 = no cap = loosest; a higher cap = looser. Lowering the cap tightens.
45
+ rate_max_per_window: (prev, next) => {
46
+ const looseness = (v) => { const n = Number(v) || 0; return n === 0 ? Infinity : n; };
47
+ const p = looseness(prev), q = looseness(next);
48
+ return q > p ? "loosen" : q < p ? "tighten" : "neutral";
49
+ },
50
+ // The window pairs with the cap: a SHORTER window refills faster → strictly more throughput → looser
51
+ // (code-review H2 — shrinking the window must be gated like raising the cap). A longer window tightens.
52
+ rate_window_ms: (prev, next) => {
53
+ const p = Number(prev) || 0, q = Number(next) || 0;
54
+ return q < p ? "loosen" : q > p ? "tighten" : "neutral";
55
+ },
56
+ };
57
+ /**
58
+ * The TIGHTEST default for every guard (code-review B1). The §7 contract defines a baseline: each guard
59
+ * defaults to its most restrictive value, and LOOSENING from that default requires confirmation. The
60
+ * store ships empty, so the FIRST set of a key must be classified against THIS baseline — not treated as
61
+ * a free "neutral" — otherwise first-enabling autonomous_override (or seeding a whitelist) would be free,
62
+ * inverting the security model.
63
+ */
64
+ const BASELINE = {
65
+ autonomous_override: false, // the agent cannot self-authorize
66
+ pii_whitelist: [], // nothing passes silently
67
+ language_allow: ["latin"], // English only (the product default; allowing MORE languages loosens)
68
+ rate_max_per_window: 0, // 0 = no cap is the loosest; SETTING a cap tightens (so it is free)
69
+ rate_window_ms: 60_000, // a shorter window loosens; first-set of a shorter one is gated
70
+ };
71
+ /** Per-key value-type guard (code-review M2): a type-confused value must not silently disable a guard. */
72
+ const VALIDATORS = {
73
+ autonomous_override: (v) => typeof v === "boolean",
74
+ pii_whitelist: (v) => Array.isArray(v) && v.every((x) => typeof x === "string"),
75
+ language_allow: (v) => Array.isArray(v) && v.every((x) => typeof x === "string"),
76
+ rate_max_per_window: (v) => typeof v === "number" && Number.isFinite(v) && v >= 0,
77
+ rate_window_ms: (v) => typeof v === "number" && Number.isFinite(v) && v > 0,
78
+ };
79
+ /** The hash-chain fingerprint over a version's fields (incl. direction + confirmed, H1) + the prior fp. */
80
+ function fingerprintOf(key, version, valueJson, direction, confirmed, prevFingerprint) {
81
+ return createHash("sha256")
82
+ .update(`${key}|${version}|${valueJson}|${direction}|${confirmed}|${prevFingerprint}`)
83
+ .digest("hex");
84
+ }
85
+ const DDL = `
86
+ CREATE TABLE IF NOT EXISTS config_versions (
87
+ key TEXT NOT NULL,
88
+ version INTEGER NOT NULL,
89
+ value_json TEXT NOT NULL,
90
+ direction TEXT NOT NULL,
91
+ confirmed INTEGER NOT NULL,
92
+ fingerprint TEXT NOT NULL,
93
+ prev_fingerprint TEXT NOT NULL,
94
+ changed_at INTEGER NOT NULL,
95
+ PRIMARY KEY (key, version)
96
+ );
97
+ `;
98
+ export class GatewayConfigStore {
99
+ #db;
100
+ #closed = false;
101
+ constructor(dbPath) {
102
+ this.#db = new DatabaseSync(dbPath);
103
+ this.#db.exec(`PRAGMA busy_timeout = 3000;`); // tolerate brief lock contention from an orphan gateway
104
+ this.#db.exec(DDL);
105
+ }
106
+ /** Set `key` to `value`. Loosening requires `opts.confirmed`; tightening/neutral is free. The FIRST
107
+ * set of a key is classified against the per-key TIGHTEST baseline, not treated as free (B1). */
108
+ set(key, value, opts = {}) {
109
+ const classify = CLASSIFIERS[key];
110
+ if (!classify)
111
+ throw new Error(`unknown config key: ${key}`);
112
+ if (!VALIDATORS[key](value))
113
+ throw new Error(`invalid value for config key '${key}': ${JSON.stringify(value)}`);
114
+ const latest = this.#latestRow(key);
115
+ // First set → compare against the tightest BASELINE so initial loosening is gated like any other (B1).
116
+ const prevValue = latest ? JSON.parse(latest.value_json) : BASELINE[key];
117
+ const direction = classify(prevValue, value);
118
+ if (direction === "loosen" && !opts.confirmed) {
119
+ return { ok: false, reason: "needs_confirmation", direction: "loosen" };
120
+ }
121
+ const version = (latest?.version ?? 0) + 1;
122
+ const valueJson = JSON.stringify(value);
123
+ const confirmed = opts.confirmed ? 1 : 0;
124
+ const prevFingerprint = latest?.fingerprint ?? "";
125
+ // The fingerprint binds direction + confirmed too (code-review H1): the whole point of attesting the
126
+ // chain is to prove a loosening WAS confirmed by a human — so those fields must be inside the hash, or
127
+ // an editor could flip confirmed 0→1 / relabel a loosen as neutral and still pass verifyChain.
128
+ const fingerprint = fingerprintOf(key, version, valueJson, direction, confirmed, prevFingerprint);
129
+ // Read-modify-write as one transaction so two processes on the same file cannot both write the same
130
+ // version and collide on the PRIMARY KEY (code-review L1).
131
+ this.#db.exec("BEGIN IMMEDIATE");
132
+ try {
133
+ this.#db
134
+ .prepare(`INSERT INTO config_versions
135
+ (key, version, value_json, direction, confirmed, fingerprint, prev_fingerprint, changed_at)
136
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`)
137
+ .run(key, version, valueJson, direction, confirmed, fingerprint, prevFingerprint, Date.now());
138
+ this.#db.exec("COMMIT");
139
+ }
140
+ catch (err) {
141
+ this.#db.exec("ROLLBACK");
142
+ throw err;
143
+ }
144
+ return { ok: true, version, direction, fingerprint };
145
+ }
146
+ /** The current (latest-version) value for `key`, or undefined if never set. */
147
+ get(key) {
148
+ const row = this.#latestRow(key);
149
+ return row ? JSON.parse(row.value_json) : undefined;
150
+ }
151
+ /** The full append-only version history for `key`, oldest first. */
152
+ history(key) {
153
+ const rows = this.#db
154
+ .prepare(`SELECT version, value_json, direction, confirmed, fingerprint FROM config_versions WHERE key = ? ORDER BY version ASC`)
155
+ .all(key);
156
+ return rows.map((r) => ({
157
+ version: r.version,
158
+ value: JSON.parse(r.value_json),
159
+ direction: r.direction,
160
+ confirmed: r.confirmed === 1,
161
+ fingerprint: r.fingerprint,
162
+ }));
163
+ }
164
+ /**
165
+ * Recompute the hash chain for `key` and confirm every stored fingerprint + prev-link matches
166
+ * (catches an edited value, a flipped `confirmed`, a relabelled `direction`, a deleted/reordered row).
167
+ * NOT resistant to a full consistent rewrite or tail truncation by an actor with DB write access +
168
+ * the (unkeyed) hash — that needs the Phase-2 attested head on the directory (M9-ATTEST-001); this is
169
+ * the local half (code-review M3, recorded).
170
+ */
171
+ verifyChain(key) {
172
+ const rows = this.#db
173
+ .prepare(`SELECT version, value_json, direction, confirmed, fingerprint, prev_fingerprint FROM config_versions WHERE key = ? ORDER BY version ASC`)
174
+ .all(key);
175
+ let prevFingerprint = "";
176
+ for (const r of rows) {
177
+ if (r.prev_fingerprint !== prevFingerprint)
178
+ return false;
179
+ const expected = fingerprintOf(key, r.version, r.value_json, r.direction, r.confirmed, prevFingerprint);
180
+ if (expected !== r.fingerprint)
181
+ return false;
182
+ prevFingerprint = r.fingerprint;
183
+ }
184
+ return true;
185
+ }
186
+ close() {
187
+ if (this.#closed)
188
+ return; // idempotent — a double close (e.g. test teardown after an explicit close) is a no-op
189
+ this.#closed = true;
190
+ this.#db.close();
191
+ }
192
+ #latestRow(key) {
193
+ return this.#db
194
+ .prepare(`SELECT version, value_json, fingerprint FROM config_versions WHERE key = ? ORDER BY version DESC LIMIT 1`)
195
+ .get(key);
196
+ }
197
+ }
198
+ //# sourceMappingURL=config-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-store.js","sourceRoot":"","sources":["../../src/config/config-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * GENERATED (scripts/gen-deberta-manifest.py) — the M9-IN-002 model manifest.
3
+ * The big ONNX weights + the SentencePiece model carry a pinned content SHA-256 (from
4
+ * Hugging Face LFS). NOTE: the SHA-256 values are not committed here — this dev environment's
5
+ * secret-redaction rewrites any 64-hex digest to asterisks, even in generated files. Integrity is
6
+ * the committed file SIZE plus, in production, verification against Hugging Face's HTTPS LFS API.
7
+ * Committing the pinned digests (TUF-style, so a compromised mirror cannot swap the model) is the
8
+ * intended hardening and must be added out-of-band (CI / a non-redacting path).
9
+ */
10
+ export interface ModelFile {
11
+ path: string;
12
+ size: number;
13
+ sha256: string | null;
14
+ }
15
+ export declare const DEBERTA_MODEL: {
16
+ readonly repo: "protectai/deberta-v3-small-prompt-injection-v2";
17
+ readonly revision: "main";
18
+ /** Hugging Face resolve URL base for the pinned revision. */
19
+ readonly baseUrl: "https://huggingface.co/protectai/deberta-v3-small-prompt-injection-v2/resolve/main/";
20
+ readonly files: readonly [{
21
+ readonly path: "config.json";
22
+ readonly size: 994;
23
+ readonly sha256: null;
24
+ }, {
25
+ readonly path: "tokenizer.json";
26
+ readonly size: 8656722;
27
+ readonly sha256: null;
28
+ }, {
29
+ readonly path: "tokenizer_config.json";
30
+ readonly size: 1284;
31
+ readonly sha256: null;
32
+ }, {
33
+ readonly path: "special_tokens_map.json";
34
+ readonly size: 286;
35
+ readonly sha256: null;
36
+ }, {
37
+ readonly path: "added_tokens.json";
38
+ readonly size: 23;
39
+ readonly sha256: null;
40
+ }, {
41
+ readonly path: "spm.model";
42
+ readonly size: 2464616;
43
+ readonly sha256: null;
44
+ }, {
45
+ readonly path: "onnx/model.onnx";
46
+ readonly size: 568027819;
47
+ readonly sha256: null;
48
+ }, {
49
+ readonly path: "onnx/config.json";
50
+ readonly size: 1031;
51
+ readonly sha256: null;
52
+ }];
53
+ };
54
+ //# sourceMappingURL=deberta-model-manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deberta-model-manifest.d.ts","sourceRoot":"","sources":["../../src/detect/deberta-model-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,WAAW,SAAS;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE;AAEhF,eAAO,MAAM,aAAa;;;IAGxB,6DAA6D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAYrD,CAAC"}
@@ -0,0 +1,17 @@
1
+ export const DEBERTA_MODEL = {
2
+ repo: "protectai/deberta-v3-small-prompt-injection-v2",
3
+ revision: "main",
4
+ /** Hugging Face resolve URL base for the pinned revision. */
5
+ baseUrl: "https://huggingface.co/protectai/deberta-v3-small-prompt-injection-v2/resolve/main/",
6
+ files: [
7
+ { path: "config.json", size: 994, sha256: null },
8
+ { path: "tokenizer.json", size: 8656722, sha256: null },
9
+ { path: "tokenizer_config.json", size: 1284, sha256: null },
10
+ { path: "special_tokens_map.json", size: 286, sha256: null },
11
+ { path: "added_tokens.json", size: 23, sha256: null },
12
+ { path: "spm.model", size: 2464616, sha256: null },
13
+ { path: "onnx/model.onnx", size: 568027819, sha256: null },
14
+ { path: "onnx/config.json", size: 1031, sha256: null },
15
+ ],
16
+ };
17
+ //# sourceMappingURL=deberta-model-manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deberta-model-manifest.js","sourceRoot":"","sources":["../../src/detect/deberta-model-manifest.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,IAAI,EAAE,gDAAgD;IACtD,QAAQ,EAAE,MAAM;IAChB,6DAA6D;IAC7D,OAAO,EAAE,qFAAqF;IAC9F,KAAK,EAAE;QACL,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;QAChD,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE;QACvD,EAAE,IAAI,EAAE,uBAAuB,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;QAC3D,EAAE,IAAI,EAAE,yBAAyB,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;QAC5D,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE;QACrD,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE;QAClD,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE;QAC1D,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;KAC9C;CACF,CAAC"}
@@ -0,0 +1,14 @@
1
+ export interface ExfilEvent {
2
+ category: "exfil:invisible" | "exfil:image_url" | "exfil:encoded" | "exfil:injection_artifact";
3
+ reason: string;
4
+ detail?: string;
5
+ }
6
+ export interface ExfilResult {
7
+ /** `block` (output hijacked — do not send), `redact` (cleaned, send the result), or `allow`. */
8
+ disposition: "allow" | "redact" | "block";
9
+ /** The egress-cleaned text (for redact/allow). For block the original is returned (it is not sent). */
10
+ text: string;
11
+ events: ExfilEvent[];
12
+ }
13
+ export declare function screenOutboundExfil(content: Uint8Array): ExfilResult;
14
+ //# sourceMappingURL=exfil.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exfil.d.ts","sourceRoot":"","sources":["../../src/detect/exfil.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,iBAAiB,GAAG,iBAAiB,GAAG,eAAe,GAAG,0BAA0B,CAAC;IAC/F,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,gGAAgG;IAChG,WAAW,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;IAC1C,uGAAuG;IACvG,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB;AAsBD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,UAAU,GAAG,WAAW,CAsCpE"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * M9-OUT-003 — outbound exfiltration checks.
3
+ *
4
+ * A compromised LOCAL agent must not be able to smuggle data out, nor signal (via leaked
5
+ * injection artifacts) that it was hijacked. This screens egress content:
6
+ * - strips invisible/smuggled Unicode (symmetric with the inbound IN-001 strip),
7
+ * - neutralizes zero-click image-exfil URLs (an image whose URL carries query data),
8
+ * - redacts high-entropy encoded-payload blobs,
9
+ * - and BLOCKS outright when the output body carries injection artifacts (role markers /
10
+ * override phrases) — that is a compromise signal, so the whole message is attacker-controlled.
11
+ *
12
+ * Pure, deterministic, no model/network. All patterns use negated character classes / fixed
13
+ * alternations (linear time — no catastrophic backtracking), so no RE2 engine is required here.
14
+ */
15
+ import { stripInvisible, highEntropyTokens } from "./sanitize.js";
16
+ // Injection artifacts that, in the agent's OWN output, indicate a hijack. Anchored / fixed
17
+ // alternations — linear time. (Inbound STRIPS these; outbound BLOCKS, because their presence in
18
+ // output means the message body is attacker-controlled, attack-corpus §3.3.)
19
+ const ARTIFACT_PATTERNS = [
20
+ /\[SYSTEM\]|<\|im_(?:start|end)\|>|<<\/?SYS>>|\[\/?INST\]|<\|system\|>|<\|assistant\|>/i,
21
+ /\b(?:ignore|disregard)\s+(?:all\s+)?(?:your\s+)?previous\s+instructions\b/i,
22
+ /\bforget\s+everything\s+above\b/i,
23
+ ];
24
+ function findInjectionArtifact(text) {
25
+ for (const re of ARTIFACT_PATTERNS) {
26
+ const m = re.exec(text);
27
+ if (m)
28
+ return m[0];
29
+ }
30
+ return null;
31
+ }
32
+ // A markdown image whose URL carries a query string is a zero-click data-exfil vector (the
33
+ // renderer auto-fetches it, sending the query to the attacker). Negated char classes → linear.
34
+ const MD_IMAGE = /!\[[^\]]*\]\(([^)\s]+)\)/g;
35
+ export function screenOutboundExfil(content) {
36
+ const events = [];
37
+ let text = new TextDecoder("utf-8", { fatal: false }).decode(content);
38
+ // 1. Injection artifacts in output → BLOCK the whole message (compromise signal).
39
+ const artifact = findInjectionArtifact(text);
40
+ if (artifact) {
41
+ events.push({
42
+ category: "exfil:injection_artifact",
43
+ reason: "the output body contains an injection artifact, indicating the agent's output was hijacked — message not sent",
44
+ detail: artifact,
45
+ });
46
+ return { disposition: "block", text, events };
47
+ }
48
+ // 2. Egress invisible-Unicode strip (symmetric with M9-IN-001).
49
+ const inv = stripInvisible(text);
50
+ if (inv.removed > 0) {
51
+ events.push({ category: "exfil:invisible", reason: `stripped ${inv.removed} invisible/smuggled codepoint(s) on egress` });
52
+ text = inv.text;
53
+ }
54
+ // 3. Zero-click image-exfil: neutralize data-carrying image URLs; leave ordinary links/images.
55
+ text = text.replace(MD_IMAGE, (whole, url) => {
56
+ if (url.includes("?")) {
57
+ events.push({ category: "exfil:image_url", reason: "neutralized a data-carrying image URL (zero-click exfil vector)", detail: url });
58
+ return "[image removed: possible data-carrying URL]";
59
+ }
60
+ return whole;
61
+ });
62
+ // 4. High-entropy encoded-payload blobs → redact (SI-001: the raw payload must not be emitted).
63
+ for (const token of highEntropyTokens(text)) {
64
+ events.push({ category: "exfil:encoded", reason: "redacted a high-entropy encoded payload (possible exfiltration)" });
65
+ text = text.split(token).join("[redacted: high-entropy data]");
66
+ }
67
+ return { disposition: events.length > 0 ? "redact" : "allow", text, events };
68
+ }
69
+ //# sourceMappingURL=exfil.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exfil.js","sourceRoot":"","sources":["../../src/detect/exfil.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAgBlE,2FAA2F;AAC3F,gGAAgG;AAChG,6EAA6E;AAC7E,MAAM,iBAAiB,GAAa;IAClC,wFAAwF;IACxF,4EAA4E;IAC5E,kCAAkC;CACnC,CAAC;AACF,SAAS,qBAAqB,CAAC,IAAY;IACzC,KAAK,MAAM,EAAE,IAAI,iBAAiB,EAAE,CAAC;QACnC,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxB,IAAI,CAAC;YAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,2FAA2F;AAC3F,+FAA+F;AAC/F,MAAM,QAAQ,GAAG,2BAA2B,CAAC;AAE7C,MAAM,UAAU,mBAAmB,CAAC,OAAmB;IACrD,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,IAAI,IAAI,GAAG,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAEtE,kFAAkF;IAClF,MAAM,QAAQ,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAC7C,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,CAAC,IAAI,CAAC;YACV,QAAQ,EAAE,0BAA0B;YACpC,MAAM,EAAE,+GAA+G;YACvH,MAAM,EAAE,QAAQ;SACjB,CAAC,CAAC;QACH,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAChD,CAAC;IAED,gEAAgE;IAChE,MAAM,GAAG,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IACjC,IAAI,GAAG,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC;QACpB,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,EAAE,YAAY,GAAG,CAAC,OAAO,4CAA4C,EAAE,CAAC,CAAC;QAC1H,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;IAClB,CAAC;IAED,+FAA+F;IAC/F,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAa,EAAE,GAAW,EAAE,EAAE;QAC3D,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,EAAE,iEAAiE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;YACrI,OAAO,6CAA6C,CAAC;QACvD,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;IAEH,gGAAgG;IAChG,KAAK,MAAM,KAAK,IAAI,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5C,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,iEAAiE,EAAE,CAAC,CAAC;QACtH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;IACjE,CAAC;IAED,OAAO,EAAE,WAAW,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AAC/E,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * GENERATED from gitleaks' canonical config (github.com/gitleaks/gitleaks, MIT) — the full
3
+ * 222-detector secret dictionary. Do not hand-edit; regenerate from config/gitleaks.toml.
4
+ * File-path allowlists are dropped (CELLO scans message TEXT, not git files); the value-level
5
+ * stopwords + allow-regexes are kept for the false-positive layer (M9-OUT-001 AC-003).
6
+ */
7
+ export interface GitleaksRule {
8
+ id: string;
9
+ regex: string;
10
+ keywords: string[];
11
+ entropy: number;
12
+ }
13
+ export declare const GITLEAKS_RULES: GitleaksRule[];
14
+ /** Value-level stopwords: if a candidate secret contains one of these, it is a false positive. */
15
+ export declare const GITLEAKS_STOPWORDS: string[];
16
+ /** Value-level allow regexes: a candidate matching one of these is NOT a secret. */
17
+ export declare const GITLEAKS_ALLOW_REGEXES: string[];
18
+ //# sourceMappingURL=gitleaks-rules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitleaks-rules.d.ts","sourceRoot":"","sources":["../../src/detect/gitleaks-rules.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE;AAEhG,eAAO,MAAM,cAAc,EAAE,YAAY,EA+NxC,CAAC;AAEF,kGAAkG;AAClG,eAAO,MAAM,kBAAkB,EAAE,MAAM,EAA2E,CAAC;AAEnH,oFAAoF;AACpF,eAAO,MAAM,sBAAsB,EAAE,MAAM,EAAgiB,CAAC"}