Skip to content

Releases: Jovancoding/Network-AI

v5.8.4 — blackboard.py path-traversal fix (CWE-22)

24 May 11:19

Choose a tag to compare

Network-AI v5.8.4 — blackboard.py path-traversal fix (CWE-22)

Security

Arbitrary file read/write via --path in blackboard.py (Description-Behavior Mismatch, 96% confidence)

The --path CLI argument was forwarded to SharedBlackboard without any boundary check, allowing an agent or operator to read or write arbitrary local files outside the project directory. This contradicts the documented storage boundary and could be abused to overwrite sensitive project files or operate on attacker-chosen state.

Fix: Added a runtime path-traversal check immediately after argument parsing. args.path.resolve() is tested with relative_to(project_root); any path that escapes the project directory causes the script to exit with a clear error message. Symlink traversal is also blocked because resolve() is called before the comparison. The --path help text and script header comment both document this restriction. SKILL.md capabilities.filesystem updated to reflect the enforcement.

Files changed

scripts/blackboard.py, SKILL.md, CHANGELOG.md, package.json, skill.json, openapi.yaml, README.md, and all version-bearing doc files.

v5.8.3 — SKILL.md filesystem scope and script list accuracy

24 May 10:26

Choose a tag to compare

Network-AI v5.8.3 — SKILL.md filesystem scope and script list accuracy

This patch resolves 2 findings from the ClawHub SkillSpector v5.8.2 scan.

Fixed

Filesystem scope understated in capabilities manifest (Description-Behavior Mismatch, 84%)
capabilities.filesystem previously said "data/ directory only", but scripts/blackboard.py also reads and writes swarm-blackboard.md in the project root and data/pending_changes/<id>.json WAL entries. The field now enumerates every file path actually touched by the bundled Python scripts. A separate privacy.blackboard_file entry has been added for swarm-blackboard.md.

Incorrect script names in clawhub_python_scripts (Intent-Code Divergence, 90%)
The frontmatter listed token_manager.py and check_context.py — neither of which exists — and omitted validate_token.py and revoke_token.py, both of which exist in scripts/ and are referenced throughout the documentation. Corrected to the six actual scripts: blackboard.py, check_permission.py, context_manager.py, swarm_guard.py, validate_token.py, revoke_token.py.

Files changed

SKILL.md, CHANGELOG.md, package.json, skill.json, openapi.yaml, README.md, and all version-bearing doc files.

v5.8.2 — Token masking, inject-block, capabilities manifest, SkillSpector fixes

24 May 09:31

Choose a tag to compare

Network-AI v5.8.2 — Security & SkillSpector fixes

This patch resolves 8 findings from the ClawHub SkillSpector v5.8.1 scan, including two security fixes.

Security fixes

Token exposure in grant listings (Ssd3, 98% confidence)
scripts/check_permission.py --active-grants --json previously included a token_full field with the live grant token in every listing entry. Full tokens are now only shown at issuance time. All listing output uses the masked prefix (token[:16] + "...") only. The script header now includes an explicit warning that justification strings are logged verbatim to data/audit_log.jsonl and must not contain PII, credentials, or secrets.

Prompt injection not blocked in context_manager.py (Missing User Warnings, 93% confidence)
context_manager.py inject previously warned to stderr about detected prompt-injection patterns in data/project-context.json but still proceeded to emit the context block. Injection is now blocked (exit 1) when _validate_context() returns warnings. A new --force flag allows operators to override in explicitly trusted/CI environments. This prevents adversarially-crafted context entries from persisting across agent sessions.

Metadata / documentation fixes

  • SKILL.md — explicit capabilities manifest (Lp3, 90%): Added a machine-readable capabilities block under metadata.openclaw declaring filesystem, env_vars, shell_exec, and tcp_port surfaces, scope, and conditions.
  • SKILL.md — scope ambiguity resolved (Mismatch Medium/High, 92%/89%): bundle_scope and network_calls split from single prose strings into structured sub-fields: clawhub_python_scripts (local-only, zero network) vs npm_full_package (TypeScript library + CLI + optional MCP SSE server). Operators can now unambiguously determine what ClawHub ships vs what npm install delivers.
  • claude-tools.json — vague trigger conditions (Vague Triggers, 83%): Added explicit DENY conditions and scoping rules to delegate_task and spawn_parallel_agents describing when the tools must not be invoked.
  • SECURITY.md — auto-approve warning (Excessive Agency, 78%): ApprovalGate entry updated to explicitly warn that auto_approve: true is only appropriate in isolated CI/dev sandboxes and must never be used in production. Also added to SKILL.md privacy.auto_approve_warning.
  • SECURITY.md — justification field sensitivity (Ssd3, 94%): SecureAuditLogger table entry now documents that justification fields are stored verbatim and must not contain PII, credentials, or secrets.

