Back to skill

Security audit

BrainX V5 — The First Brain for OpenClaw

Security checks for vulnerabilities and agentic risk

Overview

The skill is a disclosed memory system, but it automatically captures, shares, and injects broad cross-agent memories and can promote them into startup instruction files, so it needs careful review before installation.

Install only if you intentionally want a shared, persistent agent memory system with startup injection and are prepared to manage it like sensitive infrastructure. Disable unattended promotion into AGENTS.md, TOOLS.md, and SOUL.md unless every rule is reviewed, avoid storing personal or financial data by default, encrypt or exclude secrets from backups, and warn users that search and memory content may be sent to OpenAI for embeddings.

Vulnerability Patterns
  • 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
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (4)

T02 · Agent Memory Poisoning

Error
Location
hook/handler.js:128
Finding
Untrusted Cross-Agent Memories Are Persistently Injected into Privileged Bootstrap Context<![CDATA[ ## Vulnerability Details **File Location**: `hook/handler.js:128-161, 349-421, 552-571` **Vulnerability Type**: Persistent memory poisoning and cross-agent prompt injection **Risk Level**: Critical ### Vulnerable Code ```js async function queryTopMemories(pool, { limit = 8, minImportance = 5, agentName = null }) { // Split into own-agent + cross-agent slots to ensure visibility across agents const crossSlots = Math.max(2, Math.floor(limit * 0.3)); const ownSlots = limit - crossSlots; return withRetry(async () => { const ownFilter = agentName ? `AND (agent = $3 OR agent IS NULL)` : ''; const ownParams = agentName ? [minImportance, ownSlots, agentName] : [minImportance, ownSlots]; const { rows: ownRows } = await pool.query( `SELECT content, tier, importance, type, agent, context FROM brainx_memories WHERE tier IN ('hot', 'warm') AND importance >= $1 AND superseded_by IS NULL ${ownFilter} ORDER BY importance DESC, last_seen DESC NULLS LAST, created_at DESC LIMIT $2`, ownParams ); const crossFilter = agentName ? `AND agent IS DISTINCT FROM $3 AND agent IS NOT NULL` : ''; const crossParams = agentName ? [minImportance, crossSlots, agentName] : [minImportance, crossSlots]; const { rows: crossRows } = await pool.query( `SELECT content, tier, importance, type, agent, context FROM brainx_memories WHERE tier IN ('hot', 'warm') AND importance >= $1 AND superseded_by IS NULL ${crossFilter} ORDER BY CASE WHEN 'cross-agent' = ANY(tags) THEN 1 ELSE 0 END DESC, importance DESC, last_seen DESC NULLS LAST, created_at DESC LIMIT $2`, crossParams ); return [...ownRows, ...crossRows]; }, "queryTopMemories"); } ``` ```js function buildMemorySection(agentName, timestamp, teamMems, ownMems) { const lines = [BRAINX_START, ...[truncated 4532 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not write untrusted memory text into privileged bootstrap files such as `MEMORY.md`, `AGENTS.md`, or `SOUL.md`. 2. Pass retrieved memories through a dedicated untrusted-data channel that explicitly tells the model the content is reference material, not instructions. 3. Implement per-agent access controls and deny cross-agent retrieval by default. 4. Require verified provenance before a memory is eligible for bootstrap injection. 5. Store and inject structured facts rather than unrestricted Markdown. 6. Detect and quarantine imperative, meta-instruction, tool-invocation, credential-request, and safety-override patterns. 7. Add explicit delimiters and escape Markdown constructs, while recognizing that escaping alone is not a complete prompt-injection defense. 8. Require human approval for memories that could alter agent behavior. 9. Add expiration, revocation, and audit mechanisms for all injected memories. 10. Test with adversarial memories that attempt to override instructions, invoke tools, exfiltrate data, or propagate between agents. ]]>

T01 · Skill Instruction Hijacking

Error
Location
README.md:253
Finding
Scheduled Auto-Promotion Can Convert Learned Content into Permanent Agent Instructions<![CDATA[ ## Vulnerability Details **File Location**: `README.md:253-275, 1388-1441, 1626-1653` **Vulnerability Type**: Autonomous modification of privileged agent instruction files **Risk Level**: Critical ### Vulnerable Configuration and Documented Behavior ```text ### Auto-Promotion Pipeline What it does: Detects high-recurrence patterns and automatically promotes them as permanent rules into agent workspace files (AGENTS.md, TOOLS.md, SOUL.md). Closes the learning → rule loop without any human intervention required. How it works: 1. auto-promoter.js scans brainx_patterns for entries with recurrence_count ≥ threshold 2. Classifies each pattern to its target file 3. Saves suggestions as BrainX memories tagged promotion-suggestion 4. promotion-applier.js reads pending suggestions, distills them via LLM (gpt-4.1-mini), and writes the final rules into the workspace files under the ## Auto-Promoted Rules section ``` ```text Reads pending promotion suggestions, distills each suggestion via LLM (gpt-4.1-mini) into a concise rule, and writes the final rules into the target workspace files under the ## Auto-Promoted Rules section. 1. Queries BrainX for memories tagged promotion-suggestion with status = pending 2. For each suggestion, calls gpt-4.1-mini to distill it into a 1-2 sentence rule 3. Appends the rule to the ## Auto-Promoted Rules section in the target workspace file (AGENTS.md, TOOLS.md, or SOUL.md) 4. Marks the suggestion memory as status = promoted ``` ```cron # Daily: Cross-agent learning + Contradiction detection + Quality scoring + Promotions 0 3 * * * cd /path/to/brainx-v5 && node scripts/cross-agent-learning.js >> logs/cross-agent.log 2>&1 30 3 * * * cd /path/to/brainx-v5 && node scripts/contradiction-detector.js >> logs/contradiction.log 2>&1 0 4 * * * cd /path/to/brainx-v5 && node scripts/quality-scorer.js >> logs/quality.log 2>&1 15 4 * * * cd /path/to/brainx-v5 && node scripts/auto-promoter.js --save >> logs/auto-promoter.lo ...[truncated 2740 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Eliminate automatic writes to `AGENTS.md`, `TOOLS.md`, `SOUL.md`, and equivalent instruction files. 2. Make the promotion pipeline proposal-only and require explicit human approval for every rule. 3. Disable `promotion-applier.js --apply` in all unattended cron pipelines. 4. Require signed or otherwise authenticated provenance for promotion candidates. 5. Treat recurrence only as a relevance metric, never as proof of trust. 6. Use a restrictive schema for candidate rules and reject tool commands, network destinations, credential requests, policy overrides, and recursive self-modification. 7. Show reviewers the complete source memories, originating agents, timestamps, and transformations. 8. Store approved rules in a separate, version-controlled file with mandatory code review. 9. Implement atomic writes, backups, diffs, audit logs, and one-command rollback. 10. Add rate limits and diversity checks so repetition from one source cannot satisfy a promotion threshold. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
lib/openai-rag.js:267
Finding
Search Queries Are Sent to OpenAI Before Secret and PII Redaction<![CDATA[ ## Vulnerability Details **File Location**: `lib/openai-rag.js:267-276`; outbound transmission at `lib/embedding-client.js:34-56` **Vulnerability Type**: Sensitive information disclosure to an external service **Risk Level**: High ### Vulnerable Code ```js async function search(query, options = {}) { const { limit = 10, minImportance = 0, tierFilter = null, contextFilter = null, minSimilarity = 0.3 } = options; const queryEmbedding = await embed(query); let sql = ` SELECT id, type, content, context, tier, agent, importance, tags, created_at, last_accessed, access_count, source_session, superseded_by, status, category, pattern_key, recurrence_count, first_seen, last_seen, resolved_at, promoted_to, resolution_notes, source_kind, source_path, confidence_score, expires_at, sensitivity, 1 - (embedding <=> $1::vector) AS similarity FROM brainx_memories WHERE importance >= $2 AND superseded_by IS NULL AND (expires_at IS NULL OR expires_at > NOW()) AND embedding IS NOT NULL `; ``` ```js async function embed(text) { const cfg = getOpenAIConfig(); if (text === null || text === undefined) { throw new Error('embed() requires a non-null/undefined input'); } const inputText = typeof text === 'string' ? text : String(text); let lastError; for (let attempt = 0; attempt < MAX_RETRIES; attempt++) { try { const res = await fetch('https://api.openai.com/v1/embeddings', { method: 'POST', headers: { Authorization: `Bearer ${cfg.apiKey}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ model: cfg.model, input: inputText, dimensions: cfg.dimensions }) }); ``` ### Technical Analysis `search()` passes the raw search query to `embed()`. The embedding client then transmits that text to the OpenAI embeddings endpoint. The ...[truncated 1792 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Run `scrubTextPII()` on every query before calling `embed()`. 2. Apply redaction inside the embedding client as a mandatory final safety boundary so callers cannot bypass it. 3. Reject rather than merely redact recognized private keys, connection strings, session tokens, and high-confidence credentials. 4. Warn users clearly that semantic search sends query text to an external embedding provider. 5. Require explicit configuration or consent before enabling external embeddings. 6. Offer a local embedding provider for sensitive deployments. 7. Add context-aware allowlists only when administrators explicitly accept the disclosure risk. 8. Add tests for OpenAI keys, GitHub tokens, JWTs, private keys, passwords, emails, internal IP addresses, and database URLs. 9. Avoid logging raw provider errors if responses could contain request details. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:225
Finding
Backup Guidance Includes Plaintext Credential Files in Archives<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:225-243`; related credential-path documentation at `RESILIENCE.md:10-11, 68` **Vulnerability Type**: Insecure storage and backup of secrets **Risk Level**: Medium ### Vulnerable Documentation ```markdown ## Backup and Recovery ### Create Backup ```bash ./scripts/backup-brainx.sh ~/backups ``` Creates `brainx-v5_backup_YYYYMMDD_HHMMSS.tar.gz` containing: - Full PostgreSQL database (SQL dump) - OpenClaw configuration (hooks, .env) - Skill files - Workspace documentation ``` ```markdown | Component | Location | Risk | Impact | | **Environment Vars** | `~/.openclaw/.env` | MEDIUM | CRITICAL - DB/OpenAI credentials | ``` ### Technical Analysis The documented backup scope explicitly includes `.env` files containing database and OpenAI credentials. A `.tar.gz` archive provides compression, not encryption or authentication. Combining database contents, workspace documentation, configuration, and credentials in one archive increases the consequences of backup disclosure. Backups are also commonly copied to shared storage, cloud synchronization services, or less protected retention locations. The backup implementation referenced by the documentation is absent from the supplied project artifact. File permissions, encryption, exclusion rules, and cloud-transfer behavior therefore could not be verified. The confirmed issue is the insecure documented backup design rather than a verified flaw in an available script. ### Attack Path 1. An administrator follows the documented backup procedure. 2. The procedure includes `.env` files in the generated archive. 3. The archive is stored under a backup directory or copied to remote storage. 4. Another local user, compromised process, exposed storage bucket, or stolen backup obtains the archive. 5. The attacker extracts the unencrypted `.env` file. 6. The attacker uses the recovered database and OpenAI credentials. ### Impact Assessment Compromise of the b ...[truncated 441 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Exclude `.env` and other credential files from backups by default. 2. Back up secret-manager references rather than secret values. 3. If secret backup is operationally required, use authenticated encryption with keys stored separately from the archive. 4. Create archives with owner-only permissions and verify the effective process umask. 5. Separate database, workspace, configuration, and secret backups into different protection domains. 6. Document retention, deletion, key rotation, and recovery procedures. 7. Rotate database and API credentials after restoring onto a new host. 8. Prevent accidental synchronization to public or broadly shared cloud storage. 9. Add automated tests that inspect archive manifests and fail when plaintext secret files are included. 10. Provide a safe default command and require an explicit high-friction option to include encrypted secrets. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (126)

Missing User Warnings

High
Confidence
98% confidence
Finding
The README normalizes broad automated collection, storage, and sharing of sensitive session data, including personal and financial information, without a prominent privacy warning or meaningful consent boundary. Users and operators may not understand that full transcripts are mined and reused across agents, increasing the likelihood of silent overcollection and disclosure.

Ssd 3

High
Confidence
99% confidence
Finding
The README explicitly states that the LLM distiller reads full session transcripts and extracts personal, technical, and financial data into persistent memory. Combined with automatic sharing and injection, this creates a high-risk pipeline for retaining and redistributing sensitive information far beyond the immediate session where it was provided.

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
Automatically writing permanent behavioral rules into AGENTS.md, TOOLS.md, and SOUL.md without human review is a strong persistence mechanism. Because future agents read those files at startup, any bad promotion can continuously steer behavior, amplify prompt injection, or institutionalize incorrect or unsafe operational practices.

Credential Access

High
Category
Privilege Escalation
Content
pnpm install  # or npm install

# 3. Configure environment
cp .env.example .env
# Edit: DATABASE_URL, OPENAI_API_KEY

# 4. Database setup (requires PostgreSQL with pgvector)
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Ssd 3

High
Confidence
98% confidence
Finding
The documentation explicitly frames personal, financial, contact, and health information as reusable facts for future agents to use without asking again. That encourages persistent storage and broad reuse of highly sensitive data, undermining confidentiality and user expectations across sessions and agents.

Ssd 3

High
Confidence
97% confidence
Finding
Automatic propagation and startup injection of memories derived from full transcripts creates persistent, repeated exposure of sensitive information. Because injected context is surfaced to agents at bootstrap, sensitive details can be needlessly replicated into prompts and become available to tools, logs, and downstream model providers.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
**Qué pasa:**
```bash
# El usuario ejecuta:
rm -rf ~/.openclaw
# o
openclaw reset --hard
```
Confidence
97% confidence
Finding
`rm -rf ~/.openclaw` is a classic parameter-abuse pattern because recursive forced deletion on a home-directory subtree can irreversibly remove application state and secrets. In this skill's context, that includes hooks, environment files, and operational configs required for recovery, making the guidance more dangerous than a generic example.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
**Qué pasa:**
```bash
# El usuario ejecuta:
rm -rf ~/.openclaw
# o
openclaw reset --hard
```
Confidence
97% confidence
Finding
`rm -rf ~/.openclaw` is a classic parameter-abuse pattern because recursive forced deletion on a home-directory subtree can irreversibly remove application state and secrets. In this skill's context, that includes hooks, environment files, and operational configs required for recovery, making the guidance more dangerous than a generic example.

Missing User Warnings

High
Confidence
98% confidence
Finding
The guide recommends syncing backups to cloud storage but elsewhere states the backup archive contains `openclaw.env`, database dumps, and potentially API keys and database credentials. Encouraging cloud replication without encryption or credential-handling warnings materially increases the risk of credential exposure and full data compromise if the remote storage is misconfigured or accessed by unauthorized parties.

Credential Access

High
Category
Privilege Escalation
Content
cat ~/.openclaw/workspace-clawma/BRAINX_CONTEXT.md

# 4. Verificar variables de entorno
grep -E "DATABASE_URL|OPENAI_API_KEY" ~/.openclaw/.env
```

### Restauración rápida (emergencia)
Confidence
97% confidence
Finding
The guide explicitly tells users to run `grep -E "DATABASE_URL|OPENAI_API_KEY" ~/.openclaw/.env`, which prints sensitive credentials to the terminal and likely shell logs, screenshots, session transcripts, or monitoring systems. In an LLM-agent environment, outputting secrets is especially dangerous because surrounding tooling may capture and persist command output automatically.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
The code does use vector-memory-related components: it queries relevant memories through a RAG/embedding search path and uses PostgreSQL-backed storage. However, the primary behavior of this chunk is not a generic memory engine that stores, searches, and injects contextual memories into prompts. Instead, it is a specific advisory subsystem that runs before agent tool actions, aggregates memories plus trajectories and patterns, formats human-readable warnings/advice, stores advisory events, and collects feedback. Those are materially different capabilities from the declared description, and key advertised features like auto-injection hooks and backup/recovery are not represented in this code chunk. Therefore this chunk does not accurately match the declared purpose.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The code substantially matches the core memory-engine description in that it provides CLI operations to add, search, and inject memories, and it interfaces with database and RAG components consistent with PostgreSQL/pgvector/OpenAI-based memory retrieval. However, the declared description omits significant additional capabilities exposed here: an advisory subsystem and an EIDOS prediction/evaluation/learning loop, both of which go beyond simple memory storage/search/injection. Also, two specifically declared features are not supported by this chunk: a full backup/recovery system and an auto-injection hook for OpenClaw are not visible here beyond reading an OPENCLAW_AGENT env var. Because the actual code exposes materially different and additional primary capabilities while missing notable declared ones in this chunk, this should be flagged as a mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The declared description presents the skill as a vector memory engine whose main functions are storing/searching memories, injecting context into prompts, and providing backup/recovery. The supplied code does not implement those core behaviors. Instead, it is a doctor/diagnostic command that audits database connectivity, pgvector installation, schema columns/constraints/indexes, data integrity, duplicate candidates, cron configuration, deployed hook presence, CLI presence, and backup freshness, then prints a report. While some checks relate to the described system components (pgvector, auto-injection hook, backups), the primary purpose of this code chunk is operational diagnostics and infrastructure validation, which is materially different from the declared core functionality.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared description centers on a vector memory engine for storing/searching memories and injecting them into prompts, plus auto-injection and backup/recovery. This code chunk does not implement memory search, prompt injection hooks, embeddings, pgvector operations, or backup/recovery. Instead, its primary purpose is a prediction→evaluation→learning workflow for agent self-improvement, backed by a separate brainx_eidos_cycles table. While it does call rag.storeMemory to save a distilled learning as a memory, that is only a secondary integration point and does not make the chunk a vector memory engine. Therefore the behavior is materially different from the declared purpose.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The declared description presents the skill as a vector memory engine focused on storing/searching/injecting memories and backup/recovery. The supplied code chunk does not implement memory storage, search, prompt injection, or backup/recovery. Instead, it is a maintenance/fix utility (`fix.js`) that performs database repair and housekeeping tasks and reads local filesystem state for migrations and cron configuration. While regenerating embeddings and deduplication are related to a memory engine, the primary purpose of this code is operational repair, not the declared core functionality. Therefore the description does not accurately represent this code chunk's behavior.

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding
The code clearly matches part of the description: it stores memories, creates embeddings, performs vector similarity search via pgvector, and uses PostgreSQL-backed persistence. However, the declared description includes additional major capabilities not evidenced here: there is no code that injects retrieved memories into LLM prompts, no OpenClaw hook/integration, and no backup or recovery functionality. Those are material declared features, not minor implementation details. Conversely, the code includes substantial behavior not mentioned in the description, notably PII scrubbing/redaction, semantic/pattern deduplication and merge behavior, lifecycle/provenance tracking, and query-event logging. The largest issue is that the description overstates the implemented capabilities in this chunk, so this should be flagged as a mismatch.

Missing User Warnings

High
Confidence
95% confidence
Finding
The backup/restore section omits strong warnings that backups may include sensitive configuration and that restore with `--force` can destructively replace existing state. Users could unintentionally leak secrets in archives or irreversibly overwrite valid environments and workspaces.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
```bash
# Check for advisories before a tool execution
./brainx-v5 advisory --tool exec --args '{"command":"rm -rf /tmp/old"}' --agent coder --json

# Quick check via helper script
./scripts/advisory-check.sh exec '{"command":"rm -rf /tmp/old"}' coder
Confidence
90% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
```bash
# Check for advisories before a tool execution
./brainx-v5 advisory --tool exec --args '{"command":"rm -rf /tmp/old"}' --agent coder --json

# Quick check via helper script
./scripts/advisory-check.sh exec '{"command":"rm -rf /tmp/old"}' coder
Confidence
90% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
```bash
# Check for advisories before a tool execution
./brainx-v5 advisory --tool exec --args '{"command":"rm -rf /tmp/old"}' --agent coder --json

# Quick check via helper script
./scripts/advisory-check.sh exec '{"command":"rm -rf /tmp/old"}' coder
Confidence
85% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
```bash
# Check for advisories before a tool execution
./brainx-v5 advisory --tool exec --args '{"command":"rm -rf /tmp/old"}' --agent coder --json

# Quick check via helper script
./scripts/advisory-check.sh exec '{"command":"rm -rf /tmp/old"}' coder
Confidence
85% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Ae1

High
Category
analysis-evasion
Content
| `child_process.execFile` | `hook/handler.js` | Invokes the BrainX CLI to query memories during agent bootstrap. No arbitrary command execution. |
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
| `child_process.execFile` | `hook/handler.js` | Invokes the BrainX CLI to query memories during agent bootstrap. No arbitrary command execution. |
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
| `process.env` access | `lib/db.js`, `lib/openai-rag.js`, `lib/cli.js` | Reads `DATABASE_URL` and `OPENAI_API_KEY` to connect to PostgreSQL and generate embedd
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
| `process.env` access | `lib/db.js`, `lib/openai-rag.js`, `lib/cli.js` | Reads `DATABASE_URL` and `OPENAI_API_KEY` to connect to PostgreSQL and generate embedd
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Static analysis

Detected: suspicious.env_credential_access

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
lib/embedding-client.js:8