This document covers the security model of genro-daemon, recommended deployment hardening, and known limitations.
By default the daemon runs without authentication, which is safe only when the network is fully trusted (loopback or a private VLAN).
For any other environment, enable HMAC signing with the -K flag or
the GNR_DAEMON_HMAC_KEY environment variable:
# CLI
gnr web daemon -K "change-me-to-a-long-random-secret"
# Environment variable
GNR_DAEMON_HMAC_KEY="change-me-to-a-long-random-secret" gnr web daemonThe same key must be supplied to every client that connects to the daemon. Requests that fail the HMAC check are rejected before any handler code runs.
Key requirements:
- Use a cryptographically random value of at least 32 bytes.
- Generate one with:
python -c "import secrets; print(secrets.token_hex(32))" - Rotate the key by restarting the daemon and all connected clients with the new value.
- Never commit the key to version control; pass it via a secret manager or environment injection.
The daemon binds to localhost:40404 by default, which is only
reachable from the same host.
If you need the daemon reachable on a private network interface, bind explicitly and restrict access at the firewall level:
gnr web daemon -H 192.168.1.10 -P 40404Never bind to 0.0.0.0 on an internet-facing interface without a
firewall rule that allows only trusted source IPs.
The daemon does not implement TLS. If the connection crosses an untrusted network (e.g., between data-centre racks, or over a VPN), wrap it with a TLS tunnel:
# Example using stunnel (server side)
[gnrd]
accept = 0.0.0.0:40405
connect = 127.0.0.1:40404
cert = /etc/stunnel/server.pemAlternatively, route traffic through WireGuard or another overlay network that provides confidentiality and mutual authentication.
Allow only trusted application servers to reach the daemon port:
# Allow trusted source
iptables -A INPUT -p tcp --dport 40404 -s 10.0.0.0/24 -j ACCEPT
# Drop everything else
iptables -A INPUT -p tcp --dport 40404 -j DROPDo not publish the daemon port to the host network unless strictly required. Use a user-defined bridge network so only co-located containers can reach it:
# docker-compose.yml
services:
daemon:
image: your-org/genro-daemon
environment:
GNR_DAEMON_HMAC_KEY: "${GNR_DAEMON_HMAC_KEY}" # injected from .env or secret manager
GNR_DAEMON_STORE: "redis://redis:6379/0"
# Do NOT add `ports:` here unless the daemon must be reachable
# from outside the compose network.
networks:
- internal
app:
image: your-org/genropy-app
environment:
GNR_DAEMON_HMAC_KEY: "${GNR_DAEMON_HMAC_KEY}"
networks:
- internal
networks:
internal:
driver: bridgeThe daemon uses pickle internally to serialise Python objects transmitted over the protocol. Pickle can execute arbitrary Python code when deserialising; a malicious or compromised client can exploit this to achieve remote code execution on the daemon process.
Mitigations in place:
- Private methods (names starting with
_) cannot be invoked remotely. - HMAC signing (when enabled) rejects unauthenticated messages before deserialisation.
Required operational controls:
- Enable HMAC signing in all non-loopback deployments.
- Restrict network access to the daemon port to trusted hosts only (firewall rules or overlay network).
- Never expose the daemon port to the public internet.
- Treat any host that can reach the daemon as a fully trusted peer.
Each site runs its worker processes under the same OS user as the daemon. There is no additional sandboxing.
Recommendations:
- Run the daemon as a dedicated low-privilege user (not root).
- Use
systemdwithProtectSystem=strict,PrivateTmp=yes, andNoNewPrivileges=yesto limit the blast radius of a compromise.
# /etc/systemd/system/genro-daemon.service (excerpt)
[Service]
User=genro
Group=genro
NoNewPrivileges=yes
ProtectSystem=strict
PrivateTmp=yes
ReadWritePaths=/var/lib/genroWhen using GNR_DAEMON_STORE=redis://...:
- Prefer a Redis instance on
127.0.0.1or a private network; never expose Redis to the public internet. - Enable Redis authentication (
requirepass) and include the password in the store URL:redis://:password@host:6379/0. - Enable TLS on the Redis connection if traffic crosses an untrusted
link:
rediss://host:6380/0. - Restrict Redis to the minimum required keyspace with ACLs.
| Secret | Where to set | How to rotate |
|---|---|---|
HMAC key (GNR_DAEMON_HMAC_KEY) |
env / secret manager | Restart daemon + all clients simultaneously |
| Redis password | store URL env var | Update URL, restart daemon |
| TLS certificates (stunnel/WireGuard) | sidecar config | Roll cert, reload sidecar |
Please report security issues privately by e-mailing the maintainers rather than opening a public issue. Include a description of the vulnerability, steps to reproduce, and the version of genro-daemon affected.