openclaw - ✅(Solved) Fix [Bug]: Mattermost interaction token forgeable via hardcoded HMAC derivation key [1 pull requests, 1 participants]

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…
GitHub stats
openclaw/openclaw#64545Fetched 2026-04-11 06:14:29
View on GitHub
Comments
0
Participants
1
Timeline
1
Reactions
0
Author
Participants
Timeline (top)
cross-referenced ×1

Fix Action

Fix / Workaround

Technical Reproduction

  1. Obtain the Mattermost bot token (available via the Mattermost admin panel, gateway environment variables, or any configuration leak).
  2. Reproduce the derivation: derivedSecret = HMAC-SHA256("openclaw-mattermost-interactions", botToken) — this is deterministic and requires no further gateway access.
  3. Construct an action context matching an existing interactive post, e.g., {"action_id": "approve", "post_id": "<target_post_id>", "channel_id": "<target_channel_id>"}.
  4. Compute the forged token: _token = HMAC-SHA256(derivedSecret, JSON.stringify(sortedContext)).
  5. POST a crafted payload to http://<gateway-host>:<gatewayPort>/mattermost/interactions/<accountId> with the forged _token field.
  6. verifyInteractionToken at interactions.ts:165-175 passes; the handler dispatches core.system.enqueueSystemEvent to the agent as if a legitimate user clicked an approved button.

A successful forged request triggers core.system.enqueueSystemEvent (traced from monitor.ts:~448), dispatching agent system events — approvals, confirmations, or other action-gated commands associated with the original interactive message — entirely under attacker control. The /mattermost/interactions/<accountId> endpoint uses auth: "plugin" (confirmed in monitor.ts:479-482 and src/plugins/registry.ts), meaning no gateway-layer authentication sits in front of this route; the HMAC _token is the complete and sole access control.

PR fix notes

PR #64546: fix: Mattermost interaction token forgeable via hardcoded HMAC...

Description (problem / solution / changelog)

Fix Summary

The deriveInteractionSecret function in the Mattermost extension uses a hardcoded public string as the HMAC key, making the interaction signing secret fully reproducible by anyone who knows the bot token. An attacker who obtains the bot token can forge valid _token values, craft arbitrary button-click POST requests to the gateway's interaction endpoint, and trigger agent system events (core.system.enqueueSystemEvent) as if a legitimate user clicked an approved Mattermost button.

Issue Linkage

Fixes #64545

Security Snapshot

  • CVSS v3.1: 7.1 (High)
  • CVSS v4.0: 7.1 (High)

Implementation Details

Files Changed

  • extensions/mattermost/src/config-schema-core.ts (+1/-0)
  • extensions/mattermost/src/config-schema.test.ts (+19/-0)
  • extensions/mattermost/src/mattermost/accounts.test.ts (+23/-0)
  • extensions/mattermost/src/mattermost/accounts.ts (+8/-0)
  • extensions/mattermost/src/mattermost/interactions.test.ts (+20/-17)
  • extensions/mattermost/src/mattermost/interactions.ts (+23/-10)
  • extensions/mattermost/src/mattermost/monitor.ts (+2/-3)
  • extensions/mattermost/src/mattermost/send.ts (+8/-2)
  • extensions/mattermost/src/types.ts (+2/-0)

Technical Analysis

  1. Obtain the Mattermost bot token (available via the Mattermost admin panel, gateway environment variables, or any configuration leak).
  2. Reproduce the derivation: derivedSecret = HMAC-SHA256("openclaw-mattermost-interactions", botToken) — this is deterministic and requires no further gateway access.
  3. Construct an action context matching an existing interactive post, e.g., {"action_id": "approve", "post_id": "<target_post_id>", "channel_id": "<target_channel_id>"}.
  4. Compute the forged token: _token = HMAC-SHA256(derivedSecret, JSON.stringify(sortedContext)).
  5. POST a crafted payload to http://<gateway-host>:<gatewayPort>/mattermost/interactions/<accountId> with the forged _token field.
  6. verifyInteractionToken at interactions.ts:165-175 passes; the handler dispatches core.system.enqueueSystemEvent to the agent as if a legitimate user clicked an approved button.

