summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/security-audit-2026-03-02.md67
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_]`)