diff options
| -rw-r--r-- | doc/security-audit-2026-03-02.md | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/doc/security-audit-2026-03-02.md b/doc/security-audit-2026-03-02.md new file mode 100644 index 0000000..1efebb3 --- /dev/null +++ b/doc/security-audit-2026-03-02.md @@ -0,0 +1,67 @@ +# Security Audit Report — Bastion Project + +**Date**: 2026-03-02 + +--- + +## CRITICAL + +| # | Issue | Location | +|---|-------|----------| +| 1 | **Plaintext database credentials committed to repo** | `ghost/.env:18-20`, `ghost/stack.env:18-20` — Passwords like `ghostuserp@ssword` and `ghostghostpasswOrd` are in version control. `.gitignore` excludes `.env` but **not** `stack.env`. | +| 2 | **Jenkins Docker socket mount (DooD)** | `jenkins/docker-compose.yaml:14` — `/var/run/docker.sock` is mounted into Jenkins. Any compromised plugin or malicious job gets **full host Docker access**, enabling container escape and root-level host compromise. | +| 3 | **Netdata: near-root host access** | `netdata/docker-compose.yaml:8-13` — `SYS_PTRACE` + `SYS_ADMIN` capabilities, `apparmor:unconfined`, `pid: host`, and Docker socket mount. This is effectively root on the host. | +| 4 | **World-readable credential files** | `ghost/.env` and `ghost/stack.env` have `0644` permissions — any local user can read the database passwords. | + +--- + +## HIGH + +| # | Issue | Location | +|---|-------|----------| +| 5 | **No security headers on any nginx server block** | `nginx/nginx.conf` — Missing `Strict-Transport-Security`, `X-Frame-Options`, `X-Content-Type-Options`, `Content-Security-Policy`, `Referrer-Policy` on all proxied services. | +| 6 | **No rate limiting** | `nginx/nginx.conf` — No `limit_req` or `limit_conn` directives anywhere. All endpoints are vulnerable to brute-force and DoS. | +| 7 | **Unpinned image tags (`:latest`)** | `git-server/Dockerfile`, `git-server/cgit/Dockerfile`, `jenkins/docker-compose.yaml` (Gerrit), `nginx/docker-compose.yaml`, `netdata/docker-compose.yaml` — All use `:latest`, risking supply-chain attacks and breaking changes. | +| 8 | **Cockpit: SSL verification disabled** | `cockpit/nginx-cockpit.conf:15` — `proxy_ssl_verify off` for the Cockpit proxy, vulnerable to MITM. | +| 9 | **SQL injection risk in DB init script** | `ghost/mysql-init-script/create-multiple-databases.sh:6-14` — Database names from env var interpolated into SQL with only backtick escaping; no input validation. | + +--- + +## MEDIUM + +| # | Issue | Location | +|---|-------|----------| +| 10 | **No resource limits on any container** | All compose files — No CPU/memory limits. A runaway process in any service can starve the host. | +| 11 | **Containers run as root** | Ghost, MySQL, Gerrit, git-server — No `user:` directive or `USER` instruction to drop privileges. | +| 12 | **SSH hardening incomplete** | `git-server/sshd_config` — `PermitRootLogin` not explicitly set to `no`, no `MaxAuthTries`, SFTP subsystem enabled (unnecessary for git-only server). | +| 13 | **Unquoted variables in shell script** | `nginx/run_certbot.sh:9-10` — `mkdir $lts_dir/...` without quotes; path injection risk. | +| 14 | **DB password in healthcheck CLI args** | `ghost/compose.yml:56` — `mysqladmin ping -p$$MYSQL_ROOT_PASSWORD` exposes the password in process listing. | +| 15 | **Public DNS for OCSP stapling** | `nginx/nginx.conf` — `resolver 8.8.8.8` with no fallback and no timeout. DNS queries leak to Google; single point of failure. | +| 16 | **No certificate auto-renewal** | `nginx/run_certbot.sh` — Manual certbot execution only. Certs will silently expire. | +| 17 | **Email address hardcoded** | `nginx/run_certbot.sh:3` — Personal email in source control. | + +--- + +## Recommended Actions + +### Immediate + +1. Rotate all database passwords on the live server +2. `chmod 600` on `.env` and `stack.env` files +3. Add `stack.env` to `.gitignore` and scrub credentials from git history (`git filter-repo`) +4. Add security headers to all nginx HTTPS server blocks + +### This week + +5. Pin all Docker images to specific version digests +6. Add `limit_req` rate limiting to nginx +7. Add resource limits (`deploy.resources.limits`) to all compose services +8. Harden `sshd_config`: set `PermitRootLogin no`, `MaxAuthTries 3`, remove SFTP subsystem + +### Short-term + +9. Evaluate alternatives to Jenkins DooD (rootless Docker, dedicated build agents, or a restricted Docker daemon) +10. Reduce Netdata capabilities — remove `SYS_ADMIN`, keep only `SYS_PTRACE` if needed, re-enable AppArmor +11. Add `user:` directives to drop root in Ghost, MySQL, and Gerrit containers +12. Set up automated certbot renewal (cron or systemd timer) +13. Validate input in `create-multiple-databases.sh` (allow only `[a-zA-Z0-9_]`) |
