LayerZeroFault
ai agents-api

Fix: ElizaOS AgentSkillsService 'SKILLS_AUTO_LOAD' Boolean Setting Bug

VV

Written by

Fact-Checked on September 11, 2026

Verified Expert

Fix: ElizaOS AgentSkillsService “SKILLS_AUTO_LOAD” Boolean Setting Bug

In autonomous AI agent architectures deployed on ElizaOS (formerly ai16z), configuring modular capabilities and safety boundaries is done through environment variables and character configuration files (character.json).

When deploying on-chain trading agents or automated DeFi node operators, administrators frequently disable dynamic external skill downloads by setting:

{
  "name": "DeFiSentinel",
  "settings": {
    "SKILLS_AUTO_LOAD": false,
    "CLAWHUB_AUTO_LOAD": false,
    "SKILLS_AUTO_REFRESH": true
  }
}

However, upon runtime startup, developers discover a critical flaw: the agent completely ignores the false setting. The agent connects to remote repositories (such as ClawHub), pulls third-party skill modules into local storage, and initializes unexpected action handlers:

[2026-09-11 11:42:01] [AgentSkillsService] Initializing skills subsystem...
[2026-09-11 11:42:02] [AgentSkillsService] AutoLoad active (SKILLS_AUTO_LOAD=false detected as enabled).
[2026-09-11 11:42:03] [ClawHub] Querying remote index for installed actions...
[2026-09-11 11:42:04] [AgentSkillsService] Warning: AutoRefresh daemon failed to start (expected string 'true').

Placeholder: ElizaOS AgentSkillsService Settings Coercion Bug Diagram


1. Code-Level Root Cause Analysis

The vulnerability resides within @elizaos/plugin-agent-skills/src/service.ts. In the AgentSkillsService constructor and initialization lifecycle, settings are read via runtime.getSetting(...):

// Vulnerable Implementation in @elizaos/plugin-agent-skills/src/service.ts
this.autoLoad = config?.autoLoad ??
  (runtime.getSetting("SKILLS_AUTO_LOAD") !== "false" &&
   runtime.getSetting("CLAWHUB_AUTO_LOAD") !== "false");

this.autoRefreshEnabled = config?.autoRefresh ??
  runtime.getSetting("SKILLS_AUTO_REFRESH") === "true";

The Type Incompatibility

In the ElizaOS core runtime, runtime.getSetting(key: string) is typed as:

$$\text{getSetting}: \text{string} \to \text{string} \mid \text{boolean} \mid \text{number} \mid \text{null}$$

When a setting is injected via .env, process environment variables arrive as strings ("false"). However, when settings are declared in character.json or provided dynamically via plugin configurations, modern JSON parsers supply native JavaScript primitives:

  • runtime.getSetting("SKILLS_AUTO_LOAD") returns false (boolean).
  • The expression evaluates: false !== "false".
  • Because the types differ (boolean vs string), the inequality evaluates to true.

As a consequence, setting SKILLS_AUTO_LOAD: false inadvertently enables autoloading.

Conversely, for SKILLS_AUTO_REFRESH:

  • runtime.getSetting("SKILLS_AUTO_REFRESH") returns true (boolean).
  • The expression evaluates: true === "true".
  • Because boolean !== string, the check evaluates to false, and the refresh daemon silently never runs.

(This exact type coercion flaw is also present in other ElizaOS modules; see our analysis on ElizaOS VisionService Boolean Env Setting Disabled Fix).


2. Security Implications for Web3 Agents

For crypto-native agents managing private keys, delegating transaction intents, or monitoring mempools, uncontrolled skill acquisition presents severe hazards:

  1. Supply Chain Hijacking: ClawHub or community registry compromises could lead an agent to load compromised tool definitions.
  2. Memory Poisoning: Dynamically loaded skills register prompt templates and action extractors that can alter transaction limits or gas thresholds.
  3. Bandwidth & Rate-Limit Spikes: Background polling of unregistered endpoints burns through API rate limits and network sockets.

Placeholder: Attack Vector Diagram of Unwanted Skill Injection via AutoLoad Defect


3. Remediation Protocols

Strategy 1: Immediate Front-End Patch (Character & Environment Config)

Until packages are updated upstream, force string literals in both .env and character.json.

In .env:

SKILLS_AUTO_LOAD="false"
CLAWHUB_AUTO_LOAD="false"
SKILLS_AUTO_REFRESH="true"

In character.json (explicit string quotes instead of booleans):

{
  "name": "DeFiSentinel",
  "settings": {
    "SKILLS_AUTO_LOAD": "false",
    "CLAWHUB_AUTO_LOAD": "false",
    "SKILLS_AUTO_REFRESH": "true"
  }
}

