| Version | Supported |
|---|---|
| latest (main) | ✅ |
| older tags |
Please do not open a public GitHub issue for security vulnerabilities.
Report privately via GitHub's Security Advisories or email the maintainer directly. You will receive a response within 72 hours. Confirmed vulnerabilities will be patched and disclosed publicly after a fix is available.
maude is a multi-user, networked appliance intended for trusted development environments. It is not designed as a hardened public-internet server. Threat actors considered:
- Malicious co-users on the same appliance (horizontal privilege escalation)
- Remote attackers with network access to the appliance
- Malicious input via web-term (terminal injection, path traversal)
- Supply chain threats via third-party install scripts
Exposure: HTTP port (default: 3000, routed via Traefik). Accessible to any user who can reach the host.
| Threat | Risk | Mitigation |
|---|---|---|
| Credential brute-force | Medium | SSH MaxAuthTries 5, LoginGraceTime 30; fail2ban monitors /var/log/auth.log |
| Session hijacking | Medium | UUIDs generated per-session; HTTPS recommended for production (see Traefik/appmotel config) |
| Terminal input injection (ANSI escape sequences) | Low-Medium | xterm.js handles terminal emulation; server-side shell is the user's own session |
| Path traversal via file manager | Medium | All file ops use SFTP over SSH; permissions enforced by Linux kernel |
| Username enumeration via login errors | Low | SSH auth errors are generic; timing differences are inherent to SSH protocol |
| DoS via open connections | Medium | Traefik rate limiting (100 req/s average, 50 burst) per app |
Hardening recommendations:
- Enable HTTPS (configure
BASE_DOMAIN+LETSENCRYPT_EMAILviamaude-setup) - Restrict web-term to VPN or known IP ranges using Traefik middleware
- Monitor
/var/log/auth.logand Traefik access logs
Exposure: Traefik listens on port 80 (HTTP) and optionally 443 (HTTPS). On WSL, bound to 127.0.0.1 only.
| Threat | Risk | Mitigation |
|---|---|---|
| App-to-app lateral movement | Low | Each app runs as appmotel user; apps cannot write to each other's data dirs |
| Port scanning / exposure | Medium | UFW allows only 22, 80, 443 on VM deployments |
| Traefik dashboard exposure | Low | Dashboard not enabled by default |
| Malicious app deployment | Medium | Only apps user (sudoers) can deploy; no anonymous deployment |
| HTTP (no TLS) credential interception | High on untrusted networks | Run behind a TLS terminator or enable Let's Encrypt |
| WSL host-as-server abuse | High (prevented) | Traefik binds 127.0.0.1 on WSL; cannot accept external connections |
WSL localhost restriction rationale:
When running under WSL, the Linux network stack shares the Windows host's interfaces. Binding Traefik to 127.0.0.1 prevents the developer's laptop from acting as a public hosting platform, which would expose apps to the internet without the user's knowledge.
Exposure: /usr/local/bin/mom is a setuid-root binary. Any member of the mom group can install/update packages.
| Threat | Risk | Mitigation |
|---|---|---|
| Privilege escalation via malicious package | High | mom only calls apt-get/dnf with hardcoded absolute paths; no shell execution |
| Deny list bypass | Low | Deny list uses glob matching; all package names validated against strict regex before processing |
| Group membership abuse | Medium | Only explicitly provisioned users added to mom group (via maude-adduser) |
| Environment injection (LD_PRELOAD, PATH) | Low | mom strips entire caller environment; only safe vars (PATH, LANG, proxy) passed to subprocess |
| Audit log tampering | Low | /var/log/mom.log writable only by root; syslog copy provides independent audit trail |
Hardening recommendations:
- Audit
momgroup membership regularly:getent group mom - Review
/var/log/mom.logand/etc/mom/deny.listperiodically - Consider restricting deny list to match your threat model (e.g., block
*-dev, compiler tools)
Exposure: Port 22, accessible per firewall rules.
| Threat | Risk | Mitigation |
|---|---|---|
| Root login | Prevented | PermitRootLogin no enforced in sshd_config |
| Brute-force | Medium | MaxAuthTries 5, LoginGraceTime 30, fail2ban |
| Key-based auth not default | Medium | Password auth enabled for usability; users should add ~/.ssh/authorized_keys |
| Port 22 exposure | Medium | UFW restricts to allowed sources; consider changing to a non-standard port for internet-facing VMs |
Risk: first-boot.sh downloads and executes scripts from GitHub at first boot (appmotel/install.sh).
| Threat | Risk | Mitigation |
|---|---|---|
| MITM / DNS hijack during install | Medium | curl -fsSL enforces TLS; GitHub's TLS cert is pinned by OS trust store |
| Supply chain compromise of upstream repos | Medium | Pin to a specific commit SHA instead of main for production builds |
| No integrity verification of downloaded scripts | Medium | Recommended: add SHA256 verification of downloaded install.sh |
Recommendation for hardened deployments:
# Pin to a specific commit instead of 'main':
curl -fsSL https://raw.githubusercontent.com/dirkpetersen/appmotel/<COMMIT_SHA>/install.sh \
-o /tmp/appmotel-install.sh
echo "<expected-sha256> /tmp/appmotel-install.sh" | sha256sum -cRisk: Users are prompted to install Claude Code via curl | bash.
| Threat | Risk | Mitigation |
|---|---|---|
| Malicious Claude Code binary | Low | Official Anthropic install script served over TLS |
| API key exposure in shell history | Medium | Advise users to set ANTHROPIC_API_KEY in ~/.config/maude/ rather than shell history |
| Claude Code executing malicious prompts | Varies | User responsibility; standard AI safety guidance applies |
Users are separate Linux users with standard DAC (discretionary access control).
| Capability | Isolated? |
|---|---|
| Home directory | ✅ Yes (chmod 700 default) |
| Processes | ❌ No (ps aux visible to all; by design) |
| Deployed apps (appmotel) | ❌ Apps visible to all; data in /home/appmotel/ |
| Package installation | ✅ Only via mom (group-gated) |
| Root escalation | ✅ No sudo for regular users |
Recommendation: For stronger isolation, consider running appmotel with per-user instances (future roadmap) or using Linux namespaces.
After deploying maude, consider the following:
- Run
sudo maude-setupto configure domain + Let's Encrypt (enables HTTPS) - Set a strong password for the
maudedefault user or disable password auth - Add SSH public keys to
~/.ssh/authorized_keysand disablePasswordAuthentication - Review
/etc/mom/deny.listand add packages inappropriate for your environment - For internet-facing VMs: restrict UFW to known source IPs where possible
- Enable fail2ban email alerts (edit
/etc/fail2ban/jail.local) - Rotate the default
maudepassword before sharing the appliance - Pin appmotel and web-term to specific release tags (edit
first-boot.sh) - Review users in
momgroup:getent group mom - Monitor logs:
/var/log/auth.log,/var/log/mom.log, Traefik access logs
- HTTP-only by default — TLS not configured until
maude-setupis run. Do not transmit sensitive credentials over HTTP on untrusted networks. - No Azure AD authentication — web-term uses SSH password auth. Azure AD integration is on the roadmap.
- No per-user appmotel instances — all user apps run under the shared
appmoteluser. - Process visibility — users can see each other's processes (
ps aux). This is intentional for a collaborative dev environment. - curl-pipe installs — first-boot installs appmotel via
curl | bash. Acceptable for dev environments; pin to commit SHA for production.