mastercontroller 1.3.0 → 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1056 @@
1
+ # MasterController HTTPS/TLS Security Audit
2
+
3
+ **Date:** January 2026
4
+ **Version:** v1.3.1
5
+ **Auditor:** Security Review
6
+
7
+ ---
8
+
9
+ ## Executive Summary
10
+
11
+ **Overall Security Rating:** ⚠️ **GOOD with Critical Issues**
12
+
13
+ MasterController's HTTPS/TLS implementation includes many advanced features but has several **critical security issues** that must be fixed before production deployment.
14
+
15
+ **✅ Strengths:**
16
+ - SNI (Server Name Indication) support with multiple domains
17
+ - TLS certificate live reload (zero-downtime updates)
18
+ - Secure TLS defaults (TLS 1.2+, cipher order)
19
+ - HTTP to HTTPS redirect server
20
+ - HSTS support with configurable max-age
21
+ - Security headers middleware
22
+
23
+ **❌ Critical Issues:**
24
+ 1. Missing `enableHSTS()` method (documented but not implemented)
25
+ 2. HSTS hardcoded max-age doesn't use configured value
26
+ 3. Weak TLS minimum version (should be TLS 1.3 in 2026)
27
+ 4. No cipher suite configuration by default
28
+ 5. HTTP redirect doesn't validate host header (open redirect vulnerability)
29
+ 6. Static file serving has path traversal vulnerability
30
+ 7. Error responses leak stack traces in production
31
+
32
+ ---
33
+
34
+ ## Issue #1: Missing `enableHSTS()` Method
35
+
36
+ **Severity:** 🔴 **CRITICAL**
37
+
38
+ ### Current State
39
+ ```javascript
40
+ // README.md documents this:
41
+ master.enableHSTS(); // In production HTTPS
42
+
43
+ // But the method doesn't exist in MasterControl.js!
44
+ ```
45
+
46
+ **Grep Result:**
47
+ ```bash
48
+ $ grep -n "enableHSTS\s*(" MasterControl.js
49
+ (no results - method doesn't exist)
50
+ ```
51
+
52
+ ### Issue
53
+ The README documents `master.enableHSTS()` as an API method, but it's not implemented. Users following the docs will get `TypeError: master.enableHSTS is not a function`.
54
+
55
+ ### Fix Required
56
+ Add the missing method:
57
+
58
+ ```javascript
59
+ // MasterControl.js
60
+ enableHSTS(maxAge = 31536000, includeSubDomains = true, preload = false) {
61
+ this._hstsEnabled = true;
62
+ this._hstsMaxAge = maxAge;
63
+ this._hstsIncludeSubDomains = includeSubDomains;
64
+ this._hstsPreload = preload;
65
+ }
66
+ ```
67
+
68
+ And update HSTS middleware to use these values:
69
+
70
+ ```javascript
71
+ // _registerCoreMiddleware() - line 546
72
+ $that.pipeline.use(async (ctx, next) => {
73
+ if ($that.serverProtocol === 'https' && $that._hstsEnabled) {
74
+ let hstsValue = `max-age=${$that._hstsMaxAge || 31536000}`;
75
+ if ($that._hstsIncludeSubDomains) hstsValue += '; includeSubDomains';
76
+ if ($that._hstsPreload) hstsValue += '; preload';
77
+ ctx.response.setHeader('Strict-Transport-Security', hstsValue);
78
+ }
79
+ await next();
80
+ });
81
+ ```
82
+
83
+ ---
84
+
85
+ ## Issue #2: HSTS Max-Age Ignored
86
+
87
+ **Severity:** 🟡 **MEDIUM**
88
+
89
+ ### Current State
90
+ ```javascript
91
+ // MasterControl.js:416 - TLS config sets _hstsMaxAge
92
+ this._hstsMaxAge = tlsCfg.hstsMaxAge || 15552000; // 180 days
93
+
94
+ // MasterControl.js:547 - But middleware ignores it!
95
+ ctx.response.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
96
+ // ^^^ Hardcoded to 365 days!
97
+ ```
98
+
99
+ ### Issue
100
+ Users configure HSTS max-age in their environment config, but it's ignored. The middleware always uses 31536000 (365 days).
101
+
102
+ ### Fix Required
103
+ Use the configured value:
104
+
105
+ ```javascript
106
+ let hstsValue = `max-age=${$that._hstsMaxAge || 31536000}`;
107
+ if ($that._hstsIncludeSubDomains !== false) hstsValue += '; includeSubDomains';
108
+ ctx.response.setHeader('Strict-Transport-Security', hstsValue);
109
+ ```
110
+
111
+ ---
112
+
113
+ ## Issue #3: Weak TLS Minimum Version
114
+
115
+ **Severity:** 🟡 **MEDIUM** (but will become CRITICAL in 2026)
116
+
117
+ ### Current State
118
+ ```javascript
119
+ // MasterControl.js:327 - Default to TLS 1.2
120
+ if(!credentials.minVersion){ credentials.minVersion = 'TLSv1.2'; }
121
+ ```
122
+
123
+ ### Comparison with Other Frameworks
124
+
125
+ | Framework | Default TLS Version (2026) | Recommendation |
126
+ |-----------|----------------------------|----------------|
127
+ | **Express** | Node.js default (TLS 1.2+) | TLS 1.2 minimum |
128
+ | **ASP.NET Core 8** | TLS 1.2 minimum | TLS 1.3 recommended |
129
+ | **Rails 7.1** | TLS 1.2 minimum | TLS 1.3 recommended |
130
+ | **Django 5.0** | TLS 1.2 minimum | TLS 1.3 recommended |
131
+ | **MasterController** | TLS 1.2 default | ⚠️ Should be TLS 1.3 |
132
+
133
+ ### Industry Standards (2026)
134
+ - **PCI DSS 4.0:** Requires TLS 1.2+ (TLS 1.3 recommended)
135
+ - **NIST SP 800-52 Rev. 2:** Recommends TLS 1.3
136
+ - **OWASP:** TLS 1.3 recommended, TLS 1.2 acceptable
137
+ - **Mozilla SSL Config Generator:** TLS 1.3 for "Modern" config
138
+
139
+ ### Fix Required
140
+ Update default to TLS 1.3 with fallback to TLS 1.2:
141
+
142
+ ```javascript
143
+ // MasterControl.js:327
144
+ if(!credentials.minVersion){
145
+ credentials.minVersion = 'TLSv1.3'; // Default to TLS 1.3
146
+ }
147
+
148
+ // Or make it configurable by environment:
149
+ if(!credentials.minVersion){
150
+ const isProduction = this.environmentType === 'production';
151
+ credentials.minVersion = isProduction ? 'TLSv1.3' : 'TLSv1.2';
152
+ }
153
+ ```
154
+
155
+ **Why TLS 1.3?**
156
+ - Faster handshake (1-RTT vs 2-RTT)
157
+ - Forward secrecy by default
158
+ - Removed weak ciphers
159
+ - 0-RTT resumption (performance)
160
+ - Better privacy (encrypted SNI)
161
+
162
+ ---
163
+
164
+ ## Issue #4: No Cipher Suite Configuration
165
+
166
+ **Severity:** 🟡 **MEDIUM**
167
+
168
+ ### Current State
169
+ ```javascript
170
+ // MasterControl.js:411 - Only set if provided in env
171
+ if(tlsCfg.ciphers){ options.ciphers = tlsCfg.ciphers; }
172
+ // Otherwise uses Node.js defaults (which may include weak ciphers)
173
+ ```
174
+
175
+ ### Comparison with Other Frameworks
176
+
177
+ **Express (with helmet):**
178
+ ```javascript
179
+ const helmet = require('helmet');
180
+ app.use(helmet.hsts({
181
+ maxAge: 31536000,
182
+ includeSubDomains: true,
183
+ preload: true
184
+ }));
185
+
186
+ // Cipher suite must be set manually
187
+ const server = https.createServer({
188
+ ciphers: 'ECDHE-RSA-AES256-GCM-SHA384:...',
189
+ honorCipherOrder: true
190
+ }, app);
191
+ ```
192
+
193
+ **ASP.NET Core 8:**
194
+ ```csharp
195
+ // appsettings.json
196
+ {
197
+ "Kestrel": {
198
+ "EndpointDefaults": {
199
+ "Protocols": "Http1AndHttp2AndHttp3",
200
+ "SslProtocols": ["Tls13", "Tls12"],
201
+ "CipherSuitesPolicy": {
202
+ "CipherSuites": [
203
+ "TLS_AES_256_GCM_SHA384",
204
+ "TLS_CHACHA20_POLY1305_SHA256",
205
+ "TLS_AES_128_GCM_SHA256"
206
+ ]
207
+ }
208
+ }
209
+ }
210
+ }
211
+ ```
212
+
213
+ **Rails 7.1 (with Puma):**
214
+ ```ruby
215
+ # config/puma.rb
216
+ ssl_bind '0.0.0.0', '443', {
217
+ key: 'key.pem',
218
+ cert: 'cert.pem',
219
+ ssl_cipher_filter: 'ECDHE-RSA-AES256-GCM-SHA384:...',
220
+ verify_mode: 'none'
221
+ }
222
+ ```
223
+
224
+ ### Mozilla SSL Configuration Levels
225
+
226
+ **Modern (2026 recommended):**
227
+ ```javascript
228
+ ciphers: [
229
+ 'TLS_AES_256_GCM_SHA384',
230
+ 'TLS_CHACHA20_POLY1305_SHA256',
231
+ 'TLS_AES_128_GCM_SHA256'
232
+ ].join(':')
233
+ ```
234
+
235
+ **Intermediate (broader compatibility):**
236
+ ```javascript
237
+ ciphers: [
238
+ 'TLS_AES_256_GCM_SHA384',
239
+ 'TLS_CHACHA20_POLY1305_SHA256',
240
+ 'TLS_AES_128_GCM_SHA256',
241
+ 'ECDHE-ECDSA-AES256-GCM-SHA384',
242
+ 'ECDHE-RSA-AES256-GCM-SHA384',
243
+ 'ECDHE-ECDSA-CHACHA20-POLY1305',
244
+ 'ECDHE-RSA-CHACHA20-POLY1305',
245
+ 'ECDHE-ECDSA-AES128-GCM-SHA256',
246
+ 'ECDHE-RSA-AES128-GCM-SHA256'
247
+ ].join(':')
248
+ ```
249
+
250
+ ### Fix Required
251
+
252
+ Add secure defaults:
253
+
254
+ ```javascript
255
+ // MasterControl.js:327 - After minVersion
256
+ if(!credentials.ciphers){
257
+ // Mozilla Intermediate config (2026)
258
+ credentials.ciphers = [
259
+ // TLS 1.3 ciphers
260
+ 'TLS_AES_256_GCM_SHA384',
261
+ 'TLS_CHACHA20_POLY1305_SHA256',
262
+ 'TLS_AES_128_GCM_SHA256',
263
+ // TLS 1.2 ciphers (backward compatibility)
264
+ 'ECDHE-ECDSA-AES256-GCM-SHA384',
265
+ 'ECDHE-RSA-AES256-GCM-SHA384',
266
+ 'ECDHE-ECDSA-CHACHA20-POLY1305',
267
+ 'ECDHE-RSA-CHACHA20-POLY1305',
268
+ 'ECDHE-ECDSA-AES128-GCM-SHA256',
269
+ 'ECDHE-RSA-AES128-GCM-SHA256'
270
+ ].join(':');
271
+ }
272
+ ```
273
+
274
+ ---
275
+
276
+ ## Issue #5: HTTP to HTTPS Redirect - Open Redirect Vulnerability
277
+
278
+ **Severity:** 🔴 **CRITICAL**
279
+
280
+ ### Current State
281
+ ```javascript
282
+ // MasterControl.js:348-357
283
+ startHttpToHttpsRedirect(redirectPort, bindHost){
284
+ var $that = this;
285
+ return http.createServer(function (req, res) {
286
+ try{
287
+ var host = req.headers['host'] || '';
288
+ // Force original host, just change scheme
289
+ var location = 'https://' + host + req.url;
290
+ res.statusCode = 301;
291
+ res.setHeader('Location', location);
292
+ res.end();
293
+ }catch(e){
294
+ res.statusCode = 500;
295
+ res.end();
296
+ }
297
+ }).listen(redirectPort, bindHost);
298
+ }
299
+ ```
300
+
301
+ ### Vulnerability
302
+ The `host` header is user-controlled and not validated. An attacker can exploit this:
303
+
304
+ **Attack Example:**
305
+ ```bash
306
+ # Attacker crafts malicious request
307
+ curl -H "Host: evil.com" http://example.com/login
308
+
309
+ # Server redirects to:
310
+ Location: https://evil.com/login
311
+ # User credentials sent to attacker's domain!
312
+ ```
313
+
314
+ ### Comparison with Other Frameworks
315
+
316
+ **Express (with express-force-ssl):**
317
+ ```javascript
318
+ // Validates host against allowed list
319
+ const allowedHosts = ['example.com', 'www.example.com'];
320
+ app.use((req, res, next) => {
321
+ const host = req.hostname;
322
+ if (!allowedHosts.includes(host)) {
323
+ return res.status(400).send('Invalid host');
324
+ }
325
+ if (!req.secure) {
326
+ return res.redirect(301, `https://${host}${req.url}`);
327
+ }
328
+ next();
329
+ });
330
+ ```
331
+
332
+ **ASP.NET Core 8:**
333
+ ```csharp
334
+ // Built-in HTTPS redirection validates hostname
335
+ app.UseHttpsRedirection();
336
+
337
+ // Or manual validation
338
+ app.Use(async (context, next) => {
339
+ var allowedHosts = new[] { "example.com", "www.example.com" };
340
+ var host = context.Request.Host.Host;
341
+
342
+ if (!allowedHosts.Contains(host)) {
343
+ context.Response.StatusCode = 400;
344
+ return;
345
+ }
346
+
347
+ if (!context.Request.IsHttps) {
348
+ var redirectUrl = $"https://{host}{context.Request.Path}";
349
+ context.Response.Redirect(redirectUrl, permanent: true);
350
+ return;
351
+ }
352
+
353
+ await next();
354
+ });
355
+ ```
356
+
357
+ **Rails 7.1:**
358
+ ```ruby
359
+ # config/environments/production.rb
360
+ config.force_ssl = true
361
+ config.ssl_options = {
362
+ redirect: {
363
+ exclude: ->(request) {
364
+ !['example.com', 'www.example.com'].include?(request.host)
365
+ }
366
+ }
367
+ }
368
+ ```
369
+
370
+ ### Fix Required
371
+
372
+ Add host validation:
373
+
374
+ ```javascript
375
+ startHttpToHttpsRedirect(redirectPort, bindHost, allowedHosts = []){
376
+ var $that = this;
377
+ return http.createServer(function (req, res) {
378
+ try{
379
+ var host = req.headers['host'] || '';
380
+
381
+ // CRITICAL: Validate host header to prevent open redirect
382
+ if (allowedHosts.length > 0) {
383
+ const hostname = host.split(':')[0]; // Remove port
384
+ if (!allowedHosts.includes(hostname)) {
385
+ res.statusCode = 400;
386
+ res.end('Bad Request: Invalid host');
387
+ return;
388
+ }
389
+ }
390
+
391
+ // Redirect to HTTPS
392
+ var location = 'https://' + host + req.url;
393
+ res.statusCode = 301;
394
+ res.setHeader('Location', location);
395
+ res.end();
396
+ }catch(e){
397
+ res.statusCode = 500;
398
+ res.end();
399
+ }
400
+ }).listen(redirectPort, bindHost);
401
+ }
402
+ ```
403
+
404
+ **Usage:**
405
+ ```javascript
406
+ // In production, always specify allowed hosts
407
+ const redirectServer = master.startHttpToHttpsRedirect(80, '0.0.0.0', [
408
+ 'example.com',
409
+ 'www.example.com',
410
+ 'api.example.com'
411
+ ]);
412
+ ```
413
+
414
+ ---
415
+
416
+ ## Issue #6: Static File Serving - Path Traversal Vulnerability
417
+
418
+ **Severity:** 🔴 **CRITICAL**
419
+
420
+ ### Current State
421
+ ```javascript
422
+ // MasterControl.js:482 - No path validation!
423
+ let pathname = `.${ctx.request.url}`;
424
+
425
+ fs.exists(pathname, function (exist) {
426
+ if (!exist) {
427
+ ctx.response.statusCode = 404;
428
+ ctx.response.end(`File ${pathname} not found!`);
429
+ return;
430
+ }
431
+
432
+ // Reads file without validating path!
433
+ fs.readFile(pathname, function(err, data) {
434
+ // ...
435
+ });
436
+ });
437
+ ```
438
+
439
+ ### Vulnerability
440
+ An attacker can use `../` sequences to read arbitrary files:
441
+
442
+ **Attack Example:**
443
+ ```bash
444
+ # Read /etc/passwd
445
+ curl http://example.com/../../../etc/passwd
446
+
447
+ # Read source code
448
+ curl http://example.com/../../../server.js
449
+
450
+ # Read environment files
451
+ curl http://example.com/../../../.env
452
+ ```
453
+
454
+ ### Comparison with Other Frameworks
455
+
456
+ **Express (express.static):**
457
+ ```javascript
458
+ // Built-in path traversal protection
459
+ app.use(express.static('public', {
460
+ dotfiles: 'deny', // Block .env, .git, etc.
461
+ index: false,
462
+ maxAge: '1d',
463
+ redirect: false,
464
+ setHeaders: (res, path) => {
465
+ res.setHeader('X-Content-Type-Options', 'nosniff');
466
+ }
467
+ }));
468
+
469
+ // Internally uses path normalization:
470
+ const safePath = path.normalize(requestedPath);
471
+ if (!safePath.startsWith(rootPath)) {
472
+ return res.status(403).send('Forbidden');
473
+ }
474
+ ```
475
+
476
+ **ASP.NET Core 8:**
477
+ ```csharp
478
+ // Built-in static files middleware with security
479
+ app.UseStaticFiles(new StaticFileOptions {
480
+ ServeUnknownFileTypes = false,
481
+ OnPrepareResponse = ctx => {
482
+ // Prevent path traversal
483
+ var path = ctx.File.PhysicalPath;
484
+ var root = Path.GetFullPath("wwwroot");
485
+ if (!path.StartsWith(root)) {
486
+ ctx.Context.Response.StatusCode = 403;
487
+ ctx.Context.Response.ContentLength = 0;
488
+ ctx.Context.Response.Body = Stream.Null;
489
+ }
490
+ }
491
+ });
492
+ ```
493
+
494
+ **Rails 7.1:**
495
+ ```ruby
496
+ # Built-in protection via ActionDispatch::FileHandler
497
+ config.public_file_server.enabled = true
498
+ # Automatically sanitizes paths and blocks ../ traversal
499
+ ```
500
+
501
+ ### Fix Required
502
+
503
+ Add path validation:
504
+
505
+ ```javascript
506
+ // _registerCoreMiddleware() - lines 479-507
507
+ $that.pipeline.use(async (ctx, next) => {
508
+ if (ctx.isStatic) {
509
+ let pathname = `.${ctx.request.url}`;
510
+
511
+ // CRITICAL: Prevent path traversal attacks
512
+ const path = require('path');
513
+ const publicRoot = path.resolve('.'); // Or master.root + '/public'
514
+ const requestedPath = path.resolve(pathname);
515
+
516
+ // Ensure requested path is within public root
517
+ if (!requestedPath.startsWith(publicRoot)) {
518
+ ctx.response.statusCode = 403;
519
+ ctx.response.end('Forbidden');
520
+ return;
521
+ }
522
+
523
+ // Block dotfiles (.env, .git, etc.)
524
+ const filename = path.basename(requestedPath);
525
+ if (filename.startsWith('.')) {
526
+ ctx.response.statusCode = 403;
527
+ ctx.response.end('Forbidden');
528
+ return;
529
+ }
530
+
531
+ fs.exists(requestedPath, function (exist) {
532
+ if (!exist) {
533
+ ctx.response.statusCode = 404;
534
+ ctx.response.end('Not Found');
535
+ return;
536
+ }
537
+
538
+ if (fs.statSync(requestedPath).isDirectory()) {
539
+ requestedPath += '/index.html';
540
+ }
541
+
542
+ fs.readFile(requestedPath, function(err, data) {
543
+ if (err) {
544
+ ctx.response.statusCode = 500;
545
+ ctx.response.end('Internal Server Error');
546
+ } else {
547
+ const mimeType = $that.router.findMimeType(path.extname(requestedPath));
548
+ ctx.response.setHeader('Content-Type', mimeType || 'text/plain');
549
+ ctx.response.setHeader('X-Content-Type-Options', 'nosniff');
550
+ ctx.response.end(data);
551
+ }
552
+ });
553
+ });
554
+
555
+ return; // Terminal
556
+ }
557
+
558
+ await next();
559
+ });
560
+ ```
561
+
562
+ ---
563
+
564
+ ## Issue #7: Error Responses Leak Stack Traces
565
+
566
+ **Severity:** 🟡 **MEDIUM**
567
+
568
+ ### Current State
569
+ ```javascript
570
+ // MasterControl.js:559-577 - Global error handler
571
+ $that.pipeline.useError(async (error, ctx, next) => {
572
+ logger.error({
573
+ code: 'MC_ERR_PIPELINE',
574
+ message: 'Error in middleware pipeline',
575
+ error: error.message,
576
+ stack: error.stack, // Logged (good)
577
+ path: ctx.request.url,
578
+ method: ctx.type
579
+ });
580
+
581
+ if (!ctx.response.headersSent) {
582
+ ctx.response.statusCode = 500;
583
+ ctx.response.setHeader('Content-Type', 'application/json');
584
+ ctx.response.end(JSON.stringify({
585
+ error: 'Internal Server Error',
586
+ message: process.env.NODE_ENV === 'production'
587
+ ? 'An error occurred'
588
+ : error.message // ⚠️ Leaks error details in dev
589
+ }));
590
+ }
591
+ });
592
+ ```
593
+
594
+ ### Issue
595
+ While better than many frameworks (checks NODE_ENV), it should use `master.environmentType` for consistency and never leak stack traces.
596
+
597
+ ### Comparison with Other Frameworks
598
+
599
+ **Express:**
600
+ ```javascript
601
+ app.use((err, req, res, next) => {
602
+ res.status(500);
603
+ if (process.env.NODE_ENV === 'production') {
604
+ res.json({ error: 'Internal Server Error' });
605
+ } else {
606
+ res.json({
607
+ error: err.message,
608
+ stack: err.stack // Dev only
609
+ });
610
+ }
611
+ });
612
+ ```
613
+
614
+ **ASP.NET Core 8:**
615
+ ```csharp
616
+ if (env.IsDevelopment()) {
617
+ app.UseDeveloperExceptionPage(); // Stack traces in dev
618
+ } else {
619
+ app.UseExceptionHandler("/Error"); // Generic error page in prod
620
+ }
621
+ ```
622
+
623
+ ### Fix Required
624
+
625
+ ```javascript
626
+ $that.pipeline.useError(async (error, ctx, next) => {
627
+ logger.error({
628
+ code: 'MC_ERR_PIPELINE',
629
+ message: 'Error in middleware pipeline',
630
+ error: error.message,
631
+ stack: error.stack,
632
+ path: ctx.request.url,
633
+ method: ctx.type
634
+ });
635
+
636
+ if (!ctx.response.headersSent) {
637
+ const isDev = $that.environmentType === 'development';
638
+
639
+ ctx.response.statusCode = 500;
640
+ ctx.response.setHeader('Content-Type', 'application/json');
641
+ ctx.response.end(JSON.stringify({
642
+ error: 'Internal Server Error',
643
+ ...(isDev && {
644
+ message: error.message,
645
+ stack: error.stack
646
+ })
647
+ }));
648
+ }
649
+ });
650
+ ```
651
+
652
+ ---
653
+
654
+ ## Strengths: What MasterController Does Well
655
+
656
+ ### ✅ 1. SNI (Server Name Indication) Support
657
+
658
+ **Excellent implementation!** Most Node.js frameworks require manual SNI setup.
659
+
660
+ ```javascript
661
+ // MasterControl.js:377-398 - SNI with multiple domains
662
+ var sniMap = {};
663
+ if(tlsCfg.sni && typeof tlsCfg.sni === 'object'){
664
+ for (var domain in tlsCfg.sni){
665
+ var domCreds = this._buildSecureContextFromPaths(tlsCfg.sni[domain]);
666
+ if(domCreds){
667
+ sniMap[domain] = tls.createSecureContext(domCreds);
668
+ }
669
+ }
670
+ }
671
+
672
+ options.SNICallback = function(servername, cb){
673
+ var ctx = sniMap[servername];
674
+ if(!ctx && defaultContext){ ctx = defaultContext; }
675
+ if(cb){ return cb(null, ctx); }
676
+ return ctx;
677
+ };
678
+ ```
679
+
680
+ **Comparison:**
681
+ - **Express:** Requires manual SNI setup
682
+ - **ASP.NET Core:** Built-in SNI support
683
+ - **Rails/Puma:** Requires manual configuration
684
+ - **MasterController:** ✅ Built-in, easy configuration
685
+
686
+ ### ✅ 2. TLS Certificate Live Reload
687
+
688
+ **Outstanding feature!** Zero-downtime certificate renewal.
689
+
690
+ ```javascript
691
+ // MasterControl.js:454-469 - Watch files and reload
692
+ _watchTlsFilesAndReload(desc, onChange){
693
+ var paths = [];
694
+ if(desc.keyPath){ paths.push(desc.keyPath); }
695
+ if(desc.certPath){ paths.push(desc.certPath); }
696
+ paths.forEach(function(p){
697
+ fs.watchFile(p, { interval: 5000 }, function(){
698
+ onChange();
699
+ });
700
+ });
701
+ }
702
+ ```
703
+
704
+ **Comparison:**
705
+ - **Express:** Manual restart required
706
+ - **ASP.NET Core:** Requires manual restart or IIS binding
707
+ - **Rails:** Manual restart required
708
+ - **MasterController:** ✅ Automatic reload, zero downtime
709
+
710
+ ### ✅ 3. HTTP to HTTPS Redirect Server
711
+
712
+ **Well-designed!** (But needs host validation - see Issue #5)
713
+
714
+ ```javascript
715
+ // MasterControl.js:348-363
716
+ startHttpToHttpsRedirect(redirectPort, bindHost){
717
+ return http.createServer(function (req, res) {
718
+ var location = 'https://' + host + req.url;
719
+ res.statusCode = 301;
720
+ res.setHeader('Location', location);
721
+ res.end();
722
+ }).listen(redirectPort, bindHost);
723
+ }
724
+ ```
725
+
726
+ **Comparison:**
727
+ - **Express:** Requires middleware
728
+ - **ASP.NET Core:** Built-in with `UseHttpsRedirection()`
729
+ - **Rails:** Requires `config.force_ssl`
730
+ - **MasterController:** ✅ Dedicated redirect server (good pattern)
731
+
732
+ ### ✅ 4. Security Headers Middleware
733
+
734
+ **Comprehensive implementation!**
735
+
736
+ ```javascript
737
+ // security/SecurityMiddleware.js:19-40
738
+ const SECURITY_HEADERS = {
739
+ 'X-XSS-Protection': '1; mode=block',
740
+ 'X-Frame-Options': 'SAMEORIGIN',
741
+ 'X-Content-Type-Options': 'nosniff',
742
+ 'X-DNS-Prefetch-Control': 'off',
743
+ 'Permissions-Policy': 'geolocation=(), microphone=(), camera=()',
744
+ 'Referrer-Policy': 'strict-origin-when-cross-origin',
745
+ 'X-Powered-By': ''
746
+ };
747
+ ```
748
+
749
+ **Comparison:**
750
+ - **Express:** Requires helmet package
751
+ - **ASP.NET Core:** Requires manual headers
752
+ - **Rails:** Requires secure_headers gem
753
+ - **MasterController:** ✅ Built-in, comprehensive
754
+
755
+ ---
756
+
757
+ ## Comparison Table: MasterController vs Other Frameworks
758
+
759
+ | Feature | MasterController | Express | ASP.NET Core 8 | Rails 7.1 | Django 5.0 |
760
+ |---------|------------------|---------|----------------|-----------|------------|
761
+ | **TLS Version** | TLS 1.2 (default) | Node.js default | TLS 1.2+ | TLS 1.2+ | TLS 1.2+ |
762
+ | **Cipher Suites** | None (uses Node.js) | Manual | Configurable | Manual | Manual |
763
+ | **SNI Support** | ✅ Built-in | Manual | ✅ Built-in | Manual | Manual |
764
+ | **Cert Live Reload** | ✅ Automatic | ❌ Manual restart | ❌ Manual | ❌ Manual | ❌ Manual |
765
+ | **HSTS** | ⚠️ Partial (broken) | Via helmet | ✅ Built-in | ✅ Built-in | ✅ Built-in |
766
+ | **HTTP Redirect** | ⚠️ Vulnerable | Via middleware | ✅ Built-in | ✅ Built-in | ✅ Built-in |
767
+ | **Security Headers** | ✅ Built-in | Via helmet | Manual | Via gem | Manual |
768
+ | **Path Traversal Protection** | ❌ Vulnerable | ✅ Protected | ✅ Protected | ✅ Protected | ✅ Protected |
769
+ | **HTTPS by Default** | ❌ Manual | ❌ Manual | ✅ Dev mode | ❌ Manual | ❌ Manual |
770
+ | **CSP Support** | ❌ None | Via helmet | Via middleware | Via gem | Via middleware |
771
+
772
+ **Legend:**
773
+ - ✅ **Good:** Feature exists and works correctly
774
+ - ⚠️ **Partial:** Feature exists but has issues
775
+ - ❌ **Missing:** Feature not implemented or requires manual setup
776
+
777
+ ---
778
+
779
+ ## Recommendations
780
+
781
+ ### Priority 1: Critical Fixes (Must Fix Before Production)
782
+
783
+ 1. **Add `enableHSTS()` method** - Documented API that doesn't exist
784
+ 2. **Fix HSTS max-age** - Use configured value, not hardcoded
785
+ 3. **Add host validation to HTTP redirect** - Prevent open redirect attacks
786
+ 4. **Fix path traversal vulnerability** - Validate and normalize file paths
787
+ 5. **Update TLS default to 1.3** - Align with 2026 security standards
788
+ 6. **Add secure cipher suite defaults** - Use Mozilla Intermediate config
789
+
790
+ ### Priority 2: High Priority (Recommended)
791
+
792
+ 7. **Add Content Security Policy (CSP)** - Modern XSS protection
793
+ 8. **Add rate limiting to redirector** - Prevent abuse
794
+ 9. **Improve error handling** - Use `master.environmentType` consistently
795
+ 10. **Add OCSP stapling** - Better certificate validation
796
+
797
+ ### Priority 3: Nice to Have
798
+
799
+ 11. **Add HTTP/2 push support** - Performance optimization
800
+ 12. **Add certificate expiry warnings** - Proactive monitoring
801
+ 13. **Add TLS session resumption** - Performance optimization
802
+ 14. **Add Expect-CT header** - Certificate Transparency
803
+
804
+ ---
805
+
806
+ ## Fixed Implementation Examples
807
+
808
+ ### Complete Secure HTTPS Setup
809
+
810
+ ```javascript
811
+ // MasterControl.js - Secure defaults
812
+ setupServer(type, credentials){
813
+ // ... (auto-load internal modules) ...
814
+
815
+ if(type === "https"){
816
+ $that.serverProtocol = "https";
817
+
818
+ // Initialize TLS from env if no credentials passed
819
+ if(!credentials){
820
+ $that._initializeTlsFromEnv();
821
+ credentials = $that._tlsOptions;
822
+ }
823
+
824
+ // Apply SECURE defaults (2026 standards)
825
+ if(credentials){
826
+ // TLS 1.3 by default (fallback to 1.2 for compatibility)
827
+ if(!credentials.minVersion){
828
+ credentials.minVersion = 'TLSv1.3';
829
+ }
830
+
831
+ // Secure cipher suites (Mozilla Intermediate 2026)
832
+ if(!credentials.ciphers){
833
+ credentials.ciphers = [
834
+ // TLS 1.3 ciphers
835
+ 'TLS_AES_256_GCM_SHA384',
836
+ 'TLS_CHACHA20_POLY1305_SHA256',
837
+ 'TLS_AES_128_GCM_SHA256',
838
+ // TLS 1.2 ciphers (backward compatibility)
839
+ 'ECDHE-ECDSA-AES256-GCM-SHA384',
840
+ 'ECDHE-RSA-AES256-GCM-SHA384',
841
+ 'ECDHE-ECDSA-CHACHA20-POLY1305',
842
+ 'ECDHE-RSA-CHACHA20-POLY1305',
843
+ 'ECDHE-ECDSA-AES128-GCM-SHA256',
844
+ 'ECDHE-RSA-AES128-GCM-SHA256'
845
+ ].join(':');
846
+ }
847
+
848
+ // Server prefers cipher order
849
+ if(credentials.honorCipherOrder === undefined){
850
+ credentials.honorCipherOrder = true;
851
+ }
852
+
853
+ // HTTP/2 and HTTP/1.1 support
854
+ if(!credentials.ALPNProtocols){
855
+ credentials.ALPNProtocols = ['h2', 'http/1.1'];
856
+ }
857
+
858
+ const server = https.createServer(credentials, async function(req, res) {
859
+ $that.serverRun(req, res);
860
+ });
861
+
862
+ $that.server = server;
863
+ return server;
864
+ }else{
865
+ throw new Error('HTTPS requires TLS credentials (key and cert)');
866
+ }
867
+ }
868
+ }
869
+
870
+ // Add enableHSTS() method
871
+ enableHSTS(options = {}) {
872
+ this._hstsEnabled = true;
873
+ this._hstsMaxAge = options.maxAge || 31536000; // 1 year default
874
+ this._hstsIncludeSubDomains = options.includeSubDomains !== false;
875
+ this._hstsPreload = options.preload === true;
876
+
877
+ return this; // Chainable
878
+ }
879
+
880
+ // Fix HSTS middleware
881
+ _registerCoreMiddleware(){
882
+ // ... (other middleware) ...
883
+
884
+ // HSTS Header (if enabled for HTTPS)
885
+ $that.pipeline.use(async (ctx, next) => {
886
+ if ($that.serverProtocol === 'https' && $that._hstsEnabled) {
887
+ let hstsValue = `max-age=${$that._hstsMaxAge}`;
888
+ if ($that._hstsIncludeSubDomains) hstsValue += '; includeSubDomains';
889
+ if ($that._hstsPreload) hstsValue += '; preload';
890
+ ctx.response.setHeader('Strict-Transport-Security', hstsValue);
891
+ }
892
+ await next();
893
+ });
894
+ }
895
+
896
+ // Fix HTTP to HTTPS redirect with host validation
897
+ startHttpToHttpsRedirect(redirectPort, bindHost, allowedHosts = []){
898
+ var $that = this;
899
+
900
+ return http.createServer(function (req, res) {
901
+ try{
902
+ var host = req.headers['host'] || '';
903
+ var hostname = host.split(':')[0]; // Remove port
904
+
905
+ // CRITICAL: Validate host header
906
+ if (allowedHosts.length > 0 && !allowedHosts.includes(hostname)) {
907
+ res.statusCode = 400;
908
+ res.end('Bad Request');
909
+ return;
910
+ }
911
+
912
+ // Redirect to HTTPS
913
+ var location = 'https://' + host + req.url;
914
+ res.statusCode = 301;
915
+ res.setHeader('Location', location);
916
+ res.setHeader('Cache-Control', 'no-cache');
917
+ res.end();
918
+ }catch(e){
919
+ logger.error({
920
+ code: 'MC_ERR_REDIRECT',
921
+ message: 'HTTP to HTTPS redirect failed',
922
+ error: e.message
923
+ });
924
+ res.statusCode = 500;
925
+ res.end();
926
+ }
927
+ }).listen(redirectPort, bindHost);
928
+ }
929
+ ```
930
+
931
+ ### Production-Ready Usage
932
+
933
+ ```javascript
934
+ // server.js
935
+ const master = require('mastercontroller');
936
+ const fs = require('fs');
937
+
938
+ master.environmentType = 'production';
939
+ master.root = __dirname;
940
+
941
+ // Setup HTTPS with secure defaults
942
+ const server = master.setupServer('https', {
943
+ key: fs.readFileSync('/path/to/privkey.pem'),
944
+ cert: fs.readFileSync('/path/to/fullchain.pem')
945
+ // minVersion, ciphers, etc. automatically set to secure defaults
946
+ });
947
+
948
+ // Enable HSTS for production
949
+ master.enableHSTS({
950
+ maxAge: 31536000, // 1 year
951
+ includeSubDomains: true,
952
+ preload: true // Submit to HSTS preload list
953
+ });
954
+
955
+ // Load config
956
+ require('./config/initializers/config');
957
+
958
+ // Start HTTPS server on 443
959
+ master.start(server);
960
+ master.serverSettings({ httpPort: 443 });
961
+
962
+ // Start HTTP to HTTPS redirect on port 80
963
+ const redirectServer = master.startHttpToHttpsRedirect(80, '0.0.0.0', [
964
+ 'example.com',
965
+ 'www.example.com',
966
+ 'api.example.com'
967
+ ]);
968
+
969
+ console.log('✅ HTTPS server running on port 443');
970
+ console.log('✅ HTTP redirect server running on port 80');
971
+ ```
972
+
973
+ ---
974
+
975
+ ## Testing Checklist
976
+
977
+ ### TLS/HTTPS Tests
978
+
979
+ - [ ] TLS 1.3 handshake succeeds
980
+ - [ ] TLS 1.2 handshake succeeds (backward compatibility)
981
+ - [ ] TLS 1.1 handshake fails (blocked)
982
+ - [ ] TLS 1.0 handshake fails (blocked)
983
+ - [ ] Weak ciphers rejected
984
+ - [ ] Strong ciphers accepted
985
+ - [ ] SNI routing works for multiple domains
986
+ - [ ] Certificate reload works without downtime
987
+ - [ ] HSTS header present with correct max-age
988
+ - [ ] HSTS includeSubDomains works
989
+ - [ ] HTTP to HTTPS redirect works
990
+ - [ ] Invalid host header rejected (400 Bad Request)
991
+ - [ ] Path traversal attacks blocked
992
+ - [ ] Dotfiles blocked
993
+ - [ ] Security headers present
994
+
995
+ ### Tools for Testing
996
+
997
+ **SSL Labs:**
998
+ ```bash
999
+ # Test your HTTPS configuration
1000
+ https://www.ssllabs.com/ssltest/analyze.html?d=example.com
1001
+ ```
1002
+
1003
+ **testssl.sh:**
1004
+ ```bash
1005
+ # Comprehensive TLS testing
1006
+ ./testssl.sh --full https://example.com
1007
+ ```
1008
+
1009
+ **nmap:**
1010
+ ```bash
1011
+ # Check TLS versions and ciphers
1012
+ nmap --script ssl-enum-ciphers -p 443 example.com
1013
+ ```
1014
+
1015
+ **curl:**
1016
+ ```bash
1017
+ # Test TLS 1.3
1018
+ curl -v --tlsv1.3 https://example.com
1019
+
1020
+ # Test HSTS
1021
+ curl -I https://example.com | grep Strict-Transport-Security
1022
+
1023
+ # Test redirect
1024
+ curl -I http://example.com
1025
+
1026
+ # Test path traversal
1027
+ curl http://example.com/../../../etc/passwd
1028
+
1029
+ # Test open redirect
1030
+ curl -H "Host: evil.com" http://example.com -I
1031
+ ```
1032
+
1033
+ ---
1034
+
1035
+ ## Conclusion
1036
+
1037
+ MasterController has **excellent TLS features** (SNI, certificate reload) that surpass many popular frameworks, but has **critical security vulnerabilities** that must be fixed:
1038
+
1039
+ **Must Fix:**
1040
+ 1. Path traversal vulnerability (file serving)
1041
+ 2. Open redirect vulnerability (HTTP redirect)
1042
+ 3. Missing `enableHSTS()` method
1043
+ 4. HSTS configuration ignored
1044
+ 5. Weak TLS/cipher defaults for 2026
1045
+
1046
+ **After fixes, MasterController will have:**
1047
+ - ✅ Best-in-class SNI support
1048
+ - ✅ Zero-downtime certificate reload
1049
+ - ✅ Comprehensive security headers
1050
+ - ✅ Modern TLS 1.3 defaults
1051
+ - ✅ Secure cipher suites
1052
+ - ✅ Production-ready HTTPS setup
1053
+
1054
+ **Estimated Fix Time:** 4-6 hours for all critical issues
1055
+
1056
+ **Risk Level After Fixes:** Low (production-ready)