Run q as a separate (non-root) user. If you need it to run on port 80, use authbind or iptables redirect

Do not allow that user to write to any directory or files. If you need file access, arbitrate it via IPC with another q process. Pay attention to how that process will return values via or or similar.

Firewall all ports inbound and outbound except ones explicitly used.

For any backend q processes, restrict them to localhost or a protected network (e.g. iptables --pol ipsec)

Set process limits with ulimit no larger than you need them.

Restrict input by defining at least:

If you want to allow certain IPC calls, implement only the ones you want. Trying to blacklist functions is tricky because some otherwise useful functions may have a mode that accesses the disk which may cause information leak (e.g. key). It is much easier to use a whitelist approach. Whitepaper Permissions with kdb+ has some suggestions here.

As IPC functions either receive a parse tree or a string (that you could parse yourself), make sure you check the type of the input e.g. x:$[10h=type x;parse x;x]

If you use WebSockets, define:

When handling untrusted input, consider designing your application to wrap public entrypoints with reval.

Pay attention to the fact that each WebSocket client can open up a lot of connections (200 on Mozilla, 256 for Chrome), so limit using .z.a.

Log connections and consider using fail2ban to block suspicious traffic.