Files changed

scripts/check_permission.py, scripts/context_manager.py, SKILL.md, claude-tools.json, SECURITY.md, .github/SECURITY.md, CHANGELOG.md, package.json, skill.json, openapi.yaml, README.md, and all version-bearing doc files.

v5.8.1 — SkillSpector accuracy fixes (bundle_scope, THREAT_MODEL, swarm_guard I/O)

24 May 08:55

Choose a tag to compare

What's changed

Fixed

  • SKILL.md frontmatter (bundle_scope / network_calls) — Fields now accurately describe both scopes: Python scripts are local-only, stdlib-only, zero network calls; the full npm package also includes TypeScript modules, a CLI, and an optional self-hosted MCP SSE server that binds a TCP port when explicitly started by the operator and requires a non-empty bearer-token secret. Resolves ClawHub SkillSpector High findings (Intent-Code Divergence, Description-Behavior Mismatch).
  • THREAT_MODEL.md — "There is no hosted service" replaced with "There is no SaaS or cloud-hosted service" with an explicit callout that the optional MCP SSE server is a network-reachable service boundary when started by the operator. Resolves SkillSpector Medium finding (Intent-Code Divergence).
  • scripts/swarm_guard.py I/O header — READS/WRITES comment updated to list all files actually written (task_tracking.json, agent_health.json, budget_tracking.json) and to document that the base data directory is data/ or data/<env>/ when NETWORK_AI_ENV / --env is set. Resolves SkillSpector Medium findings (Description-Behavior Mismatch, Intent-Code Divergence).

Full changelog: https://github.com/Jovancoding/Network-AI/blob/main/CHANGELOG.md

v5.8.0 — Doctor, Inspect, Kill Switch, --why scoring, Minimal Mode, Threat Model

23 May 17:09

Choose a tag to compare

What's changed

Added

  • network-ai doctor — Self-diagnostic command: validates data directory, env routing, audit log JSONL integrity, stale WAL entries, kill-switch state, MCP secret presence, and blackboard schema. Exits 0 all-pass / 1 any-fail. Supports --json.
  • network-ai inspect <key> — Inspect any blackboard key: value, metadata (source agent, timestamp, TTL, version), pending WAL history (--history), audit trail (--audit).
  • network-ai pause / network-ai resume — Kill switch: writes/removes a data/SYSTEM_PAUSED sentinel. doctor reports pause state.
  • --why flag on auth token — Prints full permission scoring breakdown (justification 40%, trust 30%, risk 30%, weighted total, verdict) before issuing a token.
  • --minimal global flag — Disables WAL replay and TTL sweep for fast CI/test startup. Also set via NETWORK_AI_MINIMAL=1.
  • AuthGuardian.scoreRequest() — New public read-only method returning the full scoring breakdown without issuing a token or writing to the audit log.
  • LockedBlackboard disableWal option — New disableWal?: boolean in LockedBlackboardOptions; also activated by NETWORK_AI_MINIMAL=1.

Documentation

  • THREAT_MODEL.md — Adversary profiles, trust boundaries, explicit non-goals, security controls summary.
  • DATA_LOCATIONS.md — Every file Network-AI creates at runtime: path, purpose, data classification, operator responsibilities.
  • SUPPLY_CHAIN.md — One runtime dependency, no install-time scripts, network surface, SLSA Build Level 2 / npm provenance verification.
  • SECURITY.md — Added Disclosure SLA table (acknowledgment 48h, Critical/High patch 14 days, public disclosure 7 days post-patch).

Full changelog: https://github.com/Jovancoding/Network-AI/blob/main/CHANGELOG.md

v5.7.2 — Security Fix GHSA-r78r-rwrf-rjwp

23 May 14:58

