Skip to content
This repository was archived by the owner on May 27, 2025. It is now read-only.

Hubot can DOS itself via conversations.info events #554

@mistydemeo

Description

@mistydemeo

Description

My company recently experienced an outage of our Hubot when we were rate-limited by surprise. After discussing it with Slack support, the reason is apparently that conversations.info was being called a large number of times.

What type of issue is this? (place an x in one of the [ ])

  • bug
  • enhancement (feature request)
  • question
  • documentation related
  • testing related
  • discussion

Requirements (place an x in each of the [ ])

  • I've read and understood the Contributing guidelines and have done my best effort to follow them.
  • I've read and agree to the Code of Conduct.
  • I've searched for any related issues and avoided creating a duplicate issue.

Bug Report

It looks like hubot-slack calls this API method during the process of sending a message:

# The `envelope.room` property is intended to be a conversation ID. Even when that is not the case, this method will
# makes a reasonable attempt at sending the message. If the property is set to a public or private channel name, it
# will still work. When there's no `room` in the envelope, this method will fallback to the `id` property. That
# affordance allows scripts to use Hubot User objects, Slack users (as obtained from the response to `users.info`),
# and Slack conversations (as obtained from the response to `conversations.info`) as possible envelopes. In the first
# two cases, envelope.id` will contain a user ID (`Uxxx` or `Wxxx`). Since Hubot runs using a bot token (`xoxb`),
# passing a user ID as the `channel` argument to `chat.postMessage` (with `as_user=true`) results in a DM from the bot
# user (if `as_user=false` it would instead result in a DM from slackbot). Leaving `as_user=true` has no effect when
# the `channel` argument is a conversation ID.
It only happens sometimes, and it looks like there's an attempt at maintaining an internal mapping:
###*
# Fetch conversation info from conversation map. If not available, call conversations.info
# @public
###
fetchConversation: (conversationId) ->
# Current date minus 5 minutes (time of expiration for conversation info)
expiration = Date.now() - (5 * 60 * 1000)
# Check whether conversation is held in client's channelData map and whether information is expired
return Promise.resolve(@channelData[conversationId].channel) if @channelData[conversationId]?.channel? and
expiration < @channelData[conversationId]?.updated
# Delete data from map if it's expired
delete @channelData[conversationId] if @channelData[conversationId]?
# Return conversations.info promise
@web.conversations.info(conversationId).then((r) =>
if r.channel?
@channelData[conversationId] = {
channel: r.channel,
updated: Date.now()
}
r.channel
)
But I'm guessing for whatever reason we saw a lot of cases where real API requests were made.

I'm not clear why exactly this was; I don't have much visibility into it. Our application itself doesn't call this method at all except through whatever hubot-slack calls on its own. Since conversations.info has a much lower rate limit than actually posting messages, this has the possibility to reduce the number of messages that can be safely posted under some circumstances.

Reproducible in:

hubot-slack version: 4.6.0

node version: 8.2.0

OS version(s): Debian jesse

Steps to reproduce:

Unclear

Expected result:

Hubot doesn't rate-limit itself in normal operation.

Actual result:

Hubot was rate-limited.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementM-T: A feature request for new functionality

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions