Back to skill

Security audit

Vinculum - Shared Consciousness

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real LAN sync skill, but it shares agent data through an unauthenticated plaintext relay while claiming encryption.

Review carefully before installing. Use this only on trusted private networks and assume shared memories, activity, decisions, messages, filenames, and status can be read or modified by anyone who can reach the relay or access relay storage/config. Do not share secrets through it, do not rely on the advertised encryption, restrict the relay with localhost/VPN/firewall rules, and prefer waiting for real client-side encryption, peer authentication, and dependency updates before using it with sensitive data.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/gun-adapter.js:58
Finding
Collective Data Is Stored and Transmitted Without the Advertised Encryption<![CDATA[ ## Vulnerability Details **File Location**: `scripts/gun-adapter.js:58-68, 139-199`; `scripts/utils/schema.js:34-98` **Vulnerability Type**: Plaintext storage and transmission of potentially sensitive collective data **Risk Level**: High ### Vulnerable Code ```js async connect(namespaceId, encryptionKey, agentInfo) { if (!this.gun) { await this.init(); } this.namespaceId = namespaceId; this.encryptionKey = encryptionKey; this.agentId = agentInfo.instanceId; this.agentName = agentInfo.name; // Register this agent await this.registerAgent(agentInfo); ``` The key is retained in memory, but it is not subsequently used to encrypt or authenticate records: ```js async logActivity(activityData) { const entry = schema.createActivityEntry({ agent: this.agentName, ...activityData }); // Store entry data this.node('activity', entry.id).put(entry); // Add to activity collection this.gun.get(this.key('activities')).set({ id: entry.id, agent: entry.agent, timestamp: entry.timestamp }); await new Promise(r => setTimeout(r, 50)); return entry; } async shareMemory(memoryData) { const entry = schema.createMemoryEntry({ learnedBy: this.agentName, ...memoryData }); this.node('memory', entry.id).put(entry); this.gun.get(this.key('memories')).set({ id: entry.id, learned_by: entry.learned_by, timestamp: entry.timestamp }); await new Promise(r => setTimeout(r, 50)); return entry; } async recordDecision(decisionData) { const entry = schema.createDecisionEntry({ decidedBy: this.agentName, ...decisionData }); this.node('decision', entry.id).put(entry); this.gun.get(this.key('decisions')).set({ id: entry.id, topic: entry.topic, timestamp: entry.timestamp }); ``` The schema confirms that plaintext content, context, filenames, identity information, and decisions are put into these records: ```js function createMemoryEntry({ content, learnedBy, co ...[truncated 2261 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Encrypt every record client-side before passing it to Gun. 2. Use authenticated encryption, such as AES-256-GCM or XChaCha20-Poly1305, with a unique nonce for every record. 3. Derive separate encryption and authentication keys from the collective secret using HKDF or another established KDF. 4. Authenticate relevant metadata, including namespace, record type, record identifier, sender identity, and timestamp. 5. Decrypt data only on authorized clients; the relay should persist ciphertext only. 6. Add digital signatures so clients can verify which authorized agent created each record. 7. Implement key rotation and revocation procedures for compromised pairing codes. 8. Add automated tests that inspect relay storage and network messages and verify that memory, activity, decision, identity, and message plaintext never appears. 9. Correct the documentation immediately if encryption cannot yet be implemented; users must not be told that plaintext data is encrypted. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/relay-simple.js:31
Finding
Unauthenticated Gun Relay Allows Unauthorized Reading, Writing, and Agent Impersonation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/relay-simple.js:31-58, 72-82`; `scripts/gun-adapter.js:75-113` **Vulnerability Type**: Missing authentication and authorization on a network-exposed datastore **Risk Level**: High ### Vulnerable Code ```js // Create HTTP server const server = http.createServer((req, res) => { if (req.url === '/health' || req.url === '/status') { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ status: 'ok', uptime: process.uptime() * 1000, port: PORT })); return; } res.writeHead(200); res.end('Vinculum Relay'); }); // Use Gun's native server module - this properly handles WebSockets const Gun = require('gun'); require('gun/axe'); // Enable peer discovery const gun = Gun({ web: server, file: path.join(DATA_DIR, 'relay-data'), axe: true }); ``` The relay listens on every available network interface: ```js server.listen(PORT, '0.0.0.0', () => { fs.writeFileSync(PID_FILE, String(process.pid)); log(`Relay started on port ${PORT}`); log(`PID: ${process.pid}`); log(`Data: ${DATA_DIR}`); console.log(`Gun relay running on port ${PORT} (PID ${process.pid})`); }); ``` Agent records are written without a cryptographic identity or access-control check: ```js async registerAgent(agentInfo) { const identity = schema.createAgentIdentity(agentInfo); const status = schema.createAgentStatus({ online: true }); // Store agent identity (flat key) this.node('agent', this.agentId).put({ ...identity, ...status, type: 'agent' }); // Add to agents collection using set() this.gun.get(this.key('agents')).set({ id: this.agentId, name: agentInfo.name, added: Date.now() }); await new Promise(r => setTimeout(r, 100)); } ``` ### Technical Analysis The relay exposes Gun over a server bound to `0.0.0.0` and enables AXE peer discovery. The implementation does not configure: - Peer authentication - Gun S ...[truncated 1703 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Bind the relay to `127.0.0.1` by default. 2. Require an explicit, security-conscious configuration step before exposing it to a LAN or wider network. 3. Authenticate every peer using cryptographic identities. 4. Use Gun SEA or an equivalent signature scheme and reject unsigned or invalidly signed records. 5. Maintain an allowlist of authorized public keys for each namespace. 6. Enforce separate read and write permissions rather than treating knowledge of a graph name as authorization. 7. Disable AXE peer discovery unless the user explicitly enables it and understands the exposure. 8. Rate-limit connections and writes, impose record-size quotas, and cap namespace storage. 9. Validate all received records against strict schemas before storing or displaying them. 10. Recommend host firewall rules that restrict the relay port to trusted devices. 11. Add security tests proving that anonymous clients cannot read, create, or overwrite collective records. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/commands/relay.js:101
Finding
Remote Synchronization Accepts Plain HTTP Connections Without Transport Security<![CDATA[ ## Vulnerability Details **File Location**: `scripts/commands/relay.js:101-113, 263-283` **Vulnerability Type**: Cleartext transport and insufficient peer URL validation **Risk Level**: High ### Vulnerable Code The local relay is automatically recorded as a plaintext HTTP endpoint and the output encourages other devices to use an HTTP URL: ```js await configManager.set({ relay: { ...config.relay, port, auto_start: true }, peers: [`http://localhost:${port}/gun`] }); return formatting.formatSuccess( `Relay started on port ${port}\n\n` + `• PID: ${newStatus.pid}\n` + `• Local URL: \`http://localhost:${port}/gun\`\n` + `• Multicast: enabled for local network\n\n` + `Other devices can connect using:\n` + `\`/link config relay-peer http://<your-ip>:${port}/gun\`` ); ``` Remote peer validation only checks whether the supplied string begins with `http`: ```js async function addPeer(url, context) { const { configManager } = context; if (!url || !url.startsWith('http')) { return formatting.formatError( `Invalid peer URL. Must be http:// or https://\n\n` + `Example: \`/link relay peer http://192.168.1.100:8765/gun\`` ); } const config = await configManager.get(); const peers = config.peers || []; if (peers.includes(url)) { return formatting.formatWarning(`Peer already configured: ${url}`); } peers.push(url); await configManager.set({ peers }); ``` ### Technical Analysis The documented and generated multi-machine configuration uses `http://` rather than TLS-protected `https://` or `wss://`. Since the application-layer encryption key is not used to encrypt or authenticate records, transport traffic has no independent confidentiality or integrity protection. The validation is also not proper URL parsing. `startsWith('http')` accepts malformed or unexpected strings and does not enforce: - A specific protocol - A valid hostname or port - TLS for non-loopback destinations - Prohibiti ...[truncated 1086 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require `https:` or `wss:` for every non-loopback peer. 2. Permit plaintext HTTP only for an explicitly recognized loopback address and clearly label it as local-only. 3. Parse endpoints with the standard `URL` class instead of testing string prefixes. 4. Reject malformed URLs, unsupported protocols, embedded usernames or passwords, fragments, and unexpected paths. 5. Validate certificates normally and do not add insecure TLS-bypass options. 6. Support certificate pinning or mutually authenticated TLS for managed deployments. 7. Retain client-side authenticated encryption and signatures even when TLS is enabled, because relay operators remain outside the trusted endpoint boundary. 8. Update all examples and generated messages to recommend secure endpoints. 9. Warn users before saving or connecting to a plaintext non-loopback endpoint. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/index.js:54
Finding
Collective Secret Is Persisted Without Explicit Restrictive File Permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/index.js:54-70`; `scripts/commands/init.js:29-35`; `scripts/commands/join.js:45-57` **Vulnerability Type**: Insecure secret storage and unsafe configuration-file creation **Risk Level**: Medium ### Vulnerable Code The configuration manager creates the directory and writes the configuration using process-default permissions: ```js async set(updates) { if (!this.config) { await this.load(); } this.config = { ...this.config, ...updates }; // Ensure directory exists const dir = path.dirname(this.configPath); if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); } // Write config fs.writeFileSync(this.configPath, yaml.stringify(this.config)); return this.config; } ``` Initialization saves the collective key in that file: ```js await configManager.set({ enabled: true, namespace: network.namespaceId, encryption_key: network.encryptionKey }); ``` Joining another collective also persists the decoded key: ```js await configManager.set({ enabled: true, namespace: parsed.namespaceId, encryption_key: parsed.encryptionKey }); ``` ### Technical Analysis The collective secret is stored in `~/.config/clawdbot/vinculum.yaml`. Neither `mkdirSync()` nor `writeFileSync()` specifies restrictive modes. Effective permissions therefore depend on the account's umask and on whether the directory or file already existed. The write is also performed directly against the final pathname without: - Exclusive creation - Atomic temporary-file replacement - Symlink checks - Ownership validation - Permission correction for an existing file Although the key is currently not used to encrypt records, it is still presented as membership and invitation material. Future versions that enforce the key would also be exposed by this storage weakness. ### Attack Path 1. A victim runs `/link init` or `/link join <code>`. 2. The namespace and collective key are serialized into ...[truncated 1059 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create the configuration directory with mode `0700`. 2. Create configuration files with mode `0600`, and explicitly correct permissions on existing files. 3. Verify that the destination and parent directory are owned by the expected user. 4. Reject symbolic links using `lstat()` and, where supported, no-follow file-opening options. 5. Write to a uniquely named temporary file in the same directory using exclusive creation and mode `0600`. 6. Flush the temporary file and atomically rename it over the destination. 7. Avoid logging or returning the secret except when the user explicitly requests a new invitation. 8. Prefer an operating-system credential store or dedicated secret-storage facility for the collective key. 9. Document that Base64URL pairing codes contain the full collective secret and must be handled as credentials. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
Findings (35)

Tool Parameter Abuse

High
Category
Tool Misuse
Content
1. Reduce sync frequency: `/link config set syncInterval 10000`
2. Check for sync loops (two drones fighting over same file)
3. Restart relay: `/link relay stop` → `/link relay start`
4. Clear radata cache: `rm -rf skills/vinculum/radata/*`

### Problem: Conflicts in MEMORY.md
Confidence
86% confidence
Finding
The troubleshooting section recommends a destructive shell command using rm -rf to clear application data. Even though the path is scoped to the skill directory, README users may run it without understanding the consequences, and path mistakes, symlink abuse, or execution from an unexpected environment could result in unintended data loss.

Self-Modification

High
Category
Rogue Agent
Content
- Use ESLint configuration
- Follow existing patterns
- Add tests for new features
- Update SKILL.md for new commands

---
Confidence
85% confidence
Finding
Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
If the implementation does not actually provide the advertised synchronization, pairing, or encryption features, operators may rely on nonexistent protections and operational guarantees. While this is partly a product integrity issue, it becomes a security concern when users believe sensitive collective data is protected or shared only in constrained ways when that is not true.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
If the implementation does not actually provide the advertised synchronization, pairing, or encryption features, operators may rely on nonexistent protections and operational guarantees. While this is partly a product integrity issue, it becomes a security concern when users believe sensitive collective data is protected or shared only in constrained ways when that is not true.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
If the implementation does not actually provide the advertised synchronization, pairing, or encryption features, operators may rely on nonexistent protections and operational guarantees. While this is partly a product integrity issue, it becomes a security concern when users believe sensitive collective data is protected or shared only in constrained ways when that is not true.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
If the implementation does not actually provide the advertised synchronization, pairing, or encryption features, operators may rely on nonexistent protections and operational guarantees. While this is partly a product integrity issue, it becomes a security concern when users believe sensitive collective data is protected or shared only in constrained ways when that is not true.

Missing User Warnings

High
Confidence
96% confidence
Finding
Although the top-level link is disabled by default, the configuration pre-enables automatic syncing, relay auto-start, and multicast discovery once enabled, without any explicit warning, consent gate, or trust boundary controls. In the context of a P2P 'shared consciousness' feature over the local network, this increases the chance of accidental network exposure, automatic peer discovery, and uncontrolled propagation of shared data to unintended systems.

Known Vulnerable Dependency: ws==7.5.10 — 1 advisory(ies): CVE-2026-48779 (ws: Memory exhaustion DoS from tiny fragments and data chunks)

High
Category
Supply Chain
Confidence
97% confidence
Finding
The lockfile includes gun's nested dependency ws 7.5.10, which is flagged for a memory exhaustion denial-of-service issue from fragmented frames. Because this skill explicitly links bots over the local network using Gun.js P2P sync, it likely exposes a WebSocket-facing surface where a peer or attacker on the reachable network could crash or degrade relay/agent availability.

Known Vulnerable Dependency: ws==8.19.0 — 2 advisory(ies): CVE-2026-45736 (ws: Uninitialized memory disclosure); CVE-2026-48779 (ws: Memory exhaustion DoS from tiny fragments and data chunks)

High
Category
Supply Chain
Confidence
98% confidence
Finding
The top-level dependency ws 8.19.0 is identified with advisories for both uninitialized memory disclosure and memory exhaustion DoS. In this skill's context, real-time peer-to-peer synchronization over the local network increases risk because malformed or hostile WebSocket traffic could leak process memory contents or exhaust resources across connected bot instances.

Known Vulnerable Dependency: ws==8.19.0 — 2 advisory(ies): CVE-2026-45736 (ws: Uninitialized memory disclosure); CVE-2026-48779 (ws: Memory exhaustion DoS from tiny fragments and data chunks)

High
Category
Supply Chain
Confidence
97% confidence
Finding
The dependency specification ^8.18.0 for ws can resolve to ws 8.19.0, which the finding identifies as containing vulnerabilities including memory disclosure and memory-exhaustion denial of service. This is especially relevant here because the skill's purpose is real-time local-network peer synchronization over WebSockets, increasing exposure to malformed or attacker-controlled traffic.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The README prominently markets 'shared memories, activities, and decisions' across bots and machines, but it does not place a strong upfront warning that local bot data will be replicated and persisted on other systems in the collective. In a tool explicitly designed to sync agent memory and logs, users may unintentionally expose sensitive prompts, notes, or operational data to every joined node.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The documentation encourages adding arbitrary paths to syncPaths and explicitly states that non-markdown and binary files can be synced, but it does not adequately warn that this can replicate secrets, credentials, or unrelated private local files across the network. Because this feature broadens data-sharing scope beyond expected memory files, it materially increases the risk of accidental exfiltration within the collective.

Lp3

Medium
Category
MCP Least Privilege
Confidence
76% confidence
Finding
The skill metadata defines shell-based installation and implies environment-dependent execution, but it does not declare any explicit tool scope or permissions boundary. That makes the trust model unclear and increases the chance of unintended access to host environment data or execution capabilities during install/use.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The skill explicitly promotes sharing memories, activities, and decisions across bots, but it does not give a clear warning that this may include sensitive prompts, derived secrets, operational context, or private data. In a multi-agent environment, that omission can lead to accidental lateral disclosure across machines or users.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The quick-start flow encourages starting a relay and linking additional bots over the network without an explicit warning about multicast discovery, host visibility, and cross-machine data propagation. Users may enable network sharing immediately, before understanding that other systems on the LAN could discover or interact with the service depending on configuration.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The configuration shares broad categories like activity, memory, and decisions without defining scope, redaction rules, sensitivity limits, or exclusions. In a skill explicitly designed to link multiple bots and share state in real time, this can cause unintended disclosure of prompts, secrets, internal reasoning artifacts, or user-derived data across peers.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The `/link share` command transmits arbitrary user-provided text onto a peer-to-peer network immediately after basic non-empty validation, with no explicit warning, confirmation, or opportunity to review what will be shared. In a skill whose core purpose is cross-instance memory and decision sharing, this creates a real risk of accidental disclosure of sensitive prompts, secrets, internal notes, or personal data to other connected peers.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The code persists the network encryption key directly into configuration, creating a durable local secret that may be exposed through config file reads, backups, logs, or other local integrations. In this skill's context, that key grants access to a shared multi-bot namespace where participants can read and write collective memory, so compromise of the stored key can let an attacker join the network and tamper with or exfiltrate shared context.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
The join command persists the namespace identifier and encryption key directly into long-lived configuration as soon as a pairing code is accepted. In a skill whose purpose is to link multiple bot instances and share memories and decisions in real time, storing these credentials without explicit confirmation, scoping, or mention of secure storage increases the risk that anyone with config access can silently rejoin the collective or exfiltrate the shared-network secret.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
Starting the relay advertises that multicast is enabled and provides a LAN-accessible URL, but the command output does not present a clear security warning, consent step, or restriction before exposing the service to other devices on the local network. In a skill explicitly designed to share memories, activities, and decisions between bots, silent LAN exposure increases the chance of unintended access, data leakage, or peer connections from untrusted hosts on the same network.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The adapter connects agents into a shared Gun.js network and immediately registers the agent, starts syncing status, and exposes methods for sharing memories, activities, decisions, and messages without any user-facing disclosure or consent mechanism. In the context of a 'shared consciousness' skill that propagates potentially sensitive context across peers, silent network sharing can cause unanticipated disclosure of agent state, memory, and operational data to other local-network participants.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The skill is designed to share bot activity, memory, decisions, and status across the network, and this file performs that sharing without any user-facing disclosure or per-category consent checks beyond config flags. In the context of a 'shared consciousness' skill, this is especially sensitive because these data types can contain prompts, operational details, user content, or secrets, so silent synchronization materially increases privacy and data-leak risk.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
The skill contains code to start a detached background relay process automatically, which expands its capabilities beyond passive in-process bot linking into persistent local process management. Even if the relay is part of the intended sync architecture, silently spawning a daemonized process increases attack surface, persistence, and operational surprise, especially in environments where users did not explicitly approve background services.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
This code auto-starts a detached relay subprocess with no interactive confirmation or visible disclosure in this file, so users may unknowingly end up running a background network service. That is risky because it creates unintended persistence and a listening component that could expose data or be abused in multi-user or shared-host environments.

Description-Behavior Mismatch

Medium
Confidence
93% confidence
Finding
The daemon explicitly listens on 0.0.0.0, exposing the HTTP/Gun relay to every reachable interface rather than limiting it to loopback or a tightly scoped local-peer boundary. In the context of a memory/activity sync service, this increases the attack surface for unauthorized access, data tampering, or abuse of the relay by any host that can reach the port.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/commands/relay.js:84

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/index.js:168