Choose a tag to compare

Security Fix — GHSA-r78r-rwrf-rjwp / CVE-2026-46701

Severity: High (CWE-306 / CWE-862 — Missing Authentication, incomplete fix)
Credit: @SnailSploit

What was vulnerable

McpSseServer._isAuthorized() returned true when no secret was configured, granting every unauthenticated caller full access to all 22 MCP tools (blackboard_write, agent_spawn, config_set, token management, etc.). The bin/mcp-server.ts CLI path already exited on missing secret, but callers who instantiated McpSseServer directly from lib/ bypassed this guard entirely.

What changed

  • _isAuthorized() — now returns false (fail closed) when secret is empty. Requests are denied regardless of bind address.
  • listen() — now rejects with a hard Error if McpSseServerOptions.secret is empty, preventing accidental open deployments.
  • McpSseTransport — new optional secret constructor parameter; attaches Authorization: Bearer header automatically when set.

Upgrade

npm install network-ai@5.7.2

All callers that instantiate McpSseServer directly must pass a non-empty secret. For stdio mode (Claude Desktop / Cursor / Glama) use --stdioMcpSseServer is not involved.

Tests

All 3,136 tests pass. test-phase6.ts Section 7 updated to supply secrets to all authenticated endpoints.


Full changelog: https://github.com/Jovancoding/Network-AI/blob/main/CHANGELOG.md

v5.7.1 — CodeQL Security Fixes

19 May 20:27

Choose a tag to compare

Network-AI v5.7.1 — CodeQL Security Fixes

All 3,136 tests pass. Zero TypeScript errors.

Security / Bug Fixes

compactWAL() race condition — CWE-367 (High)

lib/locked-blackboard.ts — Replaced the existsSync + writeFileSync pattern with a single atomic file-descriptor operation:

// Before (TOCTOU — file could be replaced between check and write):
if (existsSync(this.walPath)) {
  writeFileSync(this.walPath, '', { encoding: 'utf-8', mode: 0o600 });
}

// After (atomic — openSync 'w' = O_WRONLY | O_CREAT | O_TRUNC):
const fd = openSync(this.walPath, 'w', 0o600);
closeSync(fd);

openSync('w') atomically truncates an existing WAL or creates a new empty one — no intermediate existence check that could be exploited in a race. Resolves CodeQL js/file-system-race #160.