Validation Evidence

  • Command: pnpm exec oxlint src/ && pnpm build && pnpm check && pnpm test
  • Status: passed (with pre-existing baseline failures)

Risk and Compatibility

  • non-breaking; no known regression impact

AI-Assisted Disclosure

  • AI-assisted: yes
  • Model: github-copilot/claude-sonnet-4.6

Changed files

  • extensions/mattermost/src/config-schema-core.ts (modified, +1/-0)
  • extensions/mattermost/src/config-schema.test.ts (modified, +19/-0)
  • extensions/mattermost/src/mattermost/accounts.test.ts (modified, +23/-0)
  • extensions/mattermost/src/mattermost/accounts.ts (modified, +8/-0)
  • extensions/mattermost/src/mattermost/interactions.test.ts (modified, +20/-17)
  • extensions/mattermost/src/mattermost/interactions.ts (modified, +23/-10)
  • extensions/mattermost/src/mattermost/monitor.ts (modified, +2/-3)
  • extensions/mattermost/src/mattermost/send.ts (modified, +8/-2)
  • extensions/mattermost/src/types.ts (modified, +2/-0)

Code Example

function deriveInteractionSecret(botToken: string): string {
  return createHmac("sha256", "openclaw-mattermost-interactions").update(botToken).digest("hex");
}

---

export function generateInteractionToken(
  context: Record<string, unknown>,
  accountId?: string,
): string {
  const secret = getInteractionSecret(accountId);
  const payload = JSON.stringify(context, Object.keys(context).sort());
  return createHmac("sha256", secret).update(payload).digest("hex");
}
RAW_BUFFERClick to expand / collapse

Severity Assessment

CVSS Assessment

Metricv3.1v4.0
Score7.1 / 10.07.1 / 10.0
SeverityHighHigh
VectorCVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:L/I:H/A:NCVSS:4.0/AV:N/AC:H/AT:N/PR:L/UI:N/VC:L/VI:H/VA:N/SC:L/SI:H/SA:N
CalculatorCVSS v3.1 CalculatorCVSS v4.0 Calculator

Threat Model Alignment

Classification: security-specific

Impact

The deriveInteractionSecret function in the Mattermost extension uses a hardcoded public string as the HMAC key, making the interaction signing secret fully reproducible by anyone who knows the bot token. An attacker who obtains the bot token can forge valid _token values, craft arbitrary button-click POST requests to the gateway's interaction endpoint, and trigger agent system events (core.system.enqueueSystemEvent) as if a legitimate user clicked an approved Mattermost button.

Affected Component

File: extensions/mattermost/src/mattermost/interactions.ts:122-124

function deriveInteractionSecret(botToken: string): string {
  return createHmac("sha256", "openclaw-mattermost-interactions").update(botToken).digest("hex");
}

The derived secret is then used to sign and verify all button-click interaction tokens at interactions.ts:155-175:

export function generateInteractionToken(
  context: Record<string, unknown>,
  accountId?: string,
): string {
  const secret = getInteractionSecret(accountId);
  const payload = JSON.stringify(context, Object.keys(context).sort());
  return createHmac("sha256", secret).update(payload).digest("hex");
}

The endpoint is registered at monitor.ts:479-482 with auth: "plugin", making this HMAC check the sole access control for the route.

