@drakon-systems/shieldcortex-realtime 4.28.1 → 4.30.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/cloud-sync.ts CHANGED
@@ -3,12 +3,24 @@
3
3
  // Network egress for SC threat events. See CHANGELOG.md v4.12.8 / v4.12.9.
4
4
 
5
5
  type CloudSyncConfig = {
6
+ cloudEnabled?: boolean;
6
7
  cloudApiKey?: string;
7
8
  cloudBaseUrl?: string;
8
9
  };
9
10
 
10
11
  export function cloudSync(threat: Record<string, unknown>, cfg: CloudSyncConfig): void {
11
- if (!cfg.cloudApiKey) return;
12
+ // Consent gate: require cloud explicitly enabled AND an API key — matching every
13
+ // other egress sender (intercept-ingest.ts, src/cloud/*). Previously this checked
14
+ // the key alone, so events could leave the machine with a key present even when
15
+ // cloud sync was "off" (ClawScan finding: external scanning without a local-only
16
+ // default).
17
+ if (!cfg.cloudEnabled || !cfg.cloudApiKey) return;
18
+ // Privacy: never transmit raw LLM input. Strip any input content/preview snippet —
19
+ // forward threat METADATA only (ClawScan finding: previews may contain credentials
20
+ // or confidential data). The local audit log keeps fuller detail for triage.
21
+ const metadata: Record<string, unknown> = { ...threat };
22
+ delete metadata.content;
23
+ delete metadata.preview;
12
24
  const url = `${cfg.cloudBaseUrl || 'https://api.shieldcortex.ai'}/v1/threats`;
13
25
  fetch(url, {
14
26
  method: 'POST',
@@ -16,7 +28,7 @@ export function cloudSync(threat: Record<string, unknown>, cfg: CloudSyncConfig)
16
28
  'Content-Type': 'application/json',
17
29
  Authorization: `Bearer ${cfg.cloudApiKey}`,
18
30
  },
19
- body: JSON.stringify(threat),
31
+ body: JSON.stringify(metadata),
20
32
  signal: AbortSignal.timeout(5000),
21
33
  }).catch(() => {
22
34
  // Fire-and-forget — never block on cloud sync failure
@@ -2,8 +2,19 @@
2
2
  //
3
3
  // Network egress for SC threat events. See CHANGELOG.md v4.12.8 / v4.12.9.
4
4
  export function cloudSync(threat, cfg) {
5
- if (!cfg.cloudApiKey)
5
+ // Consent gate: require cloud explicitly enabled AND an API key — matching every
6
+ // other egress sender (intercept-ingest.ts, src/cloud/*). Previously this checked
7
+ // the key alone, so events could leave the machine with a key present even when
8
+ // cloud sync was "off" (ClawScan finding: external scanning without a local-only
9
+ // default).
10
+ if (!cfg.cloudEnabled || !cfg.cloudApiKey)
6
11
  return;
12
+ // Privacy: never transmit raw LLM input. Strip any input content/preview snippet —
13
+ // forward threat METADATA only (ClawScan finding: previews may contain credentials
14
+ // or confidential data). The local audit log keeps fuller detail for triage.
15
+ const metadata = { ...threat };
16
+ delete metadata.content;
17
+ delete metadata.preview;
7
18
  const url = `${cfg.cloudBaseUrl || 'https://api.shieldcortex.ai'}/v1/threats`;
8
19
  fetch(url, {
9
20
  method: 'POST',
@@ -11,7 +22,7 @@ export function cloudSync(threat, cfg) {
11
22
  'Content-Type': 'application/json',
12
23
  Authorization: `Bearer ${cfg.cloudApiKey}`,
13
24
  },
14
- body: JSON.stringify(threat),
25
+ body: JSON.stringify(metadata),
15
26
  signal: AbortSignal.timeout(5000),
16
27
  }).catch(() => {
17
28
  // Fire-and-forget — never block on cloud sync failure
package/dist/index.js CHANGED
@@ -195,6 +195,9 @@ function normaliseConfig(raw) {
195
195
  if (typeof value.cloudBaseUrl === "string" && value.cloudBaseUrl.trim()) {
196
196
  config.cloudBaseUrl = value.cloudBaseUrl.trim();
197
197
  }
198
+ if (typeof value.cloudEnabled === "boolean") {
199
+ config.cloudEnabled = value.cloudEnabled;
200
+ }
198
201
  if (typeof value.binaryPath === "string" && value.binaryPath.trim()) {
199
202
  config.binaryPath = value.binaryPath.trim();
200
203
  }
@@ -494,7 +497,9 @@ function handleLlmInput(event, ctx) {
494
497
  };
495
498
  auditLog(entry);
496
499
  loadConfig()
497
- .then(cfg => cloudSync({ ...entry, content: text.slice(0, 200) }, cfg))
500
+ // Pass the local entry as-is; cloudSync strips the input preview/content
501
+ // before transmit (metadata-only egress). No raw LLM input leaves here.
502
+ .then(cfg => cloudSync(entry, cfg))
498
503
  .catch(() => { });
499
504
  }
500
505
  }
@@ -2,6 +2,11 @@ export function syncInterceptEvent(event, config) {
2
2
  if (!config.cloudEnabled || !config.cloudApiKey)
3
3
  return;
4
4
  const url = `${config.cloudBaseUrl}/v1/audit/ingest`;
5
+ // Privacy: forward audit METADATA only — strip the content preview so raw memory
6
+ // text never leaves the machine (ClawScan finding: previews may contain credentials
7
+ // or confidential data). The local audit JSONL retains the preview for triage.
8
+ const metadata = { ...event };
9
+ delete metadata.preview;
5
10
  fetch(url, {
6
11
  method: 'POST',
7
12
  headers: {
@@ -9,7 +14,7 @@ export function syncInterceptEvent(event, config) {
9
14
  Authorization: `Bearer ${config.cloudApiKey}`,
10
15
  },
11
16
  body: JSON.stringify({
12
- events: [{ ...event, source: 'openclaw-interceptor' }],
17
+ events: [{ ...metadata, source: 'openclaw-interceptor' }],
13
18
  }),
14
19
  signal: AbortSignal.timeout(5_000),
15
20
  }).catch(() => {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "shieldcortex-realtime",
3
- "version": "4.28.1",
3
+ "version": "4.30.0",
4
4
  "name": "ShieldCortex Real-time Scanner",
5
5
  "description": "Real-time defence scanning on LLM input, memory extraction on LLM output, and active tool call interception with approval gating.",
6
6
  "kind": null,
package/index.ts CHANGED
@@ -143,6 +143,7 @@ type PluginApi = {
143
143
  // ==================== CONFIG ====================
144
144
 
145
145
  interface SCConfig {
146
+ cloudEnabled?: boolean;
146
147
  cloudApiKey?: string;
147
148
  cloudBaseUrl?: string;
148
149
  binaryPath?: string;
@@ -250,6 +251,9 @@ function normaliseConfig(raw: unknown): SCConfig {
250
251
  if (typeof value.cloudBaseUrl === "string" && value.cloudBaseUrl.trim()) {
251
252
  config.cloudBaseUrl = value.cloudBaseUrl.trim();
252
253
  }
254
+ if (typeof value.cloudEnabled === "boolean") {
255
+ config.cloudEnabled = value.cloudEnabled;
256
+ }
253
257
  if (typeof value.binaryPath === "string" && value.binaryPath.trim()) {
254
258
  config.binaryPath = value.binaryPath.trim();
255
259
  }
@@ -594,7 +598,9 @@ function handleLlmInput(event: LlmInputEvent, ctx: AgentCtx): void {
594
598
  };
595
599
  auditLog(entry);
596
600
  loadConfig()
597
- .then(cfg => cloudSync({ ...entry, content: text.slice(0, 200) }, cfg))
601
+ // Pass the local entry as-is; cloudSync strips the input preview/content
602
+ // before transmit (metadata-only egress). No raw LLM input leaves here.
603
+ .then(cfg => cloudSync(entry, cfg))
598
604
  .catch(() => {});
599
605
  }
600
606
  }
@@ -12,6 +12,12 @@ export function syncInterceptEvent(event: InterceptAuditEntry, config: CloudConf
12
12
 
13
13
  const url = `${config.cloudBaseUrl}/v1/audit/ingest`;
14
14
 
15
+ // Privacy: forward audit METADATA only — strip the content preview so raw memory
16
+ // text never leaves the machine (ClawScan finding: previews may contain credentials
17
+ // or confidential data). The local audit JSONL retains the preview for triage.
18
+ const metadata: Record<string, unknown> = { ...event };
19
+ delete metadata.preview;
20
+
15
21
  fetch(url, {
16
22
  method: 'POST',
17
23
  headers: {
@@ -19,7 +25,7 @@ export function syncInterceptEvent(event: InterceptAuditEntry, config: CloudConf
19
25
  Authorization: `Bearer ${config.cloudApiKey}`,
20
26
  },
21
27
  body: JSON.stringify({
22
- events: [{ ...event, source: 'openclaw-interceptor' }],
28
+ events: [{ ...metadata, source: 'openclaw-interceptor' }],
23
29
  }),
24
30
  signal: AbortSignal.timeout(5_000),
25
31
  }).catch(() => {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "shieldcortex-realtime",
3
- "version": "4.28.1",
3
+ "version": "4.30.0",
4
4
  "name": "ShieldCortex Real-time Scanner",
5
5
  "description": "Real-time defence scanning on LLM input, memory extraction on LLM output, and active tool call interception with approval gating.",
6
6
  "kind": null,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drakon-systems/shieldcortex-realtime",
3
- "version": "4.28.1",
3
+ "version": "4.30.0",
4
4
  "description": "OpenClaw plugin for ShieldCortex real-time defence scanning and optional memory extraction.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",