A ChatOps bot that can deploy, restart or scale production is a privileged non-human identity, and the chat channel becomes its login screen. Teams wire Slack or Microsoft Teams to deployment pipelines, cloud accounts and Kubernetes clusters so engineers can type /deploy instead of opening a console. The bot then holds credentials that reach production, and anyone who can post in the right channel, or forge a request to the bot's endpoint, inherits them. This guide covers how to authorise chat commands, verify that requests really come from the chat platform, scope the credentials behind the bot and keep an audit trail. It is written for platform engineers, SRE teams and security architects; workspace-level token hygiene for Slack is covered in our Slack Tokens Security Guide, and this page goes past it to the bot's back end.
Key takeaways
- Two identities sit behind every command. The human who typed it and the bot credential that executes it; your controls must bind them together and log both.
- Channel membership is not authorisation. Check the user ID against an allow list or your identity provider groups for every privileged command, not just who can see the channel.
- Verify every inbound request. Use Slack request signing or mutual TLS, or validate the Bot Framework JWT for Teams, and reject anything that fails.
- Scope the bot's back-end credentials to the commands it offers. A bot that restarts services should not hold cloud administrator rights.
- Put approvals outside the requester's control. High-risk commands need a second person, and the bot should hand off to the pipeline's own approval gate rather than replace it.
How a ChatOps command flows, and where it can be abused
Most ChatOps designs follow the same chain. Each hop has its own identity and its own failure mode.
| Hop | Identity involved | What goes wrong | Control |
|---|---|---|---|
| User types a command in a channel | The chat user account | Compromised or guest account, or a user in the wrong channel | Per-command authorisation on user ID, MFA on the chat platform |
| Chat platform calls the bot | Platform signing secret, client certificate or JWT | Forged requests to a public bot endpoint, replayed requests | Signature or JWT validation, timestamp window |
| Bot calls back to the chat platform | Bot token or app password | Token leaked from code or logs, used to read channels | Secrets manager, least scopes, rotation |
| Bot executes the action | Cloud role, Kubernetes service account, CI/CD token | Bot holds far more than its commands need | Per-command roles, guardrails, short-lived credentials |
| Result posted to the channel | Bot token | Secrets or customer data echoed into chat history | Output filtering, private responses |
Authorising commands, not channels
A private channel feels like an access control, but membership drifts, guests get added and shared channels connect other organisations. Make the bot decide, for every command, whether this user may run it.
- Use stable IDs: Slack sends
user_id,team_id,channel_idand, for Enterprise organisations,enterprise_idwith each slash command. Slack's documentation advises working with IDs rather than names. Check all of them: the right user in the right workspace, in an approved channel. - Map chat users to corporate identities: resolve the chat user to your identity provider account and check group membership at run time, so leavers lose command rights when their account is disabled.
- Tier the commands: read-only commands (status, logs summary) for wide groups; change commands (restart, scale, deploy to staging) for the owning team; production deploys, rollbacks and data operations for a small group with approval.
- Refuse in shared and external channels: check that the workspace or tenant ID is your own before acting.
- Bind the requester to the action: pass the requesting user's identity to the pipeline or cloud API as a tag or session name, so the downstream audit log shows who asked, not just the bot.
Command tiers (our recommended baseline)
| Tier | Example commands | Who may run | Extra control |
|---|---|---|---|
| 0: read | Service status, last deploy, on-call lookup | Any employee in approved channels | Redact secrets and personal data in output |
| 1: operate | Restart a pod, clear a cache, scale within limits | Owning team group | Rate limit, log requester |
| 2: change | Deploy to production, roll back, toggle a feature flag | Release group | Second-person approval, change window check, pipeline gate |
| 3: sensitive | Data exports, IAM changes, secret reads | Not offered through chat | Use the PAM or JIT path instead |
Keeping tier 3 out of chat entirely is the simplest control you have. See the JIT Access Guide for the alternative path.
Verifying that requests come from the chat platform
A bot exposed on a public URL will receive requests from anyone who finds it. Verification is what stops a forged /deploy.
Slack
- Request signing: Slack sends
X-Slack-SignatureandX-Slack-Request-Timestamp. The app builds the stringv0:timestamp:raw_body, computes an HMAC SHA-256 with the app's signing secret, prefixesv0=and compares with a constant-time function. Slack's example rejects requests more than five minutes from local time to limit replay. Use the raw body before any parsing. - Verification tokens: Slack describes the older
tokenfield as deprecated; use the signing secret only. - Mutual TLS option: the terminating server can request Slack's client certificate and the app accepts only the exact SAN
platform-tls-client.slack.com. Make sure the forwarding header cannot be set by the client. - Socket Mode: the app opens an outbound WebSocket with an app-level token (prefix
xapp-) and needs no public request URL; Slack's docs describe events on this connection as pre-authenticated. This removes the public endpoint, so the app-level token becomes the secret to protect. Slack states Socket Mode apps are not currently allowed in the public Slack Marketplace, which is rarely an issue for internal ChatOps bots. - Timing: Slack expects an HTTP 200 within 3,000 milliseconds. Acknowledge quickly and run long actions asynchronously, but only after verification and authorisation.
Microsoft Teams (Bot Framework)
- Validate the JWT on every request: Microsoft's Bot Connector documentation requires checking the issuer
https://api.botframework.com, the audience equal to your bot's Microsoft App ID, validity with five minutes of clock skew, the signature against keys from the published OpenID metadata (refreshed at least every 24 hours) and that theserviceUrlclaim matches the activity. The documentation warns against exposing any way to disable this validation. - Outbound calls: the bot obtains a client-credentials token for its App ID. Microsoft lists a user-assigned managed identity as an option where you do not manage the bot's credentials yourself; prefer it where your hosting supports it, otherwise keep the app secret in a secrets manager.
- Tenant checks: confirm the tenant ID in the activity is your own before acting. See the Microsoft Teams Security Guide for app permission policies.
Scoping the credentials behind the bot
The bot's back-end credentials are where the real damage happens. Design them per command family, not per bot.
- One role per command family: a restart command assumes a role that can restart named services; a deploy command triggers the pipeline and holds no cloud rights at all.
- Trigger pipelines, do not replace them: the bot calls the CI/CD system with a token that can start a named workflow. The pipeline keeps its own protected environment and approval rules, so a bot compromise cannot skip them. See the CI/CD Pipeline Identity Security Guide.
- Short-lived credentials: run the bot on a platform with workload identity so it gets cloud credentials without stored keys. See the Kubernetes RBAC Guide for bots that act on clusters.
- Chat tokens with minimum scopes: a bot that only answers commands does not need history read scopes for every channel.
- Secrets out of code and chat: signing secrets, bot tokens and cloud credentials go in a secrets manager. See the Secrets Management Guide.
Managed ChatOps services: AWS example
Managed services move some of this into configuration. AWS documents its service, now called Amazon Q Developer in chat applications (formerly AWS Chatbot), with three layers. A channel role gives all members the same permissions; user roles make each member choose a role mapped to their chat ID; and channel guardrail policies cap both. AWS summarises effective permissions as the intersection of guardrail policies and what the roles allow. Its documentation lists operations it does not run from chat, including iam:*, kms:*, secretsmanager:* and sts:*, and recommends keeping the default protection policy until guardrails and roles are verified. Use user roles for change commands, set guardrails to the narrowest service set the channel needs, and confirm current behaviour in the AWS documentation.
AI assistants in the channel
Teams increasingly put a language model behind the bot so engineers can ask in plain words. That adds two risks. Text in a channel, a ticket or a log line the bot reads can carry instructions (prompt injection), and a model with broad tools can take actions nobody asked for (excessive agency). Keep the deterministic command layer as the only path to change actions, have the model propose a command that the user then confirms, and apply the same per-command authorisation. See the OWASP LLM Top 10 LLM06 Excessive Agency Guide and the AI Agent Tool and Plugin Security Guide.
Approvals in chat
Chat is a convenient place to ask for approval but a poor place to enforce it, because the requester often controls the conversation.
- The bot posts a request card with the exact change (service, version, environment, diff link).
- Approval buttons check that the approver is in the approver group and is not the requester.
- The bot records the approver's user ID and passes it to the pipeline, which checks again against its own approval rule.
- Approvals expire after a short window (our recommendation: 30 minutes) and are tied to that exact change.
For the principles of second-person approval, see Dual control and four-eyes approval for privileged and agent actions.
Detection and measurement
- Failed signature or JWT validation: a steady trickle is scanning; a burst is targeting. Log the source address and alert.
- Commands refused by authorisation: repeated refusals for one user may indicate a compromised account probing the bot.
- Bot credentials used outside the bot: cloud or pipeline API calls with the bot's role from an address other than its host.
- Commands from new channels, workspaces or tenants: anything outside the approved list.
- Privileged commands outside working hours or change windows, correlated with the on-call rota.
Metrics to track:
- Percentage of privileged commands with a recorded human requester in the downstream audit log.
- Number of distinct back-end permissions the bot holds versus the number its commands use.
- Age of the signing secret, bot token and back-end credentials against your rotation standard.
- Percentage of tier 2 commands approved by someone other than the requester.
Implementation steps
- Inventory: list every chat bot, its endpoint, its tokens and the systems its back end reaches. The Slack apps, bots and tokens audit guide helps for Slack.
- Turn on verification in log-only mode for a week, check that no legitimate request fails, then enforce. Rollback is switching enforcement off, not removing the code.
- Add per-command authorisation using identity provider groups, starting with change commands.
- Split back-end credentials by command family and remove anything unused for 90 days.
- Move production deploys to pipeline triggers with the pipeline's own approval gate.
- Add detection for the signals above and review bot permissions quarterly.
Framework mapping
| Control | NIST SP 800-53 Rev 5 | NIST CSF 2.0 | ATT&CK technique addressed |
|---|---|---|---|
| Per-command authorisation | AC-3, AC-6 | PR.AA-05 | T1078 Valid Accounts |
| Request verification | IA-9, SC-8 | PR.AA-03 | T1199 Trusted Relationship |
| Bot token storage and rotation | IA-5 | PR.AA-01 | T1552.001 Credentials In Files, T1550.001 Application Access Token |
| Second-person approval | AC-5 | PR.AA-05 | T1078.004 Cloud Accounts |
| Requester-attributed audit | AU-3, AU-12 | DE.CM-03 | T1078 Valid Accounts |
Common failure patterns
- Channel membership as the only check: a guest added for a project can deploy to production.
- Verification disabled during development and never turned back on, leaving a public endpoint that runs commands for anyone.
- One bot with cloud administrator rights because it was quicker than writing per-command roles.
- Integration tokens concentrated in one place: the Salesloft Drift Breach 2025 showed how OAuth tokens held by a chatbot integration could be used to reach connected customer Salesforce instances; Google Threat Intelligence Group reported over 700 potentially impacted organisations. Your ChatOps bot's token store is the same kind of target.
- Secrets echoed into channels: a "show config" command prints connection strings into searchable history.
- Approvals the requester can grant: the approve button checks group membership but not that the approver differs from the requester.
Practitioner checklist
- Inventory every ChatOps bot, its chat tokens and the systems its back end can reach.
- Verify every inbound request: Slack signing secret or mutual TLS, or full Bot Framework JWT validation.
- Authorise each command on user ID, workspace or tenant ID and channel ID, using identity provider groups.
- Keep sensitive operations such as IAM changes and secret reads out of chat.
- Give the bot per-command back-end roles and short-lived credentials; remove unused permissions.
- Trigger pipelines from chat and keep the pipeline's own approval gate.
- Require a different approver for production changes and pass both identities downstream.
- Filter command output so secrets and personal data never land in chat history.
- Alert on validation failures, refused commands and bot credentials used from other hosts.
Standards and references
- Slack: Verifying requests from Slack
- Slack: Implementing slash commands
- Slack: Using Socket Mode
- Microsoft Learn: Authentication with the Bot Connector API
- AWS: Understanding permissions for Amazon Q Developer in chat applications
- OWASP: LLM06:2025 Excessive Agency
- NIST: SP 800-53 Rev. 5 Security and Privacy Controls
Related NHI Mgmt Group resources: Slack Tokens Security Guide, RPA and Bot Identity Security Guide, Discord and Telegram Bot Tokens Security Guide, Network Automation Security.