openclaw - 💡(How to fix) Fix bootstrap-extra-files: user-configured paths silently dropped by VALID_BOOTSTRAP_NAMES whitelist

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

The bootstrap-extra-files internal hook silently drops any user-configured path whose basename is not in a hardcoded 8-name whitelist (VALID_BOOTSTRAP_NAMES), even when the user has explicitly opted in by listing the path in hooks.internal.entries.bootstrap-extra-files.paths. Absolute paths outside the agent workspace are additionally rejected by a workspace-root boundary check.

The whitelist was clearly intended to guard default workspace auto-discovery (so the runtime doesn't accidentally inject random .md files from a workspace). It is incorrectly applied to explicit user config, which should be a higher trust signal.

Error Message

detail: err instanceof Error ? err.message : String(err) }); Surface dropped-path diagnostics at agent bootstrap time, not just in the returned diagnostics object. A console.warn (or doctor warning) when bootstrap-extra-files drops user-configured paths would have caught this immediately instead of letting it go silent for weeks.

Root Cause

The bootstrap-extra-files internal hook silently drops any user-configured path whose basename is not in a hardcoded 8-name whitelist (VALID_BOOTSTRAP_NAMES), even when the user has explicitly opted in by listing the path in hooks.internal.entries.bootstrap-extra-files.paths. Absolute paths outside the agent workspace are additionally rejected by a workspace-root boundary check.

