From e855f5786d9e277f81e63369388bec0eb1d43fb5 Mon Sep 17 00:00:00 2001 From: UNITRONIX <36471318+UNITRONIX@users.noreply.github.com> Date: Mon, 2 Mar 2026 00:43:04 +0100 Subject: [PATCH] Add Go server and security audit; update web console Add a new betterdesk-server Go codebase (server, api, auth, db, relay, signal, metrics, audit, ratelimit, proto, tools, tests) and related deployment/migration scripts. Add a comprehensive SECURITY_AUDIT_2026-03-01 report and .gitattributes; update copilot-instructions (ALL-IN-ONE v2.4.0), README, VERSION, Dockerfiles, scripts, docker-compose and entrypoint. Large updates to web-nodejs (translations, routes, services, frontend assets and middleware) and numerous new utilities; remove legacy Flask web files and archive hbbs-patch-v2 artifacts. Prepares repository for PostgreSQL support, DB migration tooling and the new Go server as the production backend. --- .gitattributes | 45 + .github/SECURITY_AUDIT_2026-03-01.md | 676 ++ .github/copilot-instructions.md | 249 +- .github/go-server-context.md | 776 ++ .gitignore | 43 +- Dockerfile.console | 98 +- Dockerfile.hbbr | 65 +- Dockerfile.hbbs | 85 +- README.md | 2157 ++-- VERSION | 2 +- betterdesk-docker.sh | 736 +- betterdesk-server/.gitignore | 34 + betterdesk-server/DEPLOY.md | 343 + betterdesk-server/admin/server.go | 450 + betterdesk-server/admin/server_test.go | 144 + betterdesk-server/api/auth_handlers.go | 700 ++ betterdesk-server/api/server.go | 891 ++ betterdesk-server/api/server_test.go | 436 + betterdesk-server/api/token_handlers.go | 510 + betterdesk-server/audit/logger.go | 174 + betterdesk-server/audit/logger_test.go | 113 + betterdesk-server/auth/jwt.go | 123 + betterdesk-server/auth/jwt_test.go | 74 + betterdesk-server/auth/roles.go | 34 + betterdesk-server/auth/totp.go | 83 + betterdesk-server/auth/totp_test.go | 81 + betterdesk-server/codec/framing.go | 227 + betterdesk-server/codec/framing_test.go | 307 + betterdesk-server/codec/ws.go | 86 + betterdesk-server/config/config.go | 270 + betterdesk-server/config/constants.go | 61 + betterdesk-server/config/tls.go | 98 + betterdesk-server/config/tls_test.go | 281 + betterdesk-server/crypto/addr_mangle.go | 72 + betterdesk-server/crypto/addr_mangle_test.go | 158 + betterdesk-server/crypto/keys.go | 145 + betterdesk-server/crypto/keys_test.go | 169 + betterdesk-server/crypto/secure.go | 357 + betterdesk-server/db/database.go | 165 + betterdesk-server/db/open.go | 22 + betterdesk-server/db/postgres.go | 972 ++ betterdesk-server/db/sqlite.go | 973 ++ betterdesk-server/db/sqlite_test.go | 328 + betterdesk-server/deploy.sh | 529 + betterdesk-server/events/bus.go | 118 + betterdesk-server/events/bus_test.go | 122 + betterdesk-server/go.mod | 29 + betterdesk-server/go.sum | 85 + betterdesk-server/logging/logger.go | 148 + betterdesk-server/logging/logger_test.go | 94 + betterdesk-server/main.go | 380 + betterdesk-server/metrics/collector.go | 138 + betterdesk-server/metrics/collector_test.go | 64 + betterdesk-server/peer/map.go | 468 + betterdesk-server/peer/map_test.go | 457 + betterdesk-server/proto/message.pb.go | 9437 +++++++++++++++++ betterdesk-server/proto/rendezvous.pb.go | 2661 +++++ betterdesk-server/protos/message.proto | 842 ++ betterdesk-server/protos/rendezvous.proto | 238 + betterdesk-server/ratelimit/bandwidth.go | 264 + betterdesk-server/ratelimit/connlimiter.go | 60 + .../ratelimit/connlimiter_test.go | 82 + betterdesk-server/ratelimit/ip_limiter.go | 201 + .../ratelimit/ip_limiter_test.go | 156 + betterdesk-server/relay/server.go | 333 + betterdesk-server/relay/server_test.go | 178 + betterdesk-server/relay/ws.go | 154 + betterdesk-server/relay/ws_test.go | 110 + betterdesk-server/reload/handler.go | 52 + betterdesk-server/reload/handler_test.go | 75 + betterdesk-server/reload/signal_unix.go | 30 + betterdesk-server/reload/signal_windows.go | 14 + betterdesk-server/security/blocklist.go | 307 + betterdesk-server/security/blocklist_test.go | 188 + betterdesk-server/signal/handler.go | 1085 ++ betterdesk-server/signal/server.go | 736 ++ betterdesk-server/signal/ws.go | 278 + betterdesk-server/signal/ws_test.go | 229 + betterdesk-server/tools/migrate/main.go | 1733 +++ betterdesk-server/tools/setup-remote.sh | 84 + betterdesk.ps1 | 969 +- betterdesk.sh | 1345 ++- dev_modules/check_hbbs_online.py | 35 + dev_modules/check_id.py | 12 +- dev_modules/diagnose_pro_features.sh | 238 + dev_modules/patch_tcp_fix.py | 2 +- dev_modules/patch_tcp_idchange.py | 2 +- dev_modules/test_db_exports.js | 16 + docker-compose.yml | 118 +- docker-entrypoint.sh | 273 +- docs/BETTERDESK_CLIENT_ARCHITECTURE.md | 311 + docs/DOCKER_SUPPORT.md | 2 +- docs/ENTERPRISE_ROADMAP.md | 427 + docs/README.md | 4 +- hbbs-patch-v2/.gitignore | 45 - hbbs-patch-v2/BUILD.md | 388 - hbbs-patch-v2/CHANGES.md | 539 - hbbs-patch-v2/CHECKSUMS.md | 158 - hbbs-patch-v2/CONTRIBUTING.md | 261 - hbbs-patch-v2/Cargo.toml | 66 - hbbs-patch-v2/GETTING_STARTED.md | 97 - hbbs-patch-v2/INDEX.md | 260 - hbbs-patch-v2/INSTALLATION.md | 330 - hbbs-patch-v2/LICENSE | 33 - hbbs-patch-v2/QUICKSTART.md | 248 - hbbs-patch-v2/README.md | 345 - hbbs-patch-v2/SUMMARY.md | 323 - hbbs-patch-v2/TODO.md | 196 - hbbs-patch-v2/build.sh | 129 - hbbs-patch-v2/complete.sh | 107 - hbbs-patch-v2/hbbr-linux-x86_64 | Bin 3098072 -> 0 bytes hbbs-patch-v2/hbbr-windows-x86_64.exe | Bin 2881024 -> 0 bytes hbbs-patch-v2/hbbs-linux-x86_64 | Bin 9954936 -> 0 bytes hbbs-patch-v2/hbbs-windows-x86_64.exe | Bin 7654912 -> 0 bytes hbbs-patch-v2/src/database.rs | 330 - hbbs-patch-v2/src/http_api.rs | 492 - hbbs-patch-v2/src/main.rs | 75 - hbbs-patch-v2/src/peer.rs | 529 - hbbs-patch-v2/src/relay_server.rs | 696 -- hbbs-patch-v2/src/rendezvous_server.rs | 1362 --- hbbs-patch-v2/src/rendezvous_server_core.rs | 581 - scripts/legacy/docker-quickstart.sh | 2 +- web-nodejs/config/config.js | 15 +- web-nodejs/lang/de.json | 1054 ++ web-nodejs/lang/en.json | 602 +- web-nodejs/lang/es.json | 1054 ++ web-nodejs/lang/fr.json | 1054 ++ web-nodejs/lang/it.json | 1054 ++ web-nodejs/lang/nl.json | 1054 ++ web-nodejs/lang/pl.json | 602 +- web-nodejs/lang/pt.json | 1054 ++ web-nodejs/lang/zh.json | 1054 ++ web-nodejs/middleware/csrf.js | 48 +- web-nodejs/middleware/security.js | 1 + web-nodejs/middleware/wanSecurity.js | 138 +- web-nodejs/package.json | 6 + web-nodejs/public/css/device-detail.css | 986 ++ web-nodejs/public/css/pages.css | 298 + web-nodejs/public/css/registrations.css | 367 + web-nodejs/public/img/betterdesk.png | Bin 0 -> 2091667 bytes web-nodejs/public/img/betterdesk_icon.png | Bin 0 -> 2177755 bytes web-nodejs/public/js/app.js | 22 + web-nodejs/public/js/dashboard.js | 30 +- web-nodejs/public/js/deviceDetail.js | 978 ++ web-nodejs/public/js/devices.js | 41 +- web-nodejs/public/js/rdclient/client.js | 334 +- web-nodejs/public/js/rdclient/crypto.js | 33 +- web-nodejs/public/js/registrations.js | 309 + web-nodejs/public/js/settings.js | 344 +- web-nodejs/public/js/utils.js | 28 +- web-nodejs/routes/activity.routes.js | 243 + web-nodejs/routes/automation.routes.js | 483 + web-nodejs/routes/bd-api.routes.js | 326 + web-nodejs/routes/dashboard.routes.js | 84 +- web-nodejs/routes/dataguard.routes.js | 275 + web-nodejs/routes/devices.routes.js | 177 +- web-nodejs/routes/fileTransfer.routes.js | 181 + web-nodejs/routes/folders.routes.js | 6 +- web-nodejs/routes/i18n.routes.js | 5 +- web-nodejs/routes/index.js | 59 + web-nodejs/routes/inventory.routes.js | 255 + web-nodejs/routes/network.routes.js | 335 + web-nodejs/routes/registration.routes.js | 328 + web-nodejs/routes/remote.routes.js | 57 +- web-nodejs/routes/reports.routes.js | 193 + web-nodejs/routes/rustdesk-api.routes.js | 886 +- web-nodejs/routes/settings.routes.js | 196 +- web-nodejs/routes/tenants.routes.js | 285 + web-nodejs/routes/tickets.routes.js | 528 + web-nodejs/routes/users.routes.js | 9 + web-nodejs/server.js | 72 +- web-nodejs/services/alertRulesEngine.js | 137 + web-nodejs/services/authService.js | 24 +- web-nodejs/services/backupService.js | 337 + web-nodejs/services/bdRelay.js | 492 + web-nodejs/services/betterdeskApi.js | 413 + web-nodejs/services/brandingService.js | 47 +- web-nodejs/services/chatRelay.js | 297 + web-nodejs/services/database.js | 1127 +- web-nodejs/services/dbAdapter.js | 3003 ++++++ web-nodejs/services/emailService.js | 188 + web-nodejs/services/fileTransferService.js | 287 + web-nodejs/services/hbbsApi.js | 28 +- web-nodejs/services/i18nService.js | 32 + web-nodejs/services/lanDiscovery.js | 128 + web-nodejs/services/networkMonitor.js | 332 + web-nodejs/services/remoteRelay.js | 298 + web-nodejs/services/reportEngine.js | 326 + web-nodejs/services/serverBackend.js | 268 + web-nodejs/views/dashboard.ejs | 48 +- web-nodejs/views/devices.ejs | 4 +- web-nodejs/views/errors/500.ejs | 5 +- web-nodejs/views/partials/sidebar.ejs | 6 + web-nodejs/views/registrations.ejs | 88 + web-nodejs/views/remote-viewer.ejs | 504 + web-nodejs/views/settings.ejs | 192 + web/app.py | 1629 --- web/auth.py | 518 - web/betterdesk.service | 20 - web/client_generator_module.py | 443 - web/i18n.py | 493 - web/lang/en.json | 263 - web/lang/pl.json | 263 - web/requirements.txt | 8 - web/source_client_generator.py | 826 -- web/static/MATERIAL_ICONS.md | 67 - web/static/client_generator.css | 447 - web/static/client_generator.js | 555 - web/static/css/i18n.css | 166 - web/static/js/i18n.js | 331 - web/static/material-icons.woff2 | Bin 128352 -> 0 bytes web/static/script.js | 1070 -- web/static/style.css | 907 -- web/templates/client_generator.html | 2011 ---- web/templates/index.html | 1082 -- web/templates/login.html | 390 - 216 files changed, 63504 insertions(+), 21457 deletions(-) create mode 100644 .gitattributes create mode 100644 .github/SECURITY_AUDIT_2026-03-01.md create mode 100644 .github/go-server-context.md create mode 100644 betterdesk-server/.gitignore create mode 100644 betterdesk-server/DEPLOY.md create mode 100644 betterdesk-server/admin/server.go create mode 100644 betterdesk-server/admin/server_test.go create mode 100644 betterdesk-server/api/auth_handlers.go create mode 100644 betterdesk-server/api/server.go create mode 100644 betterdesk-server/api/server_test.go create mode 100644 betterdesk-server/api/token_handlers.go create mode 100644 betterdesk-server/audit/logger.go create mode 100644 betterdesk-server/audit/logger_test.go create mode 100644 betterdesk-server/auth/jwt.go create mode 100644 betterdesk-server/auth/jwt_test.go create mode 100644 betterdesk-server/auth/roles.go create mode 100644 betterdesk-server/auth/totp.go create mode 100644 betterdesk-server/auth/totp_test.go create mode 100644 betterdesk-server/codec/framing.go create mode 100644 betterdesk-server/codec/framing_test.go create mode 100644 betterdesk-server/codec/ws.go create mode 100644 betterdesk-server/config/config.go create mode 100644 betterdesk-server/config/constants.go create mode 100644 betterdesk-server/config/tls.go create mode 100644 betterdesk-server/config/tls_test.go create mode 100644 betterdesk-server/crypto/addr_mangle.go create mode 100644 betterdesk-server/crypto/addr_mangle_test.go create mode 100644 betterdesk-server/crypto/keys.go create mode 100644 betterdesk-server/crypto/keys_test.go create mode 100644 betterdesk-server/crypto/secure.go create mode 100644 betterdesk-server/db/database.go create mode 100644 betterdesk-server/db/open.go create mode 100644 betterdesk-server/db/postgres.go create mode 100644 betterdesk-server/db/sqlite.go create mode 100644 betterdesk-server/db/sqlite_test.go create mode 100644 betterdesk-server/deploy.sh create mode 100644 betterdesk-server/events/bus.go create mode 100644 betterdesk-server/events/bus_test.go create mode 100644 betterdesk-server/go.mod create mode 100644 betterdesk-server/go.sum create mode 100644 betterdesk-server/logging/logger.go create mode 100644 betterdesk-server/logging/logger_test.go create mode 100644 betterdesk-server/main.go create mode 100644 betterdesk-server/metrics/collector.go create mode 100644 betterdesk-server/metrics/collector_test.go create mode 100644 betterdesk-server/peer/map.go create mode 100644 betterdesk-server/peer/map_test.go create mode 100644 betterdesk-server/proto/message.pb.go create mode 100644 betterdesk-server/proto/rendezvous.pb.go create mode 100644 betterdesk-server/protos/message.proto create mode 100644 betterdesk-server/protos/rendezvous.proto create mode 100644 betterdesk-server/ratelimit/bandwidth.go create mode 100644 betterdesk-server/ratelimit/connlimiter.go create mode 100644 betterdesk-server/ratelimit/connlimiter_test.go create mode 100644 betterdesk-server/ratelimit/ip_limiter.go create mode 100644 betterdesk-server/ratelimit/ip_limiter_test.go create mode 100644 betterdesk-server/relay/server.go create mode 100644 betterdesk-server/relay/server_test.go create mode 100644 betterdesk-server/relay/ws.go create mode 100644 betterdesk-server/relay/ws_test.go create mode 100644 betterdesk-server/reload/handler.go create mode 100644 betterdesk-server/reload/handler_test.go create mode 100644 betterdesk-server/reload/signal_unix.go create mode 100644 betterdesk-server/reload/signal_windows.go create mode 100644 betterdesk-server/security/blocklist.go create mode 100644 betterdesk-server/security/blocklist_test.go create mode 100644 betterdesk-server/signal/handler.go create mode 100644 betterdesk-server/signal/server.go create mode 100644 betterdesk-server/signal/ws.go create mode 100644 betterdesk-server/signal/ws_test.go create mode 100644 betterdesk-server/tools/migrate/main.go create mode 100644 betterdesk-server/tools/setup-remote.sh create mode 100644 dev_modules/check_hbbs_online.py create mode 100644 dev_modules/diagnose_pro_features.sh create mode 100644 dev_modules/test_db_exports.js create mode 100644 docs/BETTERDESK_CLIENT_ARCHITECTURE.md create mode 100644 docs/ENTERPRISE_ROADMAP.md delete mode 100644 hbbs-patch-v2/.gitignore delete mode 100644 hbbs-patch-v2/BUILD.md delete mode 100644 hbbs-patch-v2/CHANGES.md delete mode 100644 hbbs-patch-v2/CHECKSUMS.md delete mode 100644 hbbs-patch-v2/CONTRIBUTING.md delete mode 100644 hbbs-patch-v2/Cargo.toml delete mode 100644 hbbs-patch-v2/GETTING_STARTED.md delete mode 100644 hbbs-patch-v2/INDEX.md delete mode 100644 hbbs-patch-v2/INSTALLATION.md delete mode 100644 hbbs-patch-v2/LICENSE delete mode 100644 hbbs-patch-v2/QUICKSTART.md delete mode 100644 hbbs-patch-v2/README.md delete mode 100644 hbbs-patch-v2/SUMMARY.md delete mode 100644 hbbs-patch-v2/TODO.md delete mode 100644 hbbs-patch-v2/build.sh delete mode 100644 hbbs-patch-v2/complete.sh delete mode 100644 hbbs-patch-v2/hbbr-linux-x86_64 delete mode 100644 hbbs-patch-v2/hbbr-windows-x86_64.exe delete mode 100644 hbbs-patch-v2/hbbs-linux-x86_64 delete mode 100644 hbbs-patch-v2/hbbs-windows-x86_64.exe delete mode 100644 hbbs-patch-v2/src/database.rs delete mode 100644 hbbs-patch-v2/src/http_api.rs delete mode 100644 hbbs-patch-v2/src/main.rs delete mode 100644 hbbs-patch-v2/src/peer.rs delete mode 100644 hbbs-patch-v2/src/relay_server.rs delete mode 100644 hbbs-patch-v2/src/rendezvous_server.rs delete mode 100644 hbbs-patch-v2/src/rendezvous_server_core.rs create mode 100644 web-nodejs/lang/de.json create mode 100644 web-nodejs/lang/es.json create mode 100644 web-nodejs/lang/fr.json create mode 100644 web-nodejs/lang/it.json create mode 100644 web-nodejs/lang/nl.json create mode 100644 web-nodejs/lang/pt.json create mode 100644 web-nodejs/lang/zh.json create mode 100644 web-nodejs/public/css/device-detail.css create mode 100644 web-nodejs/public/css/registrations.css create mode 100644 web-nodejs/public/img/betterdesk.png create mode 100644 web-nodejs/public/img/betterdesk_icon.png create mode 100644 web-nodejs/public/js/deviceDetail.js create mode 100644 web-nodejs/public/js/registrations.js create mode 100644 web-nodejs/routes/activity.routes.js create mode 100644 web-nodejs/routes/automation.routes.js create mode 100644 web-nodejs/routes/bd-api.routes.js create mode 100644 web-nodejs/routes/dataguard.routes.js create mode 100644 web-nodejs/routes/fileTransfer.routes.js create mode 100644 web-nodejs/routes/inventory.routes.js create mode 100644 web-nodejs/routes/network.routes.js create mode 100644 web-nodejs/routes/registration.routes.js create mode 100644 web-nodejs/routes/reports.routes.js create mode 100644 web-nodejs/routes/tenants.routes.js create mode 100644 web-nodejs/routes/tickets.routes.js create mode 100644 web-nodejs/services/alertRulesEngine.js create mode 100644 web-nodejs/services/backupService.js create mode 100644 web-nodejs/services/bdRelay.js create mode 100644 web-nodejs/services/betterdeskApi.js create mode 100644 web-nodejs/services/chatRelay.js create mode 100644 web-nodejs/services/dbAdapter.js create mode 100644 web-nodejs/services/emailService.js create mode 100644 web-nodejs/services/fileTransferService.js create mode 100644 web-nodejs/services/lanDiscovery.js create mode 100644 web-nodejs/services/networkMonitor.js create mode 100644 web-nodejs/services/remoteRelay.js create mode 100644 web-nodejs/services/reportEngine.js create mode 100644 web-nodejs/services/serverBackend.js create mode 100644 web-nodejs/views/registrations.ejs create mode 100644 web-nodejs/views/remote-viewer.ejs delete mode 100644 web/app.py delete mode 100644 web/auth.py delete mode 100644 web/betterdesk.service delete mode 100644 web/client_generator_module.py delete mode 100644 web/i18n.py delete mode 100644 web/lang/en.json delete mode 100644 web/lang/pl.json delete mode 100644 web/requirements.txt delete mode 100644 web/source_client_generator.py delete mode 100644 web/static/MATERIAL_ICONS.md delete mode 100644 web/static/client_generator.css delete mode 100644 web/static/client_generator.js delete mode 100644 web/static/css/i18n.css delete mode 100644 web/static/js/i18n.js delete mode 100644 web/static/material-icons.woff2 delete mode 100644 web/static/script.js delete mode 100644 web/static/style.css delete mode 100644 web/templates/client_generator.html delete mode 100644 web/templates/index.html delete mode 100644 web/templates/login.html diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..7f2e0bc6 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,45 @@ +# Auto detect text files and normalize line endings +* text=auto + +# Force LF for shell scripts and config files +*.sh text eol=lf +*.yml text eol=lf +*.yaml text eol=lf +*.json text eol=lf +*.md text eol=lf +*.go text eol=lf +*.js text eol=lf +*.ejs text eol=lf +*.css text eol=lf +*.html text eol=lf +*.py text eol=lf +*.rs text eol=lf +*.toml text eol=lf +*.sql text eol=lf +*.proto text eol=lf +Dockerfile* text eol=lf +.gitignore text eol=lf +.gitattributes text eol=lf +.env.example text eol=lf + +# Force CRLF for Windows scripts +*.ps1 text eol=crlf +*.bat text eol=crlf +*.cmd text eol=crlf + +# Binary files — do not diff or normalize +*.exe binary +*.db binary +*.sqlite3 binary +*.png binary +*.jpg binary +*.ico binary +*.woff binary +*.woff2 binary +*.ttf binary +*.eot binary + +# Linguist overrides (GitHub language detection) +*.ejs linguist-language=HTML +docs/** linguist-documentation +archive/** linguist-vendored diff --git a/.github/SECURITY_AUDIT_2026-03-01.md b/.github/SECURITY_AUDIT_2026-03-01.md new file mode 100644 index 00000000..77c5dd1f --- /dev/null +++ b/.github/SECURITY_AUDIT_2026-03-01.md @@ -0,0 +1,676 @@ +# BetterDesk Security Audit Report + +**Date:** 2026-03-01 +**Auditor:** GitHub Copilot (Claude Opus 4.5) +**Scope:** `betterdesk-server/` (Go), `web-nodejs/` (Node.js) + +--- + +## Executive Summary + +This audit identified **24 security findings** across the BetterDesk project: +- **Critical:** 2 ✅ FIXED +- **High:** 5 ✅ FIXED +- **Medium:** 10 ✅ 6 FIXED, 4 LOW RISK (accepted) +- **Low:** 7 (tracked for future work) + +Many security best practices are already in place (CSRF protection, session fixation prevention, timing-safe auth, rate limiting, SQL parameterization). The findings below represent remaining gaps or areas for improvement. + +--- + +## Remediation Status (2026-03-01) + +| ID | Severity | Description | Status | +|----|----------|-------------|--------| +| C-1 | Critical | Command Injection in pingHost() | ✅ Fixed: spawn() with args array + host validation | +| C-2 | Critical | Password Logging in main.go | ✅ Fixed: Write to secure file with 0600 perms | +| H-1 | High | SQL LIKE Injection | ✅ Fixed: escapeLikePattern() + ESCAPE clause | +| H-2 | High | Error Leakage in Go API | ✅ Fixed: writeInternalError() helper | +| H-3 | High | Error Leakage in Token Handlers | ✅ Fixed: Generic error messages + logging | +| H-4 | High | Path Traversal in i18n | ✅ Fixed: isValidLangCode() validation | +| H-5 | High | MD5 for Hash | ✅ Fixed: SHA256 | +| M-1 | Medium | XSS via innerHTML | ✅ Fixed: Utils.escapeHtml() + SVG sanitization | +| M-2 | Medium | parseInt NaN validation | ✅ Fixed: isNaN() checks added | +| M-3 | Medium | Weak Random in generateId | ✅ Fixed: crypto.randomUUID() | +| M-4 | Medium | Cookie httpOnly: false | ✅ Documented: Intentional for client-side i18n | +| M-5 | Medium | Trust Proxy Default | ✅ Fixed: Default changed to false | +| M-6 | Medium | Missing Content-Type Check | ✅ Fixed: requireJsonContentType middleware | + +--- + +## Critical Findings + +### C-1: Command Injection in Network Monitor (CRITICAL) + +**File:** [web-nodejs/services/networkMonitor.js](../web-nodejs/services/networkMonitor.js#L60-L64) +**Severity:** Critical +**Description:** The `pingHost` function passes user-controllable `host` parameter directly to shell command without sanitization. + +**Code:** +```javascript +// Line 60-62 +const cmd = isWin + ? `ping -n 1 -w ${timeoutMs} ${host}` + : `ping -c 1 -W ${timeoutSec} ${host}`; + +const start = Date.now(); +exec(cmd, { timeout: timeoutMs + 2000 }, (err, stdout) => { +``` + +**Impact:** An attacker who can control the `host` parameter can execute arbitrary system commands (e.g., `; rm -rf /` or `& calc.exe`). + +**Recommended Fix:** +```javascript +// Validate hostname/IP format before use +const validHostRegex = /^[a-zA-Z0-9][a-zA-Z0-9.-]{0,253}[a-zA-Z0-9]$/; +if (!validHostRegex.test(host) && !net.isIP(host)) { + return resolve({ success: false, rtt_ms: null, error: 'Invalid host format' }); +} +// Use spawn() with array arguments instead of exec() +const { spawn } = require('child_process'); +const args = isWin ? ['-n', '1', '-w', String(timeoutMs), host] : ['-c', '1', '-W', String(timeoutSec), host]; +const proc = spawn('ping', args); +``` + +--- + +### C-2: Initial Admin Password Logged to Console (CRITICAL) + +**File:** [betterdesk-server/main.go](../betterdesk-server/main.go#L165) +**Severity:** Critical +**Description:** When a random admin password is generated, it is printed to logs in plaintext. + +**Code:** +```go +// Line 163-165 +if cfg.InitAdminPass == "" { + log.Printf(" Password: %s", adminPass) +} else { +``` + +**Impact:** The password may be visible in: +- Docker logs (`docker logs`) +- systemd journal (`journalctl`) +- Log files if stdout is redirected +- CI/CD build logs + +**Recommended Fix:** +```go +// Write password to a secure file with restricted permissions instead +if cfg.InitAdminPass == "" { + passFile := filepath.Join(cfg.DataDir, ".init_password") + os.WriteFile(passFile, []byte(adminPass), 0600) + log.Printf(" Password written to: %s (delete after reading)", passFile) + log.Printf(" (password not shown in logs for security)") +} else { + log.Printf(" Password: *** (user-provided, not logged)") +} +``` + +--- + +## High Findings + +### H-1: SQL LIKE Pattern Injection in dbAdapter.js (HIGH) + +**File:** [web-nodejs/services/dbAdapter.js](../web-nodejs/services/dbAdapter.js#L629) +**Severity:** High +**Description:** The `getAllPeers` function in the new dbAdapter does NOT escape `%` and `_` wildcards in the search parameter, unlike `database.js` which does. + +**Code:** +```javascript +// Line 629 - dbAdapter.js (NO escape) +if (filters.search) { where += ' AND (id LIKE ? OR note LIKE ? OR "user" LIKE ?)'; const s = `%${filters.search}%`; params.push(s, s, s); } + +// Compare with database.js (CORRECT - with escape) +// Line 435 - database.js +const escaped = escapeLikePattern(filters.search); +sql += " AND (id LIKE ? ESCAPE '\\' OR user LIKE ? ESCAPE '\\' OR note LIKE ? ESCAPE '\\')"; +``` + +**Impact:** User can inject `%` or `_` wildcards to match arbitrary patterns (information disclosure through pattern matching). + +**Recommended Fix:** +```javascript +if (filters.search) { + const escaped = filters.search.replace(/[%_\\]/g, '\\$&'); + where += " AND (id LIKE ? ESCAPE '\\' OR note LIKE ? ESCAPE '\\' OR \"user\" LIKE ? ESCAPE '\\')"; + const s = `%${escaped}%`; + params.push(s, s, s); +} +``` + +Also apply to lines: 903, 1510, 2096, 2297, 2889. + +--- + +### H-2: Error Message Information Leakage in Go API (HIGH) + +**File:** [betterdesk-server/api/server.go](../betterdesk-server/api/server.go#L327) +**Severity:** High +**Description:** Internal error messages are exposed to API clients via `err.Error()`. + +**Code:** +```go +// Multiple locations including line 327, 359, 380, 403, 423, 494, 519, 559, 721, 738 +writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) +``` + +**Impact:** Internal implementation details, database errors, file paths, and system information may leak to attackers. + +**Recommended Fix:** +```go +func handleDbError(w http.ResponseWriter, err error, action string) { + // Log full error internally + log.Printf("[api] %s error: %v", action, err) + // Return generic message to client + writeJSON(w, http.StatusInternalServerError, map[string]string{ + "error": "Internal server error", + }) +} +``` + +--- + +### H-3: Error Leakage in token_handlers.go (HIGH) + +**File:** [betterdesk-server/api/token_handlers.go](../betterdesk-server/api/token_handlers.go#L87) +**Severity:** High +**Description:** Database and system errors are directly exposed via `http.Error(w, err.Error(), ...)`. + +**Code:** +```go +// Lines 87, 150, 175, 199, 229, 249, 258, 343, 391, 409, 465 +http.Error(w, err.Error(), http.StatusInternalServerError) +``` + +**Impact:** Same as H-2 - information leakage. + +**Recommended Fix:** Same pattern as H-2. + +--- + +### H-4: Path Traversal Risk in i18n Language Upload (HIGH) + +**File:** [web-nodejs/routes/i18n.routes.js](../web-nodejs/routes/i18n.routes.js#L134-L145) +**Severity:** High +**Description:** Language code derived from uploaded filename or body is used in file path without full validation. + +**Code:** +```javascript +// Line 137-146 +const meta = translations._meta; +const code = meta?.code || req.body.code || req.file.originalname.replace('.json', ''); + +if (!code || code.length < 2 || code.length > 5) { + return res.status(400).json({ + success: false, + error: 'Invalid language code' + }); +} + +const result = manager.saveLanguage(code, translations); +``` + +**Impact:** An attacker could potentially submit `../../../etc/passwd` as code (though length check provides some protection). The `saveLanguage` function uses `path.join(config.langDir, ${code}.json)` which may still be vulnerable. + +**Recommended Fix:** +```javascript +// Strict validation: only allow alphanumeric + dash, 2-5 chars +if (!/^[a-z]{2}(-[A-Z]{2})?$/.test(code)) { + return res.status(400).json({ + success: false, + error: 'Invalid language code format (use: xx or xx-XX)' + }); +} +// Also validate in saveLanguage(): +const safeName = path.basename(code); // Extra protection +const filePath = path.join(config.langDir, `${safeName}.json`); +``` + +--- + +### H-5: MD5 Used for Sysinfo Hash (HIGH) + +**File:** [web-nodejs/routes/rustdesk-api.routes.js](../web-nodejs/routes/rustdesk-api.routes.js#L323) +**Severity:** High +**Description:** MD5 is used for creating content hashes, which is cryptographically weak. + +**Code:** +```javascript +// Line 323 +const hash = require('crypto').createHash('md5') + .update(JSON.stringify(sysinfo.raw_json)) + .digest('hex') + .substring(0, 16); +``` + +**Impact:** While used only for cache invalidation (not security), MD5 is deprecated and could lead to collisions. Using a deprecated algorithm in security-critical software sets a bad precedent. + +**Recommended Fix:** +```javascript +const hash = require('crypto').createHash('sha256') + .update(JSON.stringify(sysinfo.raw_json)) + .digest('hex') + .substring(0, 32); +``` + +--- + +## Medium Findings + +### M-1: XSS Risk via innerHTML in Frontend JS (MEDIUM) + +**File:** [web-nodejs/public/js/users.js](../web-nodejs/public/js/users.js#L65) +**Severity:** Medium +**Description:** User data is rendered via template literals and innerHTML without consistent escaping. + +**Code:** +```javascript +// Line 65 - users.js +tableBody.innerHTML = users.map(user => ` +