
Security News
Feross on the 10 Minutes or Less Podcast: Nobody Reads the Code
Socket CEO Feross Aboukhadijeh joins 10 Minutes or Less, a podcast by Ali Rohde, to discuss the recent surge in open source supply chain attacks.
slack-moderator
Advanced tools
As Slack is taking over for IRC as the community default platform, and because Slack isn't really designed as a community app, we need some basic moderation features. This project is to help create basic moderation rules to help control bad actors, and st
As Slack is taking over for IRC as the community default platform, and because Slack isn't really designed as a community app, we need some basic moderation features. This project is to help create basic moderation rules to help control bad actors, and stop spam.
Since we dont want the bad actors to have the signals that we look for, we create a configurable interface which allows you to create rules and checks that apply to each message or event from Slack. The rules themselves are hidden away but accessible if you contact us. Ultimately this is just a processor that runs configs and speaks Slack.
To install simply run:
$ npm i -g slack-moderator
Once its installed you can run to see the basic options.
$ slack-moderator --help
You will need to create 2 config files for this to run - (Rules Config and General Config once that is done, you can simply run the bot like:
$ slack-moderator --config [PATH_TO_CONFIG] --rules-config [PATH_TO_RULES_CONFIG]
To have the Slack moderator be able to work, you will need to create a Slack Bot and point it at the Slack Moderator bot. I will not cover this, but this will require hosting the Slack Moderator app somewhere and creating a public url to it.
Most of the config is pretty simple however the rules also contain the info for the attack vectors. For some rules contact us and we will give you a base to work with.
This is the default config. You can configure it however you want but you will need to add the verification token you got from step 2 in Installing Slack
exports.default = {
rules: "rules",
server: {
host: "0.0.0.0",
port: 3000
},
slack: {
verificationToken: "[VERIFICATION_TOKEN]",
},
logging: {
appName: "moderator",
stdoutLevel: "info",
errorPath: "/var/tmp/moderator-error.log",
requestLevels: {
default: "info",
500: "error",
404: "warn"
},
color: true
},
};
The rules file consists of 3 sections and like the general config is a javascript file.
So lets say you wanted to create a rule that deletes a message from any user that writes potato. It would look something like:
exports.default = {
users: {
"admin-user": {
"token": "[USER_TOKEN_WITH_ADMIN_PERMISSIONS]"
}
},
actions: {
"delete-current-message": {
type: "delete-message",
user: "admin-user"
}
},
rules: {
"remove-text-potato": {
"description": "Removes the message if a user writes potato",
if: {
type: "and",
rules: [
{
field: "type",
type: "equal",
value: "message"
},
{
field: "text",
type: "token-equals",
value: "potato"
},
]
},
actions: [
"delete-current-message"
]
}
}
}
The general pattern is:
exports.default = {
users: {
"[user-name]": {
"token": "[xoxb-slack-user-or-bot-token]"
}
},
actions: {
"[action-name]": {
type: "[action-type]",
... other options here
}
},
rules: {
"[rule-name]": {
"description": "Friendly description to describe what the rule does",
if: {
...conditions
},
actions: [
"[action-name]"
]
}
}
}
These are the users you want to perform certain actions on behalf of. The only thing we need here is the token used to act on behalf of this user.
...
users: {
"my-user": {
"token": "[xoxb-slack-user-or-bot-token]"
}
},
...
This is a block where you can configure certain actions to run and use them in the rules as triggers. For example,
...
actions: {
"my-action": {
type: "notify",
channel: "[my-admin-channel]",
message: "User <@${user}> wrote 'potato' messages on channel <#${channel}>.",
user: "my-user"
}
},
...
There are currently a few actions we support:
This action will send a message to the specified channel with the specified message. There are a few strings that are able to be replaced into the message to let the channel know what happened.
Fields:
| field | description |
|---|---|
| channel | The channel ID to use. The easiest way to find this is looking at the URL when in a slack channel. For example in https://my-slack.slack.com/messages/C1111111 C1111111 is the channel ID. |
| message | The message to write to the channel. Currently you can use ${user} and ${channel} to replace the raw channel and user id. |
| user | This is the user to run the command as. This should match to a user registered in the Users Section |
Example:
...
"my-action": {
type: "notify",
channel: "[my-admin-channel]",
message: "User <@${user}> wrote 'potato' messages on channel <#${channel}>.",
user: "my-user"
}
...
This action will delete the message send by the user.
Fields:
| field | description |
|---|---|
| user | This is the user to run the command as. This should match to a user registered in the Users Section. This user has to have admin permissions. |
Example:
...
"my-action": {
type: "delete-message",
user: "my-user"
}
...
This action will block the current user.
Fields:
| field | description |
|---|---|
| user | This is the user to run the command as. This should match to a user registered in the Users Section. This user has to have admin permissions. |
Example:
...
"my-action": {
type: "delete-message",
user: "my-user"
}
...
This action will send an ephemeral message (only visible to the user) with a given message
Fields:
| field | description |
|---|---|
| user | This is the user to run the command as. This should match to a user registered in the Users Section. This user has to have admin permissions. |
| message | The message to send to the user |
Example:
...
"my-action": {
type: "warn-user",
user: "my-user",
message: "Please don't do that again."
},
...
This will simply log the message to the service log. Fields:
| field | description |
|---|---|
| message | Any additional comment to add to the log |
Example:
...
"my-action": {
type: "log-message",
message: "Please don't do that again."
},
...
The rules are the actual checks which you want to run against the messages that users write and actions that happen. The general pattern is:
...
rules: {
"[rule-name]": {
"description": "Friendly description to describe what the rule does",
if: {
...conditions
},
actions: [
"[action-name]"
]
}
}
...
Looking at this example, you will see that a rule has a name and 3 sections. The name will be used only in logs but has to be unique.
| field | description |
|---|---|
| description | This is just a description used to define what this rule does. |
| if | This is the object containing the condition to match for this rule to trigger. There one root condition but can be replaced with a "and" or "or" condtion to specifiy multiple rules. (Conditions) |
| actions | This a list of string action names referring to actions registered in the Actions Block |
There are obviously a few conditions to help us create a rule to validate an action starting with very simple ones to very complex conditions.
This is a meta condition and will resolve to true if all the child rules also resolve to true.
Fields:
| field | description |
|---|---|
| rules | This is a list of child rules all of which to resolve. |
Example:
...
if: {
type: "and",
rules: [
...child rules
]
}
...
This is a meta condition and will resolve to true if any of the child rules resolve to true.
Fields:
| field | description |
|---|---|
| rules | This is a list of child rules one of which to resolve. |
Example:
...
if: {
type: "or",
rules: [
...child rules
]
}
...
This is a meta condition and will resolve the opposite of the child. If the child resolves to true, this rule will resolve to false.
Fields:
| field | description |
|---|---|
| rule | The child rule to resolve. |
Example:
...
if: {
type: "not",
rule: [
...child rule
]
}
...
This is a meta condition and will always resolve false.
Example:
...
if: {
type: "disabled"
}
...
This will compare a field in the incoming message with a static value defined in config. If these are equal this will resolve to true.
Fields:
| field | description |
|---|---|
| field | The field name to extract from the incoming Slack message - "text" is most common |
| value | The value to compare to the field |
| null | The instead of specifying a value, can just check that the value is null or not. This should be true or false. |
Example:
...
if: {
type: "equal",
field: "type",
value: "file_share"
}
...
Should match isNull``` ... if: { type: "equal", field: "bot", null: true } ...
---
##### includes
This will check if a string defined in config is a substring of a field in the incoming message. If the field in the incoming message has a given string, this will resolve to true.
*Fields:*
| field | description |
| ------ | ------------ |
| field | The field name to extract from the incoming Slack message - "text" is most common |
| value | The value to look for as a substring of the incoming message object. |
*Example:*
Will resolve to true if someone sends something like `i like potatos`.
... if: { type: "includes", field: "text", value: "potato" } ...
---
##### regex-match
This will check if a string in the incoming message matches a regular expression.
*Fields:*
| field | description |
| ------ | ------------ |
| field | The field name to extract from the incoming Slack message - "text" is most common |
| regex | The regular expression you want to test. |
| flags | Optional regular expression flags such as "i" for invariant case.
*Example:*
Will resolve to true if someone sends something like `hello world` or `HELLOworld`.
... if: { field: "text", type: "regex-match", regex: "hello[\ ]?world", flags: "i" } ...
---
##### token-equals
This is a slightly more complex version of includes. This will first try to tokenize and normalize the tokens before doing a comparison. For example if you want to block anyone writing "hell", using an `includes` rule, we would also trigger on "hello world". What this condition does is it first breaks on "hello" and "world" and checks if one of those tokens is exactly equal to "hell".
*Fields:*
| field | description |
| ------ | ------------ |
| field | The field name to extract from the incoming Slack message - "text" is most common |
| value | The value to look for as token in the given message |
*Example:*
Will resolve to true if someone sends something like `hell with this` but not `hello world`.
... if: { type: "token-equals", field: "text", value: "hell" } ...
---
##### tokens-in
This, like the tokens-equals condition, will first tokenize and normalize the tokens in the message. This will then check
if a subset of the tokens is in a given list. This method will detect things such as "hells bells" the same as "hell bell".
*Fields:*
| field | description |
| ------ | ------------ |
| field | The field name to extract from the incoming Slack message - "text" is most common |
| list | The word list to check against. |
*Word Lists*
We currently have lists of bad words for each language and one combined list. All international word lists were used from:
https://github.com/LDNOOBW/List-of-Dirty-Naughty-Obscene-and-Otherwise-Bad-Words and one set from http://www.bannedwordlist.com/lists/swearWords.txt
* bad-words - this is a longer list of words with bad words and sexual innuendo in all 25 languages below
* ar-bad-words - Bad words in Arabic
* cs-bad-words - Bad words in Czech
* da-bad-words - Bad words in Danish
* de-bad-words - Bad words in German
* en-bad-words - Bad words in English
* eo-bad-words - Bad words in Esperanto
* es-bad-words - Bad words in Spanish
* fa-bad-words - Bad words in Persian
* fi-bad-words - Bad words in Finnish
* fr-bad-words - Bad words in French
* hi-bad-words - Bad words in Hindi
* hu-bad-words - Bad words in Hungarian
* it-bad-words - Bad words in Italian
* ja-bad-words - Bad words in Japanese
* ko-bad-words - Bad words in Korean
* nl-bad-words - Bad words in Dutch
* no-bad-words - Bad words in Norwegian
* pl-bad-words - Bad words in Polish
* pt-bad-words - Bad words in Portuguese
* ru-bad-words - Bad words in Russian
* sv-bad-words - Bad words in Swedish
* th-bad-words - Bad words in Thai
* tlh-bad-words - Bad words in Klingon (yes it was part of the set)
* tr-bad-words - Bad words in Turkish
* zh-bad-words - Bad words in Chinese
* en-swear-words - This is a smaller subset of just swear words in english.
*Example:*
Will resolve to true if someone sends something like `hell with this` but not `hello world`.
... if: { field: "text", type: "tokens-in", list: "bad-words" } ...
FAQs
As Slack is taking over for IRC as the community default platform, and because Slack isn't really designed as a community app, we need some basic moderation features. This project is to help create basic moderation rules to help control bad actors, and st
The npm package slack-moderator receives a total of 5 weekly downloads. As such, slack-moderator popularity was classified as not popular.
We found that slack-moderator demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Socket CEO Feross Aboukhadijeh joins 10 Minutes or Less, a podcast by Ali Rohde, to discuss the recent surge in open source supply chain attacks.

Research
/Security News
Campaign of 108 extensions harvests identities, steals sessions, and adds backdoors to browsers, all tied to the same C2 infrastructure.

Security News
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.