Technical Reproduction

  1. Obtain the Mattermost bot token (available via the Mattermost admin panel, gateway environment variables, or any configuration leak).
  2. Reproduce the derivation: derivedSecret = HMAC-SHA256("openclaw-mattermost-interactions", botToken) — this is deterministic and requires no further gateway access.
  3. Construct an action context matching an existing interactive post, e.g., {"action_id": "approve", "post_id": "<target_post_id>", "channel_id": "<target_channel_id>"}.
  4. Compute the forged token: _token = HMAC-SHA256(derivedSecret, JSON.stringify(sortedContext)).
  5. POST a crafted payload to http://<gateway-host>:<gatewayPort>/mattermost/interactions/<accountId> with the forged _token field.
  6. verifyInteractionToken at interactions.ts:165-175 passes; the handler dispatches core.system.enqueueSystemEvent to the agent as if a legitimate user clicked an approved button.

Demonstrated Impact

The hardcoded string "openclaw-mattermost-interactions" is published in the source repository and provides zero additional entropy. The derivation is mathematically equivalent to HMAC-SHA256(botToken, payload) with no key separation: the security of the interaction signing scheme collapses entirely to the secrecy of the bot token.

Any Mattermost workspace administrator — or anyone who can read the bot token from the Mattermost admin panel, gateway environment variables, or config files — can forge legitimate-looking button interactions. Post-token checks at interactions.ts:384-421 validate post_id and channel_id against the Mattermost API, which raises attack complexity (the attacker must know a valid post and channel), but these values are observable by any workspace member who can see the interactive message, so they do not prevent exploitation by a privileged insider or anyone with token access.

A successful forged request triggers core.system.enqueueSystemEvent (traced from monitor.ts:~448), dispatching agent system events — approvals, confirmations, or other action-gated commands associated with the original interactive message — entirely under attacker control. The /mattermost/interactions/<accountId> endpoint uses auth: "plugin" (confirmed in monitor.ts:479-482 and src/plugins/registry.ts), meaning no gateway-layer authentication sits in front of this route; the HMAC _token is the complete and sole access control.

Environment

Affected in all versions containing deriveInteractionSecret in extensions/mattermost/src/mattermost/interactions.ts. Requires a running OpenClaw gateway with the Mattermost extension enabled and at least one account configured with interactive button messages. Confirmed present in current main; deterministic derivation is also asserted by extensions/mattermost/src/mattermost/interactions.test.ts.

Remediation Advice

Replace the hardcoded HMAC key with a randomly generated, per-account secret that is created at account registration time and persisted to the gateway's secure credential store (e.g., crypto.randomBytes(32).toString("hex")). The interaction signing secret must not be derived from the bot token using a publicly known constant — the bot token already serves as the Mattermost API credential and must not double as the signing root for the interaction integrity check.

<!-- submission-marker:CR-fqh-mattermost-hardcoded-hmac-key-interaction-forgery -->

extent analysis

TL;DR

Replace the hardcoded HMAC key with a randomly generated, per-account secret to prevent interaction forgery.

Guidance

  • Identify the affected code in extensions/mattermost/src/mattermost/interactions.ts and replace the hardcoded string "openclaw-mattermost-interactions" with a dynamic, randomly generated secret.
  • Generate a unique secret for each account during registration and store it securely in the gateway's credential store.
  • Update the deriveInteractionSecret function to use the stored secret instead of the hardcoded string.
  • Verify that the new secret is properly generated, stored, and used for interaction signing.

Example

// Generate a random secret during account registration
const accountSecret = crypto.randomBytes(32).toString("hex");
// Store the secret securely
// ...

// Update the deriveInteractionSecret function
function deriveInteractionSecret(botToken: string, accountSecret: string): string {
  return createHmac("sha256", accountSecret).update(botToken).digest("hex");
}

Notes

  • This fix assumes that the gateway has a secure credential store to store the generated secrets.
  • The randomly generated secret should be sufficiently long and cryptographically secure to prevent brute-force attacks.

Recommendation

Apply the workaround by replacing the hardcoded HMAC key with a randomly generated, per-account secret to prevent interaction forgery. This fix addresses the root cause of the issue and provides a secure solution to prevent attackers from forging legitimate-looking button interactions.

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