Unused imports removed — test-phase11.ts

  • CircuitOpenError import removed (CodeQL js/unused-local-variable #161)
  • existsSync import removed (CodeQL js/unused-local-variable #162)

Both were dead code from Phase 11 development that were never referenced after final test implementation.

Useless assignment removed — test-phase11.ts:384

c = await hookMgr.runAfter(c) reassigned c but the returned context was never read. Changed to await hookMgr.runAfter(c). Resolves CodeQL js/useless-assignment-to-local #163.

Zero functional changes — all 3,136 tests continue to pass unchanged.

v5.7.0 — OTel ITelemetryProvider BYOT Interface

19 May 19:31

Choose a tag to compare

Network-AI v5.7.0 — OTel ITelemetryProvider BYOT Interface

All 3,136 tests pass. Zero TypeScript errors.

Features

ITelemetryProvider BYOT abstraction (lib/telemetry-provider.ts)

A zero-dependency telemetry interface that lets you plug any OpenTelemetry SDK — or any custom backend — into Network-AI without modifying a single adapter.

Interface

interface ITelemetryProvider {
  startSpan(name: string, attributes?: SpanAttributes): unknown;
  endSpan(span: unknown, attributes?: SpanAttributes): void;
  recordError(span: unknown, error: Error): void;
}

Built-in implementations

Class Purpose
NullTelemetryProvider No-op default — zero overhead, zero imports
CapturingTelemetryProvider In-memory store for tests and local dev

createOtelHooks(provider)

Factory that converts any ITelemetryProvider into three ExecutionHook[] ready to register with AdapterHookManager:

import { createOtelHooks, CapturingTelemetryProvider } from './lib/telemetry-provider.js';
import { AdapterHookManager } from './lib/adapter-hooks.js';

const telemetry = new CapturingTelemetryProvider();
const hookManager = new AdapterHookManager();
hookManager.registerHooks(createOtelHooks(telemetry));

// After execution:
const spans = telemetry.getSpans(); // CapturedSpan[]

Wiring your OTel SDK

class MyOtelProvider implements ITelemetryProvider {
  startSpan(name: string, attrs?: SpanAttributes) {
    return otel.tracer('network-ai').startSpan(name, { attributes: attrs });
  }
  endSpan(span: unknown) { (span as Span).end(); }
  recordError(span: unknown, error: Error) {
    (span as Span).recordException(error);
    (span as Span).setStatus({ code: SpanStatusCode.ERROR });
  }
}

hookManager.registerHooks(createOtelHooks(new MyOtelProvider()));

Zero new runtime dependencies — BYOT principle maintained throughout.

16 new tests added to test-phase11.ts.

v5.6.1 — Circuit Breaker on AdapterRegistry

19 May 19:19

Choose a tag to compare

Network-AI v5.6.1 — Circuit Breaker on AdapterRegistry

All 3,136 tests pass. Zero TypeScript errors.

Features

Circuit Breaker on AdapterRegistry (lib/circuit-breaker.ts)

A new standalone CircuitBreaker class with a three-state machine wired into every adapter in AdapterRegistry.

State machine

CLOSED ──(failureThreshold failures)──► OPEN
  ▲                                       │
  │ (successThreshold successes)    (recoveryTimeoutMs)
  │                                       ▼
  └────────────────────────── HALF_OPEN ──┤
                                          │ (failure)
                                          └──► OPEN
State Behavior
CLOSED Normal execution — failures increment counter
OPEN CircuitOpenError thrown immediately — no call made to adapter
HALF_OPEN One probe call allowed — success closes, failure re-opens

Configuration

const registry = new AdapterRegistry({
  circuitBreaker: {
    failureThreshold: 3,       // trips after 3 consecutive failures (default)
    recoveryTimeoutMs: 30_000, // waits 30 s before probing (default)
    successThreshold: 1,       // 1 success in HALF_OPEN closes circuit (default)
    onStateChange: (from, to, adapterName) => console.log(`${adapterName}: ${from}${to}`),
  },
  fallbackChain: ['backup-agent', 'emergency-agent'],
});

Fallback chain

When the circuit is OPEN, the registry automatically tries each adapter in fallbackChain in order before returning a CIRCUIT_OPEN error code. This enables zero-downtime failover without changing any call site.

Public API

registry.getCircuitState('my-agent');        // 'CLOSED' | 'OPEN' | 'HALF_OPEN'
registry.resetCircuit('my-agent');           // force back to CLOSED
registry.setCircuitBreakerConfig({ failureThreshold: 5 });

New event types

circuit:open, circuit:half-open, circuit:close added to AdapterEventType.

Zero new runtime dependencies — BYOC principle maintained throughout.

13 new tests added to test-phase11.ts.

v5.6.0 — WAL Crash Recovery

19 May 19:09

Choose a tag to compare

Network-AI v5.6.0 — WAL Crash Recovery

All 3,136 tests pass. Zero TypeScript errors.

Features

LockedBlackboard Write-Ahead Log (WAL) crash recovery (lib/locked-blackboard.ts)

Every write(), commit(), and delete() now follows a strict append-before-write + checkpoint-after-write pattern:

  1. Before the file write — an append record is written to .wal.jsonl
  2. The actual state file is updated
  3. After the write succeeds — a checkpoint record is appended to .wal.jsonl

On construction, replayWAL() is called automatically after loadFromDisk(). It scans .wal.jsonl for any append records that have no matching checkpoint (= the process crashed between steps 1 and 3) and replays them into the in-memory store. The WAL is then compacted.

// WAL is automatic — nothing to configure
const board = new LockedBlackboard('.', { env: 'prod' });
// Any uncommitted ops from a previous crash are replayed here

// Manual truncation after a full snapshot:
await board.compactWAL();

WAL file locations

Mode Path
Env-scoped <basePath>/<env>/.wal.jsonl
Legacy (no env) <basePath>/data/.wal.jsonl

Resilience properties

  • Partial writes at crash time produce malformed tail lines — silently skipped
  • WAL replay is idempotent: replaying an already-committed op overwrites with the same value
  • compactWAL() is safe to call at any time; a new WAL starts clean on the next write

7 new tests added to test-phase11.ts.