VYPR
High severityNVD Advisory· Published Mar 5, 2026· Updated Mar 10, 2026

OpenClaw 2026.1.29 < 2026.2.1 - Authorization Bypass in Twitch Plugin allowFrom Access Control

CVE-2026-28448

Description

OpenClaw versions 2026.1.29 prior to 2026.2.1 contain a vulnerability in the Twitch plugin (must be installed and enabled) in which it fails to enforce the allowFrom allowlist when allowedRoles is unset or empty, allowing unauthorized Twitch users to trigger agent dispatch. Remote attackers can mention the bot in Twitch chat to bypass access control and invoke the agent pipeline, potentially causing unintended actions or resource exhaustion.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
openclawnpm
>= 2026.1.29, < 2026.2.12026.2.1

Affected products

1

Patches

1
8c7901c98486

fix(twitch): enforce allowFrom allowlist

https://github.com/openclaw/openclawPeter SteinbergerFeb 2, 2026via ghsa
4 files changed · +24 16
  • CHANGELOG.md+1 0 modified
    @@ -31,6 +31,7 @@ Docs: https://docs.openclaw.ai
     - fix(lobster): block arbitrary exec via lobsterPath/cwd injection (GHSA-4mhr-g7xj-cg8j). (#5335) Thanks @vignesh07.
     - Security: block LD_/DYLD_ env overrides for host exec. (#4896) Thanks @HassanFleyah.
     - Security: harden web tool content wrapping + file parsing safeguards. (#4058) Thanks @VACInc.
    +- Security: enforce Twitch `allowFrom` allowlist gating (deny non-allowlisted senders). Thanks @MegaManSec.
     
     ## 2026.1.30
     
    
  • docs/channels/twitch.md+7 5 modified
    @@ -112,12 +112,13 @@ If both env and config are set, config takes precedence.
       channels: {
         twitch: {
           allowFrom: ["123456789"], // (recommended) Your Twitch user ID only
    -      allowedRoles: ["moderator"], // Or restrict to roles
         },
       },
     }
     ```
     
    +Prefer `allowFrom` for a hard allowlist. Use `allowedRoles` instead if you want role-based access.
    +
     **Available roles:** `"moderator"`, `"owner"`, `"vip"`, `"subscriber"`, `"all"`.
     
     **Why user IDs?** Usernames can change, allowing impersonation. User IDs are permanent.
    @@ -208,17 +209,17 @@ Example (one bot account in two channels):
     }
     ```
     
    -### Combined allowlist + roles
    +### Role-based access (alternative)
     
    -Users in `allowFrom` bypass role checks:
    +`allowFrom` is a hard allowlist. When set, only those user IDs are allowed.
    +If you want role-based access, leave `allowFrom` unset and configure `allowedRoles` instead:
     
     ```json5
     {
       channels: {
         twitch: {
           accounts: {
             default: {
    -          allowFrom: ["123456789"],
               allowedRoles: ["moderator"],
             },
           },
    @@ -256,7 +257,8 @@ openclaw channels status --probe
     
     ### Bot doesn't respond to messages
     
    -**Check access control:** Temporarily set `allowedRoles: ["all"]` to test.
    +**Check access control:** Ensure your user ID is in `allowFrom`, or temporarily remove
    +`allowFrom` and set `allowedRoles: ["all"]` to test.
     
     **Check the bot is in the channel:** The bot must join the channel specified in `channel`.
     
    
  • extensions/twitch/src/access-control.test.ts+8 8 modified
    @@ -135,7 +135,7 @@ describe("checkTwitchAccessControl", () => {
           expect(result.matchSource).toBe("allowlist");
         });
     
    -    it("allows users not in allowlist via fallback (open access)", () => {
    +    it("blocks users not in allowlist when allowFrom is set", () => {
           const account: TwitchAccountConfig = {
             ...mockAccount,
             allowFrom: ["789012"],
    @@ -150,8 +150,8 @@ describe("checkTwitchAccessControl", () => {
             account,
             botUsername: "testbot",
           });
    -      // Falls through to final fallback since allowedRoles is not set
    -      expect(result.allowed).toBe(true);
    +      expect(result.allowed).toBe(false);
    +      expect(result.reason).toContain("allowFrom");
         });
     
         it("blocks messages without userId", () => {
    @@ -194,7 +194,7 @@ describe("checkTwitchAccessControl", () => {
           expect(result.allowed).toBe(true);
         });
     
    -    it("allows user with role even if not in allowlist", () => {
    +    it("blocks user with role when not in allowlist", () => {
           const account: TwitchAccountConfig = {
             ...mockAccount,
             allowFrom: ["789012"],
    @@ -212,11 +212,11 @@ describe("checkTwitchAccessControl", () => {
             account,
             botUsername: "testbot",
           });
    -      expect(result.allowed).toBe(true);
    -      expect(result.matchSource).toBe("role");
    +      expect(result.allowed).toBe(false);
    +      expect(result.reason).toContain("allowFrom");
         });
     
    -    it("blocks user with neither allowlist nor role", () => {
    +    it("blocks user not in allowlist even when roles configured", () => {
           const account: TwitchAccountConfig = {
             ...mockAccount,
             allowFrom: ["789012"],
    @@ -235,7 +235,7 @@ describe("checkTwitchAccessControl", () => {
             botUsername: "testbot",
           });
           expect(result.allowed).toBe(false);
    -      expect(result.reason).toContain("does not have any of the required roles");
    +      expect(result.reason).toContain("allowFrom");
         });
       });
     
    
  • extensions/twitch/src/access-control.ts+8 3 modified
    @@ -19,10 +19,10 @@ export type TwitchAccessControlResult = {
      * Priority order:
      * 1. If `requireMention` is true, message must mention the bot
      * 2. If `allowFrom` is set, sender must be in the allowlist (by user ID)
    - * 3. If `allowedRoles` is set, sender must have at least one of the specified roles
    + * 3. If `allowedRoles` is set (and `allowFrom` is not), sender must have at least one role
      *
    - * Note: You can combine `allowFrom` with `allowedRoles`. If a user is in `allowFrom`,
    - * they bypass role checks. This is useful for allowing specific users regardless of role.
    + * Note: `allowFrom` is a hard allowlist. When set, only those user IDs are allowed.
    + * Use `allowedRoles` as an alternative when you don't want to maintain an allowlist.
      *
      * Available roles:
      * - "moderator": Moderators
    @@ -66,6 +66,11 @@ export function checkTwitchAccessControl(params: {
             matchSource: "allowlist",
           };
         }
    +
    +    return {
    +      allowed: false,
    +      reason: "sender is not in allowFrom allowlist",
    +    };
       }
     
       if (account.allowedRoles && account.allowedRoles.length > 0) {
    

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

6

News mentions

0

No linked articles in our index yet.