Free tech learning for everyone, from basics to pro

Automation ProjectsProgramming and Application SecurityAdvanced

Project: a ChatOps bot for network checks

In short: ChatOps brings automation into the team chat, so checks and their results are visible to everyone. This project builds a bot that runs a small allow-list of read-only network checks for authorised users. Input is validated strictly, commands run without a shell, and every request is logged.

Goal and what you will build

ChatOps means running operational tasks from a team chat platform. When an engineer types /netcheck ping 192.168.10.20 and the bot replies in the channel, the whole team sees the question, the evidence and the answer, which speeds up incident response and helps new staff learn. In this project you will build a bot that offers three read-only checks: ping, DNS lookup and interface status from a lab switch.

The example uses Slack’s Bolt for Python in Socket Mode, which connects outwards to Slack so you do not need to expose a web server to the internet. Microsoft Teams and other platforms follow the same ideas with their own SDKs (Software Development Kits). Build it in your own workspace and lab.

ChatOps request pathEngineer/netcheckpingChatplatformsends eventBotauth +validateRun checkallow-listedonlyReplyresult inchannelAudit logwho, what,when
Figure 1. A ChatOps bot receives a command, checks who sent it and what they asked, runs only approved actions and replies in the channel.

Design and security

Bot security layersPlatformsigned events, SSOAuthorisationallowed users, channelsInput checksstrict validationActionsread-only allow-listLoggingfull audit trail
Figure 2. A chat bot is a remote control for your network, so it needs layered checks before it runs anything.

A bot that can reach your network is a powerful tool and an attractive target. Design it as you would any privileged service:

  • Read-only by default: the bot can look, not change. Change actions, if ever added, need a separate approval step.
  • Allow-list of commands: map a few command names to fixed Python functions. Never pass user text to a shell.
  • Strict validation: targets must be valid IP addresses inside approved ranges, or hostnames in your own domain.
  • Authorisation: only listed user IDs, in listed channels, may run checks.
  • Secrets: bot tokens and device credentials come from environment variables or a vault.
  • Audit: log every request with user, command, target and result.

Build it step by step

  1. Create a chat app in your own workspace, enable Socket Mode, add a slash command /netcheck and install the app. Note the bot token and app-level token.
  2. Store both tokens as environment variables: SLACK_BOT_TOKEN and SLACK_APP_TOKEN.
  3. Install the library: pip install slack_bolt.
  4. Write the bot below, run it on a lab host that can reach your devices, and test each command, including invalid input.
  5. Run it as a service under a dedicated, unprivileged user account.
#!/usr/bin/env python3
import ipaddress, logging, os, socket, subprocess
from slack_bolt import App
from slack_bolt.adapter.socket_mode import SocketModeHandler

logging.basicConfig(filename="netcheck-audit.log", level=logging.INFO,
                    format="%(asctime)s %(message)s")
app = App(token=os.environ["SLACK_BOT_TOKEN"])

ALLOWED_USERS = set(os.environ.get("NETCHECK_USERS", "").split(","))
ALLOWED_NETS = [ipaddress.ip_network(n) for n in ("192.168.10.0/24", "10.10.0.0/16")]

def safe_ip(text):
    ip = ipaddress.ip_address(text)                 # raises ValueError if invalid
    if not any(ip in n for n in ALLOWED_NETS):
        raise ValueError("address outside approved ranges")
    return str(ip)

def do_ping(arg):
    ip = safe_ip(arg)
    r = subprocess.run(["ping", "-c", "3", "-W", "2", ip],   # list: no shell
                       capture_output=True, text=True, timeout=15)
    return r.stdout.strip().splitlines()[-1] if r.returncode == 0 else f"{ip} not responding"

def do_dns(arg):
    if not arg.endswith(".example.com"):
        raise ValueError("only example.com names allowed")
    return ", ".join(sorted({a[4][0] for a in socket.getaddrinfo(arg, None)}))

CHECKS = {"ping": do_ping, "dns": do_dns}

@app.command("/netcheck")
def netcheck(ack, respond, command):
    ack()                                           # reply within 3 seconds
    user, text = command["user_id"], command.get("text", "").split()
    if user not in ALLOWED_USERS:
        logging.info("DENIED user=%s text=%s", user, text)
        return respond("You are not authorised to run network checks.")
    if len(text) != 2 or text[0] not in CHECKS:
        return respond("Usage: /netcheck ping <ip> | /netcheck dns <name>")
    try:
        result = CHECKS[text[0]](text[1])
    except (ValueError, subprocess.TimeoutExpired, OSError) as e:
        result = f"Check refused or failed: {e}"
    logging.info("user=%s check=%s target=%s", user, text[0], text[1])
    respond(response_type="in_channel", text=f"`{text[0]} {text[1]}`: {result}")

if __name__ == "__main__":
    SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"]).start()

Tip: the call to subprocess.run uses a list of arguments and no shell, and the target has already been parsed as an IP address. Together these block command injection, where input such as 8.8.8.8; rm -rf / would otherwise run a second command.

How to extend it and show it

  • Add an intf check that uses Netmiko or NAPALM with a read-only account to show one interface’s status and errors.
  • Let monitoring alerts arrive in the channel through webhooks, with buttons that run the relevant check.
  • Add rate limiting per user and move the allow-lists into a configuration file under version control.
  • For any future change action, require a second engineer to approve in the chat before it runs.

For your portfolio, record a short demo of the bot answering valid commands and refusing invalid or unauthorised ones; the refusals are as impressive as the successes. Document the security design in the README, including the threat of command injection and how you prevented it, and show a few lines of the audit log with fictional user IDs.

Practice

Why does the bot use subprocess.run with a list and no shell?
Each argument is passed directly to the program, so special characters in user input cannot start extra commands. This prevents command injection.
What is the advantage of Socket Mode for a lab bot?
The bot opens an outbound connection to the chat platform, so you do not need to expose an inbound web endpoint to the internet.
Name two controls that stop a random workspace member from using the bot against any address.
A list of authorised user IDs (and channels), and validation that targets fall inside approved IP ranges or domains.

Key takeaways

  • ChatOps makes checks and results visible to the whole team.
  • Keep the bot read-only with a fixed allow-list of commands.
  • Validate every input and never pass user text to a shell.
  • Restrict users and channels, and keep tokens out of code.
  • Log every request for audit and incident review.
Tracks your learning on this device only. See your progress on the learning paths.

About the author

Mohamed Fayas

Founder of FM TecHub. CCNA certified, with a BTEC HND in Network Engineering, and BEng (Hons) in Computer Networking and Cloud Security. He writes practical, plain-English guides on networking, security and cloud.

More about the author

Original content written by Mohamed Fayas for FM TecHub. © 2026 FM TecHub. You're welcome to share a link to this page; please don't copy the text elsewhere without permission.

Stay up to date by email

New notes, tools and security news from FM TecHub, explained simply. Free.

We only use your email to send these updates. See our privacy policy.