VYPR
Medium severity6.5NVD Advisory· Published Apr 28, 2026· Updated Apr 30, 2026

CVE-2026-41388

CVE-2026-41388

Description

OpenClaw before 2026.3.31 contains a configuration management vulnerability where startup migration treats empty-array settings as missing values. Attackers can restart the application to rehydrate revoked Tlon configuration from file state, bypassing intended revocation controls.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
openclawnpm
< 2026.3.312026.3.31

Affected products

1
  • cpe:2.3:a:openclaw:openclaw:*:*:*:*:*:node.js:*:*
    Range: <2026.3.31

Patches

1
a4d72a83f01f

fix(tlon): preserve explicit empty settings during migration (#58370)

https://github.com/openclaw/openclawJacob TomlinsonMar 31, 2026via ghsa
3 files changed · +65 8
  • extensions/tlon/src/monitor/index.ts+2 7 modified
    @@ -27,6 +27,7 @@ import {
       applyTlonSettingsOverrides,
       buildTlonSettingsMigrations,
       mergeUniqueStrings,
    +  shouldMigrateTlonSetting,
     } from "./settings-helpers.js";
     import {
       extractMessageText,
    @@ -180,13 +181,7 @@ export async function monitorTlonProvider(opts: MonitorTlonOpts = {}): Promise<v
         const migrations = buildTlonSettingsMigrations(account, currentSettings);
     
         for (const { key, fileValue, settingsValue } of migrations) {
    -      // Only migrate if file has a value and settings store doesn't
    -      const hasFileValue = Array.isArray(fileValue) ? fileValue.length > 0 : fileValue != null;
    -      const hasSettingsValue = Array.isArray(settingsValue)
    -        ? settingsValue.length > 0
    -        : settingsValue != null;
    -
    -      if (hasFileValue && !hasSettingsValue) {
    +      if (shouldMigrateTlonSetting(fileValue, settingsValue)) {
             try {
               await api!.poke({
                 app: "settings",
    
  • extensions/tlon/src/monitor/settings-helpers.test.ts+57 1 modified
    @@ -1,6 +1,10 @@
     import { describe, expect, it } from "vitest";
     import type { TlonResolvedAccount } from "../types.js";
    -import { applyTlonSettingsOverrides } from "./settings-helpers.js";
    +import {
    +  applyTlonSettingsOverrides,
    +  buildTlonSettingsMigrations,
    +  shouldMigrateTlonSetting,
    +} from "./settings-helpers.js";
     
     const baseAccount: TlonResolvedAccount = {
       accountId: "default",
    @@ -22,6 +26,58 @@ const baseAccount: TlonResolvedAccount = {
       ownerShip: "~marzod",
     };
     
    +describe("shouldMigrateTlonSetting", () => {
    +  it("does not rehydrate explicit empty-array revocations during startup migration", () => {
    +    const migrations = buildTlonSettingsMigrations(baseAccount, {
    +      dmAllowlist: [],
    +      groupInviteAllowlist: [],
    +      defaultAuthorizedShips: [],
    +    });
    +
    +    expect(
    +      Object.fromEntries(
    +        migrations
    +          .filter((migration) =>
    +            ["dmAllowlist", "groupInviteAllowlist", "defaultAuthorizedShips"].includes(
    +              migration.key,
    +            ),
    +          )
    +          .map((migration) => [
    +            migration.key,
    +            shouldMigrateTlonSetting(migration.fileValue, migration.settingsValue),
    +          ]),
    +      ),
    +    ).toEqual({
    +      dmAllowlist: false,
    +      groupInviteAllowlist: false,
    +      defaultAuthorizedShips: false,
    +    });
    +  });
    +
    +  it("still seeds file-config allowlists on first run when settings are missing", () => {
    +    const migrations = buildTlonSettingsMigrations(baseAccount, {});
    +
    +    expect(
    +      Object.fromEntries(
    +        migrations
    +          .filter((migration) =>
    +            ["dmAllowlist", "groupInviteAllowlist", "defaultAuthorizedShips"].includes(
    +              migration.key,
    +            ),
    +          )
    +          .map((migration) => [
    +            migration.key,
    +            shouldMigrateTlonSetting(migration.fileValue, migration.settingsValue),
    +          ]),
    +      ),
    +    ).toEqual({
    +      dmAllowlist: true,
    +      groupInviteAllowlist: true,
    +      defaultAuthorizedShips: true,
    +    });
    +  });
    +});
    +
     describe("applyTlonSettingsOverrides", () => {
       it("treats explicit empty settings allowlists as authoritative deny-all", () => {
         const result = applyTlonSettingsOverrides({
    
  • extensions/tlon/src/monitor/settings-helpers.ts+6 0 modified
    @@ -62,6 +62,12 @@ export function buildTlonSettingsMigrations(
       ];
     }
     
    +export function shouldMigrateTlonSetting(fileValue: unknown, settingsValue: unknown): boolean {
    +  const hasFileValue = Array.isArray(fileValue) ? fileValue.length > 0 : fileValue != null;
    +  const hasSettingsValue = settingsValue != null;
    +  return hasFileValue && !hasSettingsValue;
    +}
    +
     export function applyTlonSettingsOverrides(params: {
       account: TlonResolvedAccount;
       currentSettings: TlonSettingsStore;
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.