The whitelist was clearly intended to guard default workspace auto-discovery (so the runtime doesn't accidentally inject random .md files from a workspace). It is incorrectly applied to explicit user config, which should be a higher trust signal.

Fix Action

Fix / Workaround

Suggested patch shape (drop-in to loadExtraBootstrapFilesWithDiagnostics):

Verified working in our deployment (live patch + watchdog).

Happy to open a PR if useful. Patch is currently shipping at one of our four agents and has been live-verified.

Code Example

{
  "hooks": {
    "internal": {
      "entries": {
        "bootstrap-extra-files": {
          "paths": [
            "memory/MEMORY.md",
            "memory/PERMANENT.md",
            "/Users/me/shared/STATE.md"
          ]
        }
      }
    }
  }
}

---

import * as W from '/opt/homebrew/lib/node_modules/openclaw/dist/workspace-CrmSbLX9.js';
const loadExtraBootstrapFilesWithDiagnostics = W.m;
const r = await loadExtraBootstrapFilesWithDiagnostics('/path/to/workspace', [
  'memory/MEMORY.md',
  'memory/PERMANENT.md',
]);
console.log(`loaded=${r.files.length}/2 skipped=${r.diagnostics.length}`);
console.log(r.diagnostics);
// loaded=1/2 skipped=1
// [{ path: '.../memory/PERMANENT.md', reason: 'invalid-bootstrap-filename',
//    detail: 'unsupported bootstrap basename: PERMANENT.md' }]

---

for (const relPath of resolvedPaths) {
  const filePath = path.resolve(resolvedDir, relPath);
  const baseName = path.basename(relPath);
  // No basename whitelist for user-configured paths — explicit opt-in.

  if (path.isAbsolute(relPath)) {
    // Absolute paths: read directly, enforce size cap, skip workspace boundary.
    try {
      const stat = await fs.promises.stat(filePath);
      if (stat.size > MAX_WORKSPACE_BOOTSTRAP_FILE_BYTES) {
        diagnostics.push({ path: filePath, reason: "security",
          detail: `file too large (${stat.size} > ${MAX_WORKSPACE_BOOTSTRAP_FILE_BYTES})` });
        continue;
      }
      const content = await fs.promises.readFile(filePath, "utf-8");
      files.push({ name: baseName, path: filePath, content, missing: false });
    } catch (err) {
      const code = err && typeof err === "object" && "code" in err ? err.code : null;
      diagnostics.push({ path: filePath,
        reason: code === "ENOENT" ? "missing" : "io",
        detail: err instanceof Error ? err.message : String(err) });
    }
    continue;
  }

  // Relative paths still go through workspace-bounded read.
  const loaded = await readWorkspaceFileWithGuards({ filePath, workspaceDir: resolvedDir });
  // ... existing handling
}
RAW_BUFFERClick to expand / collapse

Bug: user-configured bootstrap-extra-files.paths silently dropped by VALID_BOOTSTRAP_NAMES whitelist

Summary

The bootstrap-extra-files internal hook silently drops any user-configured path whose basename is not in a hardcoded 8-name whitelist (VALID_BOOTSTRAP_NAMES), even when the user has explicitly opted in by listing the path in hooks.internal.entries.bootstrap-extra-files.paths. Absolute paths outside the agent workspace are additionally rejected by a workspace-root boundary check.

The whitelist was clearly intended to guard default workspace auto-discovery (so the runtime doesn't accidentally inject random .md files from a workspace). It is incorrectly applied to explicit user config, which should be a higher trust signal.

Affected version

OpenClaw 2026.5.4 (325df3e) and prior.

Repro

Config snippet (~/.openclaw/openclaw.json):

{
  "hooks": {
    "internal": {
      "entries": {
        "bootstrap-extra-files": {
          "paths": [
            "memory/MEMORY.md",
            "memory/PERMANENT.md",
            "/Users/me/shared/STATE.md"
          ]
        }
      }
    }
  }
}

Result on next agent bootstrap:

pathloaded?reason if dropped
memory/MEMORY.mdbasename MEMORY.md is in whitelist
memory/PERMANENT.md❌ silently droppedinvalid-bootstrap-filename: PERMANENT.md
/Users/me/shared/STATE.md❌ silently droppedinvalid-bootstrap-filename: STATE.md (whitelist) + workspace boundary fail

The diagnostics object correctly records the reason, but nothing surfaces it to the user — the agent just bootstraps with missing context.

Self-contained Node repro against the bundled runtime:

import * as W from '/opt/homebrew/lib/node_modules/openclaw/dist/workspace-CrmSbLX9.js';
const loadExtraBootstrapFilesWithDiagnostics = W.m;
const r = await loadExtraBootstrapFilesWithDiagnostics('/path/to/workspace', [
  'memory/MEMORY.md',
  'memory/PERMANENT.md',
]);
console.log(`loaded=${r.files.length}/2 skipped=${r.diagnostics.length}`);
console.log(r.diagnostics);
// loaded=1/2 skipped=1
// [{ path: '.../memory/PERMANENT.md', reason: 'invalid-bootstrap-filename',
//    detail: 'unsupported bootstrap basename: PERMANENT.md' }]

Source location

dist/workspace-CrmSbLX9.js (content-hashed filename, your build may differ):

  • VALID_BOOTSTRAP_NAMES = 8-name Set defined around line 143–152
  • loadExtraBootstrapFilesWithDiagnostics defined around line 505
  • Basename check at line ~523
  • File read via readWorkspaceFileWithGuards at line ~535 (which applies the workspace-root boundary check)

Impact

In our deployment, this caused 4 out of 5 explicitly configured bootstrap-extra-files to silently drop across 4 agents for ~6 weeks before someone noticed agents were operating with stale context. Symptoms looked like memory regression (agents "forgetting" things) — actual cause was their context never landing.

Proposed fix

User-configured paths under bootstrap-extra-files.paths should be treated as explicit opt-in and bypass the basename whitelist. Two cleanly separable behaviors:

  1. Basename whitelist — keep for default workspace auto-discovery (the existing safety net). Drop for explicit user config.
  2. Workspace-root boundary — keep for relative paths (which resolve inside the workspace). For absolute paths in user config, accept them outside the workspace root (still enforcing MAX_WORKSPACE_BOOTSTRAP_FILE_BYTES).

Suggested patch shape (drop-in to loadExtraBootstrapFilesWithDiagnostics):

for (const relPath of resolvedPaths) {
  const filePath = path.resolve(resolvedDir, relPath);
  const baseName = path.basename(relPath);
  // No basename whitelist for user-configured paths — explicit opt-in.

  if (path.isAbsolute(relPath)) {
    // Absolute paths: read directly, enforce size cap, skip workspace boundary.
    try {
      const stat = await fs.promises.stat(filePath);
      if (stat.size > MAX_WORKSPACE_BOOTSTRAP_FILE_BYTES) {
        diagnostics.push({ path: filePath, reason: "security",
          detail: `file too large (${stat.size} > ${MAX_WORKSPACE_BOOTSTRAP_FILE_BYTES})` });
        continue;
      }
      const content = await fs.promises.readFile(filePath, "utf-8");
      files.push({ name: baseName, path: filePath, content, missing: false });
    } catch (err) {
      const code = err && typeof err === "object" && "code" in err ? err.code : null;
      diagnostics.push({ path: filePath,
        reason: code === "ENOENT" ? "missing" : "io",
        detail: err instanceof Error ? err.message : String(err) });
    }
    continue;
  }

  // Relative paths still go through workspace-bounded read.
  const loaded = await readWorkspaceFileWithGuards({ filePath, workspaceDir: resolvedDir });
  // ... existing handling
}

Verified working in our deployment (live patch + watchdog).

Optional secondary improvement

Surface dropped-path diagnostics at agent bootstrap time, not just in the returned diagnostics object. A console.warn (or doctor warning) when bootstrap-extra-files drops user-configured paths would have caught this immediately instead of letting it go silent for weeks.

Happy to open a PR if useful. Patch is currently shipping at one of our four agents and has been live-verified.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix bootstrap-extra-files: user-configured paths silently dropped by VALID_BOOTSTRAP_NAMES whitelist