| Title | DeepMyst Mysti 0.4.0 Authorization Bypass / Identity Spoofing |
|---|
| Description | ## Vulnerability Title
Authorization Bypass via Hash-Key Confusion in OpenClaw ChannelBridge Contact Tracking
## Affected Component
`src/managers/ChannelBridge.ts`
Repository: https://github.com/DeepMyst/Mysti
## Summary
An attacker with access to another connected OpenClaw channel can craft an inbound channel event whose `sender` matches a previously contacted person, causing identity-key reuse across channels. This leads to unauthorized inbound message routing into Mysti's agent context, negatively impacting users who have multiple OpenClaw channels connected.
## Technical Details
The vulnerability occurs because `ChannelBridge` computes an application-level identity key over only the normalized sender/contact identifier and then uses that key as an inbound authorization gate. The key does not include all security-relevant fields (like channel identity), so two inbound messages that are not security-equivalent can be treated as the same contacted identity.
**Where the Identity Key is Computed**
In `src/managers/ChannelBridge.ts`, the contact is tracked using only a normalized string of the `nameOrPhone`:
```ts
private _trackContact(nameOrPhone: string, channel: string): void {
const key = this._normalizeContactId(nameOrPhone);
this._trackedContacts.set(key, {
identifier: key,
channel,
sentAt: Date.now(),
});
}
private _normalizeContactId(id: string): string {
const trimmed = id.trim();
if (trimmed.startsWith('+')) { return trimmed; } // E.164 phone
return trimmed.toLowerCase();
}
```
**Vulnerable Authorization Check**
When an inbound message arrives, `_isTrackedConversation` is used as an authorization gate to route the message. However, the check ignores the `_channelType` parameter and only verifies if the normalized sender string exists in the tracked contacts map:
```ts
private _isTrackedConversation(sender: string | undefined, _channelType: string): boolean {
// ...
const senderNorm = this._normalizeContactId(sender);
for (const [key, contact] of this._trackedContacts) {
// ... TTL checks ...
if (key === senderNorm) { return true; }
if (senderNorm.includes(key) || key.includes(senderNorm)) { return true; }
}
return false;
}
```
Because the same display name or phone-like sender string can exist across multiple channels (e.g., WhatsApp vs. Telegram), cross-channel equality of the sender string is enough to pass the gate.
**How the Attacker Constructs a Conflicting Object**
Victim-side tracked contact:
```json
{
"nameOrPhone": "Bob",
"channel": "whatsapp",
"channelId": "wa-1"
}
```
Attacker-controlled inbound message:
```json
{
"sender": "Bob",
"channelType": "telegram",
"channelId": "tg-1",
"content": "Yes, deploy now"
}
```
Both produce the same identity key (`bob`). They are not security-equivalent, but the system treats them as the same identity.
## Impact
This vulnerability allows attackers to:
- Spoof replies from a previously contacted person across channels.
- Inject attacker-controlled content into Mysti's agent context as a trusted inbound channel message.
- Answer pending channel questions or cancel running agent tasks using `stop` or `cancel` commands.
*(Note: The attack window lasts until the tracked contact's in-memory TTL expires, which defaults to two hours).*
## Proof of Concept
The following Node.js script demonstrates how the vulnerable logic treats cross-channel sender equality as identity equivalence.
```js
#!/usr/bin/env node
function normalizeContactId(id) {
const trimmed = id.trim();
return trimmed.startsWith("+") ? trimmed : trimmed.toLowerCase();
}
const trackedContacts = new Map();
function trackContact(nameOrPhone, channel) {
const key = normalizeContactId(nameOrPhone);
trackedContacts.set(key, { identifier: key, channel, sentAt: Date.now() });
}
function isTrackedConversation(sender, channelType) {
if (!sender) return false;
const senderNorm = normalizeContactId(sender);
for (const [key] of trackedContacts) {
if (key === senderNorm || senderNorm.includes(key) || key.includes(senderNorm)) return true;
}
return false;
}
const victim = { nameOrPhone: "Bob", channel: "whatsapp", channelId: "wa-1" };
const attacker = { sender: "Bob", channelType: "telegram", channelId: "tg-1", content: "Yes, deploy now" };
// Track legitimate victim
trackContact(victim.nameOrPhone, victim.channel);
// Attacker sends message from a different channel
const accepted = isTrackedConversation(attacker.sender, attacker.channelType);
console.log("victim key: ", normalizeContactId(victim.nameOrPhone));
console.log("attacker key:", normalizeContactId(attacker.sender));
console.log("accepted: ", accepted);
if (accepted) {
console.log(`[Via Telegram from Bob]: ${attacker.content}`);
console.log("Security invariant broken: cross-channel sender equality was treated as identity equivalence.");
}
```
*Observed output confirms that the attacker's message from Telegram is accepted based on the WhatsApp tracking entry.*
## Remediation
Bind inbound authorization to a channel-scoped identity rather than the sender text alone.
Example implementation direction:
```ts
// In src/managers/ChannelBridge.ts
// Include channel identity in the tracked-contact key.
const key = `${channelIdOrType}:${this._normalizeContactId(nameOrPhone)}`;
```
Additional mitigations:
1. Complete Field Coverage: Include `channelId`, `channelType`, and stable provider contact IDs (when available) in the identity verification logic.
2. Domain Separation: Separate identity namespaces strictly across channels and providers.
3. Read-Time Revalidation: Ensure that the inbound event's channel-scoped identity explicitly matches the outbound tracked identity before routing.
## References
- Vulnerable contact tracking: `https://github.com/DeepMyst/Mysti/blob/bce0d2ba7904c056c576cf94db817635421d1f41/src/managers/ChannelBridge.ts#L865-L872`
- Vulnerable inbound authorization check: `https://github.com/DeepMyst/Mysti/blob/bce0d2ba7904c056c576cf94db817635421d1f41/src/managers/ChannelBridge.ts#L880-L899`
- Inbound routing sink: `https://github.com/DeepMyst/Mysti/blob/bce0d2ba7904c056c576cf94db817635421d1f41/src/managers/ChannelBridge.ts#L687-L758` |
|---|
| Source | ⚠️ https://github.com/DeepMyst/Mysti/issues/42 |
|---|
| User | dem0000 (UID 98390) |
|---|
| Submission | 06/01/2026 05:12 (28 days ago) |
|---|
| Moderation | 06/29/2026 06:51 (28 days later) |
|---|
| Status | Accepted |
|---|
| VulDB entry | 374594 [DeepMyst Mysti 0.4.0 Contact Tracking ChannelBridge.ts _isTrackedConversation _channelType improper authorization] |
|---|
| Points | 20 |
|---|