| Severity | Count | Bedeutung | Status |
|---|---|---|---|
| CRITICAL | 2 | Active Attack-Surface ODER Data-Exfil-Risk | SOFORT-Fix vor MH-5 |
| HIGH | 6 | Pre-Mainnet-Blocker; mehrheitlich Pre-MH-5-Blocker | SEC-1b/c Mandatory |
| MEDIUM | 8 | Mitigierbar vor MH-5 ODER Mainnet | Hardening |
| LOW | 6 | Hardening-Backlog | Optional |
| INFO | 5 | Architektonische Awareness | Doku |
Verdict: NO-GO für MH-5 bis SEC-1b komplett. Begründung in §3 + §12.
Read-only Inspection aller relevanten Surface-Layer via Bash-Calls. Keine Mutation, kein Restart, keine Config-Änderung. Befunde wurden via:
ss -tlnp für Port-Inventur (Host)docker ps + docker inspect für Container-Exposure und Network-Isolationcat /etc/nginx/sites-* für Reverse-Proxy + TLS + Auth-Configpsql \du + information_schema.table_privileges für DB-Rollenstat + find für Filesystem-Permissions + Secret-Backup-Inventurcat .env für Secret-Surface (redacted output only)tail /var/log/auth.log + nginx access.log + laravel.log für aktuelle Attack-Aktivitätsystemctl is-active fail2ban + sshd_config für SSH-Hardening-Statuscurl http://127.0.0.1:<port> für Service-Identifikation (admin tools)| In Scope | Out of Scope |
|---|---|
| GUI-Exposure (Nginx, Ports, TLS, Auth, Rate-Limits) | Code-Audit der Filament-Resources (statisch, MH-5 Plan-Review-Sache) |
| Filament/Laravel-Auth (Sessions, CSRF, 2FA, Throttling) | Vulnerability-Scanner-Run (npm audit / composer audit) — kann SEC-1d sein |
| DB-User-Permissions + pg_hba | SQL-Injection-Pen-Test der Filament-Forms (MH-5 spezifisch) |
| Secrets (.env, htpasswd, Logs-Leak) | Key-Rotation-Strategie (SEC-1c) |
| Logs (Auth-Failures, Audit-Surface) | SIEM/Loki-Aggregation (SEC-1d Hardening) |
| Docker/Ops (exposed ports, watchdog, cron) | Bot-Side Python Code-Audit (separate Phase) |
Die Operator-Frage war explizit: "VOR MH-5 müssen wir die Security fertigstellen!". Das ist begründet durch:
| Aspekt | Pre-MH-5 (jetzt) | Post-MH-5 |
|---|---|---|
| Operator-Actions live | 0 (alle Phasen bisher: dormant code, kein UI-Trigger) | 6 (request/approve/reject/pause/resume/release) |
| Filament-UI-Surface | BaselineHoldings + Apply-Profile (existing) | + ManagedProposalResource + ManagedAssets Page + Approve-Wizard |
| State-File-Mutation | nicht direkt (Worker MH-6 noch nicht) | nicht direkt (Worker MH-6 immer noch nicht; aber commands queued) |
| Approver-Privilege-Theft-Impact | niedrig (nur view) | HOCH (approve = später Live-Promote-Path) |
| UI-Code-Bug-Exposure | 5 existing Filament-Resources | + 5+ neue Resources + Wizard mit Multi-Step-Logic |
MH-5 hat eigene Defense-Layer (admin-only actions, hardcoded testnet, Hard-Confirm), aber:
| Evidence |
/etc/ssh/sshd_config: PermitRootLogin yessystemctl is-active fail2ban → inactive/var/log/auth.log: aktiv um 23:55 UTC live brute-force:
May 12 23:55:54 sshd[2727994]: Failed password for root from 45.148.10.147 port 15662 ssh2 May 12 23:55:57 sshd[2728599]: Invalid user db2inst1 from 118.99.102.207 port 54350 |
|---|---|
| Risk | Server-Takeover möglich; gesamter Bot+GUI+DB-Stack kompromittierbar. Eine successful brute-force-Login = root-shell = full credential dump via /projekte/Steve-TradingBot/.env + GUI-DB + Telegram-Token + Anthropic/OpenAI Keys. |
| Erklärung | SSH ist der primäre Server-Access-Path. Default-Ubuntu lässt root-login mit Password zu. Ohne fail2ban gibt es keine IP-Throttling-Schicht. Active brute-force-Versuche von zwei verschiedenen IPs zeigen dass die IP bereits in Standard-Scan-Listen ist. |
| Recommended Fix | 1. /etc/ssh/sshd_config: PermitRootLogin prohibit-password (oder no, falls SSH-Key vorhanden)2. apt install fail2ban + ssh.local jail enabled3. UFW oder iptables IP-allowlist falls Operator nur von festen IPs zugreift 4. systemctl restart sshd |
| Phase | SEC-1b SOFORT — vor jeder weiteren Code-Phase |
| Evidence |
/projekte/Steve-TradingBot/gui/.env:
APP_ENV=local APP_DEBUG=true |
|---|---|
| Risk | Laravel zeigt bei jedem unhandled Exception:
|
| Erklärung | Laravel hat zwei Production-Sicherheits-Flags: APP_ENV + APP_DEBUG. Beide müssen production bzw false sein in Production-Deployments. Aktuell ist GUI auf local/true konfiguriert — das ist Development-Standard, NICHT Production-tauglich. |
| Recommended Fix | 1. gui/.env: APP_DEBUG=false2. gui/.env: APP_ENV=production3. docker exec steve-tradingbot-gui php artisan config:cache4. docker exec steve-tradingbot-gui php artisan view:cache |
| Phase | SEC-1b SOFORT |
| Evidence |
\du Role name | Attributes ----------------+------------------------------------------------------------ tradingbot_gui | Superuser, Create role, Create DB, Replication, Bypass RLS |
|---|---|
| Risk | App-User kann jede Tabelle ALTER, jeden Role anlegen, Replication starten — bei GUI-RCE (SQLi, deserialization, debug-disclosure) = volle DB-Kontrolle, inkl. Replikation auf externen Server (Datenexfil), audit_events-Mutation (Audit-Trail-Tampering), oder löschen. |
| Erklärung | Postgres-Best-Practice: App-User hat NUR die Privilegien die er braucht (SELECT/INSERT/UPDATE/DELETE/REFERENCES auf eigene Tabellen). SUPERUSER ist nur für Migration-Run und sollte separater User sein. |
| Recommended Fix | 1. neuen App-User anlegen: CREATE USER tradingbot_app WITH PASSWORD '...';2. GRANT SELECT,INSERT,UPDATE,DELETE,REFERENCES ON ALL TABLES IN SCHEMA public TO tradingbot_app;3. GRANT USAGE ON SCHEMA public TO tradingbot_app;4. App .env auf neuen User umstellen 5. SUPERUSER-Role auf separaten migrate-only User behalten |
| Phase | SEC-1c vor MH-5 (oder unmittelbar parallel) |
| Evidence |
docker ps: portainer 0.0.0.0:9443->9443/tcp, 0.0.0.0:8000->8000/tcpcurl https://127.0.0.1:9443 → Portainer login page
|
|---|---|
| Risk | Portainer ist Web-UI für gesamten Docker-Stack inkl. Container-Shell-Action. Bei Login-Compromise = Pivot zu Bot-Container = Bot-Live-Trading-Kontrolle, Volume-Mount-Manipulation, Image-Pull-Replace. |
| Erklärung | Portainer-Default-Listening ist 0.0.0.0:9443. Für Production sollte Portainer entweder über VPN-only, hinter Nginx-Reverse-Proxy mit Basic-Auth + Rate-Limit, oder auf localhost gebunden sein. |
| Recommended Fix | docker-compose.yml für Portainer-Service: ports: ["127.0.0.1:9443:9443"]+ Optional Nginx-Reverse-Proxy mit Basic-Auth-Layer für Remote-Access |
| Phase | SEC-1b vor MH-5 |
| Evidence |
ss -tlnp: cockpit-ws pid=1439585 listening 0.0.0.0:9090curl http://127.0.0.1:9090 → Cockpit Loading page
|
|---|---|
| Risk | Cockpit ist Linux-Admin-Web-UI mit Shell-Access. Bei Login-Compromise = root-shell des Hosts = full server-takeover, DB-Direct-Access, .env-Dump. |
| Erklärung | Cockpit ist auf vielen Ubuntu-Systemen vor-installiert. Default-Setup hat keine IP-Allowlist. Listening auf 0.0.0.0 = von überall im Internet erreichbar. |
| Recommended Fix | Cockpit-systemd-socket-config (/etc/systemd/system/cockpit.socket.d/listen.conf) auf ListenStream=127.0.0.1:9090 setzen + systemctl daemon-reload + systemctl restart cockpit.socket |
| Phase | SEC-1b vor MH-5 |
| Evidence |
docker ps: dev-wordpress-1 0.0.0.0:18080->80/tcp
|
|---|---|
| Risk | Standard-Wordpress-Installation, vermutlich nicht maintained. WordPress hat regelmäßige CVEs. Bei nicht-aktuellen Plugins = potentieller RCE-Vektor. Kompromiss erlaubt Pivot ins Docker-Network und damit zu anderen Services. |
| Erklärung | "Dev-" Prefix deutet auf Development-Container. Bleibt aber laufen seit 8 Tagen — vergessene Test-Umgebung erhöht Attack-Surface. |
| Recommended Fix | Falls WordPress nicht benötigt: docker stop dev-wordpress-1 dev-wpcli-1 dev-db-1.Falls benötigt: ports: ["127.0.0.1:18080:80"] + Plugin-Updates + WAF. |
| Phase | SEC-1b |
| Evidence |
dashboard-ssl: ssl_certificate /root/steves-tradingbot/ssl/dashboard.crt/etc/letsencrypt/live/ ist leer
|
|---|---|
| Risk | Browser-Warning desensibilisiert Operator ("Klick auf Weiter trotz Warning"). MITM auf TLS-Schicht möglich, weil Operator-Cert-Validation in der Praxis übersprungen wird. Auch für Telegram-Webhooks problematisch. |
| Erklärung | Let's Encrypt ist kostenlos und automatisierbar. Self-Signed-Certs sind nur für DEV-Tests akzeptabel; in Production untergrabbar. |
| Recommended Fix | 1. Domain für 81.169.213.37 registrieren (z.B. steve-tradingbot.example.com)2. certbot --nginx -d steve-tradingbot.example.com3. Nginx-Config auf ACME-validated cert umstellen |
| Phase | SEC-1c vor Mainnet (kein MH-5-Blocker da MH-5 testnet-only) |
| Evidence |
SELECT * FROM users: 1 row: id=23, email=admin@example.local, role=adminusers-Tabelle hat KEINE two_factor_secret, two_factor_recovery_codes, two_factor_confirmed_at Spalten.
|
|---|---|
| Risk | Password-only Auth für Operator-Action-Privilege. Approve/reject/release haben High-Impact (Live-Trading-Promote). Credential-Theft (Phishing, Keylogger, Reused-Password-Database) = full Bot-Control. |
| Erklärung | Industry-Standard für privilegierte UI-Actions ist 2FA via TOTP (Google Authenticator). Filament hat 2FA-Plugins (z.B. stechstudio/laravel-totp oder Laravel Fortify). MH-5 macht Approve-Wizard real — ohne 2FA ist Single-Password ein Single-Point-of-Failure. |
| Recommended Fix | 1. Migration für 2FA-Spalten (two_factor_secret, two_factor_recovery_codes)2. Filament-2FA-Plugin install + Konfig 3. Admin user 2FA-Enrollment-Flow 4. Filament canAccess() prüft 2FA-confirmed-at NOT NULL |
| Phase | SEC-1c vor MH-5 — MH-5 macht admin-only actions live |
| # | Sev | Finding | Risk | Fix | Phase |
|---|---|---|---|---|---|
| M1 | MED | Login-Throttling unbekannt / nicht explicit konfiguriert | Brute-Force gegen admin@example.local möglich | RateLimiter explicit in AppServiceProvider pinnen (3/min/IP + per-user-lockout 15min) + Test | SEC-1b |
| M2 | MED | .env Files 644 (world-readable) | Bei jedem non-root user-shell-access leakt secret | chmod 600 .env + zukünftige Backups mit 0600 | SEC-1b |
| M3 | MED | /srv/shares/backups/ enthält .env Kopien | Single chmod-Fehler exposed Secrets via shares-8088 autoindex (heute durch 0700 parent-dir mitigiert) | Backups außerhalb /srv/shares/ verschieben ODER .env aus Backup-Snaps löschen | SEC-1b |
| M4 | MED | Nur 1 admin mit default-haftem Email admin@example.local | Default-Account-Antipattern; Password möglicherweise schwach | Email auf real-name; Password rotieren; optional backup-admin | SEC-1c |
| M5 | MED | SESSION_ENCRYPT=false | Session-Cookies in DB klartext-lesbar bei DB-Access | SESSION_ENCRYPT=true + config:cache | SEC-1c |
| M6 | MED | HR-6 + recon24 temp-vhost-configs in sites-available/ (orphan, NICHT enabled) | Risk-of-accidental-enable; cognitive load | rm der temp-vhosts nach Phase-Closure | SEC-1d |
| M7 | MED | Worker-Container "unhealthy" Status pre-existing | Symptom-Mask: echte Outage-Detection erschwert; Watchdog respawnt regelmäßig | Healthcheck-Script im Worker-Image auf realen command_worker heartbeat anpassen | SEC-1d Ops |
| M8 | MED | Laravel.log enthält File-Path-Disclosure | Path-Disclosure für Recon (/var/www/html/storage/app/...) | Log-Level auf error; APP_DEBUG=false reduziert (siehe C2) | SEC-1b (via C2) |
| # | Finding | Fix |
|---|---|---|
| L1 | CSRF-Middleware-Setup unbekannt (Laravel 11+ Pattern hat verschoben) | bootstrap/app.php ValidateCsrfToken-config prüfen |
| L2 | dashboard-ssl proxied Bot-Dashboard (port 8050) NICHT Filament-GUI (port 8090) — möglicher Misconfig | Nginx-Routing prüfen ob Filament wirklich extern erreichbar; aktuell nur via HR-6/recon24-vhosts (orphans) |
| L3 | Sendmail-MTA listening 127.0.0.1:25 — Default Ubuntu, nicht used | systemctl disable sendmail falls nicht benötigt |
| L4 | Multiple .env backups (10+) im Repo + /srv/shares/backups/ | Lifecycle für Backups (rotation + secure storage) |
| L5 | netdata exposed auf 0.0.0.0:9080 | Bind 127.0.0.1 oder ip-allowlist |
| L6 | Sendmail-Mail-Submission auf 127.0.0.1:587 | OK as-is (localhost only) |
| # | Finding | Bedeutung |
|---|---|---|
| I1 | Public IP 81.169.213.37 | Direct-IP-Exposure; kein DNS-Hostname registriert |
| I2 | Bot port 8050 publicly exposed | Bot-internal-API extern erreichbar — Endpoint-Surface prüfen (siehe L2) |
| I3 | Multiple Docker networks isoliert | Defense-in-Depth durch network-isolation; GUI+Bot+DB+Worker im steve-tradingbot_clawbot-net |
| I4 | UFW NICHT installiert | Firewall-Layer fehlt — iptables direct, keine Chain-Inspection |
| I5 | Watchdog läuft als root via cron */5 | Akzeptabel — root-execution erforderlich (docker control) |
| Trigger | Auswirkung |
|---|---|
| C1 SSH-Brute-Force aktiv | NICHT MH-5 starten bis SSH abgesichert. Risk: Mid-Implementation-Compromise. |
| C2 APP_DEBUG=true | NICHT MH-5 starten — jeder Filament-Error leakt Stack + Pfade + DB-Queries |
| H1 DB SUPERUSER | NICHT MH-5 starten — Filament RCE = volle DB-Übernahme |
| H2 Portainer public | Independent vector — Container-Pivot zu Bot via Portainer-Shell-Action |
| H3 Cockpit-ws public | Independent vector — Server-Admin via Cookie-Theft |
| H6 Kein 2FA für Admin | MH-5 macht admin-only Actions REAL — Single-Password unzureichend |
PermitRootLogin prohibit-password + fail2ban install/enable + UFW oder iptables IP-allowlistAPP_DEBUG=false, APP_ENV=production, php artisan config:cache.env chmod 600.env-Inhalten außerhalb shares/ verschiebenSESSION_ENCRYPT=truenpm audit / composer audit)| Phase | Inhalt | SEC-Vorbedingung |
|---|---|---|
| SEC-1a ✅ jetzt | Read-only Audit (dieses Dokument) | — |
| SEC-1b nächstes | SOFORT-Fixes (C1/C2/H2/H3/H4/H6/M1/M2/M3) | SEC-1a Operator-Approval |
| MH-5 | Filament Wizard / ManagedHoldings UI | SEC-1b komplett |
| SEC-1c parallel | DB-Privs reduzieren, Let's Encrypt, Admin-Rotation, Session-Encrypt | parallel zu MH-5 erlaubt |
| MH-6 | Worker-Handler (8 CommandTypes mit Two-File-Atomic) | SEC-1b zwingend; SEC-1c bevorzugt |
| SEC-1d Hardening | Logs / Healthcheck / Security-Headers / Pen-Test | parallel oder post-MH-5 |
| MH-7 | Bot-Wiring (Restart-Pflicht; Bot-self-emit flag_managed_drift) | SEC-1c komplett; SEC-1d bevorzugt |
| MH-8 | Testnet-Drill End-to-End | SEC-1c komplett |
| MH-9 / Mainnet | Worker-Daemon Aktivierung + Mainnet-Pre-Sign-Off | SEC-1c + SEC-1d komplett + 5-Layer-Mainnet-Block verifiziert |
Nach SEC-1b Closure: memory/sec_1a_audit_findings_pin.md mit Verweis auf alle 27 Findings + Status-Tracking (offen/in-progress/closed) wäre sinnvoll.
Nach SEC-1c Closure: memory/sec_pre_mainnet_checklist.md mit allen pre-Mainnet-Pflichtfixes (H1/H5/M4/M5) als hard-gate vor MH-9.
| Item | Effort | Risk |
|---|---|---|
| C1 SSH-Hardening (sshd_config + fail2ban + iptables) | 15min | LOW (well-known) |
| C2 APP_DEBUG + APP_ENV + config:cache | 5min | LOW |
| H2 Portainer rebind to 127.0.0.1 | 15min (docker-compose edit + restart) | LOW |
| H3 Cockpit-ws rebind | 10min (systemd-override) | LOW |
| H4 dev-wordpress-1 stop oder rebind | 5min | LOW |
| H6 Filament-2FA install + Admin enroll | 60-90min | MEDIUM (Migration + Plugin-Config + Testflow) |
| M1 Login-Throttling pin + Test | 30min | LOW |
| M2 chmod 600 .env | 5min | LOW |
| M3 Backup-Secret-Cleanup | 15min | LOW |
| Total | ~2.5-3h | MEDIUM (H6 ist Hauptaufwand) |
Backup-Pflicht vor SEC-1b: pg_dump + cp /etc/ssh/sshd_config + cp docker-compose.yml + cp gui/.env als Rollback-Punkte.
Begründung:
| Aspekt | Bewertung |
|---|---|
| C1 SSH-Attack-in-Progress | LIVE attack; mid-implementation-compromise-risk acute |
| C2 APP_DEBUG=true | Jeder MH-5 Filament-Bug leakt Stack — MH-5 hat viel neuen Filament-Code = viele potentielle Errors |
| H6 Kein 2FA + admin-only actions | MH-5 macht approve/reject/release Live-Path real — Single-Factor unzureichend |
| H1 DB SUPERUSER + MH-5 Wizard mit DB-Reads | Erhöhtes Risiko bei SQL-Injection-Vektor in Filament-Form |
SEC-1b (Pre-MH-5 Mandatory)
├─ SSH-Hardening + fail2ban + UFW
├─ APP_DEBUG=false + config:cache
├─ Portainer/Cockpit/Dev-WP localhost-bind
├─ Filament-2FA + admin enrollment
├─ Login-Throttling explicit
├─ .env chmod 600
└─ Backups mit Secrets aus /srv/shares/ raus
↓
[GO MH-5 wird hier möglich]
↓
SEC-1c parallel zu MH-5 (DB-Privs / SSL / Admin / Session-Encrypt)
↓
SEC-1d Hardening-Backlog (post-MH-5)
↓
[GO Mainnet wird hier möglich, alle SEC-1c + Mainnet-Pre-Conditions]