Strategy 2: Patching AgentSkillsService via Utility Normalization

If compiling ElizaOS from source or maintaining an internal monorepo, patch the loader with a universal boolean parser:

// utils/settingParser.ts
export function parseBooleanSetting(
  value: string | boolean | number | null | undefined,
  defaultValue: boolean = false
): boolean {
  if (value === undefined || value === null) {
    return defaultValue;
  }
  if (typeof value === 'boolean') {
    return value;
  }
  if (typeof value === 'string') {
    const normalized = value.trim().toLowerCase();
    if (normalized === 'true' || normalized === '1' || normalized === 'yes') {
      return true;
    }
    if (normalized === 'false' || normalized === '0' || normalized === 'no') {
      return false;
    }
  }
  if (typeof value === 'number') {
    return value !== 0;
  }
  return defaultValue;
}

Update packages/plugin-agent-skills/src/service.ts:

import { parseBooleanSetting } from './utils/settingParser';

// Safe initialization
const skillsAutoLoad = parseBooleanSetting(
  runtime.getSetting("SKILLS_AUTO_LOAD"),
  true // Default if not specified
);

const clawHubAutoLoad = parseBooleanSetting(
  runtime.getSetting("CLAWHUB_AUTO_LOAD"),
  true // Default if not specified
);

this.autoLoad = config?.autoLoad ?? (skillsAutoLoad && clawHubAutoLoad);

this.autoRefreshEnabled = config?.autoRefresh ?? parseBooleanSetting(
  runtime.getSetting("SKILLS_AUTO_REFRESH"),
  false
);

Strategy 3: Hardened Runtime Wrapper (Plugin Defense-in-Depth)

For production deployments where you cannot alter @elizaos/plugin-agent-skills directly, intercept settings in your agent’s bootstrap file:

import { IAgentRuntime, Character } from '@elizaos/core';

export function sanitizeCharacterSettings(character: Character): Character {
  const sanitized = { ...character };
  if (!sanitized.settings) return sanitized;

  const targetBooleanKeys = [
    'SKILLS_AUTO_LOAD',
    'CLAWHUB_AUTO_LOAD',
    'SKILLS_AUTO_REFRESH',
    'ENABLE_OBJECT_DETECTION',
    'ENABLE_POSE_DETECTION'
  ];

  for (const key of targetBooleanKeys) {
    if (typeof sanitized.settings[key] === 'boolean') {
      // Coerce to string representation to appease strict string comparisons
      sanitized.settings[key] = String(sanitized.settings[key]);
    }
  }

  return sanitized;
}

Placeholder: Code Patch Comparison Showing Type-Safe Boolean Coercion


4. Operational Verification Checklist

To confirm that your ElizaOS node is properly protected against unwanted skill loads:

  1. Inspect Agent Startup Logs: Verify that no [ClawHub] Querying remote index messages appear during initialization.
  2. Audit Action Registry: Print runtime.actions.map(a => a.name) upon startup to ensure only your explicitly whitelisted plugins are registered.
  3. Verify Local Cache Directory: Ensure the .skills or clawhub_cache folder in the agent’s root directory remains empty.
Partner Spotlight: Gate.io

Trade Securely on Gate.io

Don't risk your assets on centralized silos or unverified endpoints. Trade securely on Gate.io with deep liquidity and institutional-grade security protocols.

Claim $100 Sign-up Bonus

Official Partner Referral Link

Related Inquiries

Why does ElizaOS continue autoloading skills when SKILLS_AUTO_LOAD is set to false?

In ElizaOS v2 / ai16z (@elizaos/plugin-agent-skills), AgentSkillsService evaluates settings using strict string comparisons: runtime.getSetting('SKILLS_AUTO_LOAD') !== 'false'. In character JSON files, boolean false is parsed as a JavaScript boolean primitive (false), not a string. Because false !== 'false' evaluates to true in JavaScript, the service interprets the flag as enabled and continues fetching skills from ClawHub.

Why does SKILLS_AUTO_REFRESH fail to activate when set to true?

Similarly, auto-refresh checks runtime.getSetting('SKILLS_AUTO_REFRESH') === 'true'. When passed as a boolean true from character settings, the strict equality operator evaluates true === 'true' as false. As a result, the auto-refresh daemon never starts unless the setting is explicitly wrapped as a string literal ('true').

What security risks are associated with unauthorized ClawHub skill autoloading?

Autonomous Web3 agents managing hot wallets or interacting with on-chain protocols rely on deterministic capabilities. If an agent unintentionally connects to ClawHub or external repositories to fetch unvetted community skills, it introduces supply-chain vulnerabilities, API key leaks, or prompt-injection attack vectors into the agent's runtime memory.