Bug Description
Telegram native slash commands (/status, /models, etc.) return "You are not authorized to use this command." in group chats, even when the sender is explicitly listed in commands.allowFrom.telegram. The same commands work correctly in DMs.
Root Cause
There are two separate command authorization code paths:
- Text command handler (
resolveCommandAuthorization in auto-reply/reply) — correctly resolves commands.allowFrom via resolveCommandsAllowFromList() and uses it as the sole authority when configured ✅
- Telegram native command handler (
resolveTelegramCommandAuth in telegram/bot-native-commands.ts) — does not check commands.allowFrom at all ❌ — it only evaluates channel-level allowFrom + the pairing store via normalizeDmAllowFromWithStore
The docs for commands.allowFrom state:
When configured, it is the only authorization source for commands and directives (channel allowlists/pairing and useAccessGroups are ignored).
This contract is honored by the text command path but not by the native Telegram command path.
Steps to Reproduce
- Configure
commands.allowFrom with your Telegram user IDs:
{
"commands": {
"allowFrom": {
"telegram": ["123456789"],
"*": ["123456789"]
}
},
"channels": {
"telegram": {
"groupPolicy": "open"
// Note: no channels.telegram.allowFrom set
}
}
}
- Send
/status in a DM → works ✅
- Send
/status in a group chat → "You are not authorized to use this command." ❌
Why It Surfaces Now
The breaking change in 2026.2.25 (#25988) removed the DM pairing-store fallback for group sender authorization:
Security/Telegram group allowlist: fail closed for group sender authorization by removing DM pairing-store fallback from group allowlist evaluation
In the native command handler, this means storeAllowFrom is [] for groups. Combined with no channels.telegram.allowFrom being set, the handler sees zero authorized entries and rejects the sender — even though commands.allowFrom explicitly authorizes them.
Before 2026.2.25, the pairing store fallback masked this gap.
Code References (2026.2.26)
In pi-embedded-CQnl8oWA.js:
- Native handler (
resolveTelegramCommandAuth, ~line 73597): builds dmAllow from channel-level allowFrom + pairing store only. Never calls resolveCommandsAllowFromList().
- Text handler (
resolveCommandAuthorization, ~line 10906): correctly calls resolveCommandsAllowFromList() and when commandsAllowFromList !== null, uses it as the sole authority.
Expected Behavior
resolveTelegramCommandAuth should check commands.allowFrom (via resolveCommandsAllowFromList or equivalent) before falling through to channel-level allowFrom / pairing store checks, consistent with the text command handler and the documented behavior.
Workaround
Add channels.telegram.allowFrom with the same user IDs. This feeds directly into the native handler:
{
"channels": {
"telegram": {
"allowFrom": ["123456789"]
}
}
}
Environment
- OpenClaw version: 2026.2.26
- Channel: Telegram (polling mode)
- OS: macOS (arm64)
Bug Description
Telegram native slash commands (
/status,/models, etc.) return "You are not authorized to use this command." in group chats, even when the sender is explicitly listed incommands.allowFrom.telegram. The same commands work correctly in DMs.Root Cause
There are two separate command authorization code paths:
resolveCommandAuthorizationinauto-reply/reply) — correctly resolvescommands.allowFromviaresolveCommandsAllowFromList()and uses it as the sole authority when configured ✅resolveTelegramCommandAuthintelegram/bot-native-commands.ts) — does not checkcommands.allowFromat all ❌ — it only evaluates channel-levelallowFrom+ the pairing store vianormalizeDmAllowFromWithStoreThe docs for
commands.allowFromstate:This contract is honored by the text command path but not by the native Telegram command path.
Steps to Reproduce
commands.allowFromwith your Telegram user IDs:{ "commands": { "allowFrom": { "telegram": ["123456789"], "*": ["123456789"] } }, "channels": { "telegram": { "groupPolicy": "open" // Note: no channels.telegram.allowFrom set } } }/statusin a DM → works ✅/statusin a group chat → "You are not authorized to use this command." ❌Why It Surfaces Now
The breaking change in 2026.2.25 (#25988) removed the DM pairing-store fallback for group sender authorization:
In the native command handler, this means
storeAllowFromis[]for groups. Combined with nochannels.telegram.allowFrombeing set, the handler sees zero authorized entries and rejects the sender — even thoughcommands.allowFromexplicitly authorizes them.Before 2026.2.25, the pairing store fallback masked this gap.
Code References (2026.2.26)
In
pi-embedded-CQnl8oWA.js:resolveTelegramCommandAuth, ~line 73597): buildsdmAllowfrom channel-levelallowFrom+ pairing store only. Never callsresolveCommandsAllowFromList().resolveCommandAuthorization, ~line 10906): correctly callsresolveCommandsAllowFromList()and whencommandsAllowFromList !== null, uses it as the sole authority.Expected Behavior
resolveTelegramCommandAuthshould checkcommands.allowFrom(viaresolveCommandsAllowFromListor equivalent) before falling through to channel-level allowFrom / pairing store checks, consistent with the text command handler and the documented behavior.Workaround
Add
channels.telegram.allowFromwith the same user IDs. This feeds directly into the native handler:{ "channels": { "telegram": { "allowFrom": ["123456789"] } } }Environment