diff --git a/.htaccess b/.htaccess
index 2b898e7..1740af0 100644
--- a/.htaccess
+++ b/.htaccess
@@ -143,6 +143,10 @@
Header set X-Content-Type-Options "nosniff"
Header set Referrer-Policy "strict-origin-when-cross-origin"
Header set X-Frame-Options "DENY"
+ # Force HTTPS (2 years + preload) to close the first-visit SSL-strip window.
+ Header set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
+ # Restrict powerful features; camera kept for in-page QR scanning.
+ Header set Permissions-Policy "camera=(self), microphone=(), geolocation=(), payment=(), usb=(), magnetometer=(), gyroscope=(), accelerometer=()"
# Content Security Policy (frame-ancestors and report-uri only work in HTTP headers, not meta tags)
diff --git a/deploy/nginx.conf b/deploy/nginx.conf
index efb480c..082e146 100644
--- a/deploy/nginx.conf
+++ b/deploy/nginx.conf
@@ -55,6 +55,12 @@ http {
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header X-Frame-Options "DENY" always;
add_header Content-Security-Policy "frame-ancestors 'none';" always;
+ # Force HTTPS for two years and preload, closing the first-visit SSL-strip
+ # window that upgrade-insecure-requests alone does not cover.
+ add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
+ # Lock down powerful features. Camera is allowed for in-page QR scanning;
+ # microphone/geolocation and other sensors are denied outright.
+ add_header Permissions-Policy "camera=(self), microphone=(), geolocation=(), payment=(), usb=(), magnetometer=(), gyroscope=(), accelerometer=()" always;
add_header Cache-Control $sb_cache always;
add_header Service-Worker-Allowed "/" always;
diff --git a/dist/app-boot.js b/dist/app-boot.js
index e6b5f4f..e817083 100644
--- a/dist/app-boot.js
+++ b/dist/app-boot.js
@@ -7183,17 +7183,6 @@ var EnhancedSecureWebRTCManager = class _EnhancedSecureWebRTCManager {
validationResult.errors.push(`String too long: ${data.length} > ${this._inputValidationLimits.maxStringLength}`);
return validationResult;
}
- for (const pattern of this._maliciousPatterns) {
- if (pattern.test(data)) {
- validationResult.errors.push(`Malicious pattern detected: ${pattern.source}`);
- this._secureLog("warn", "\u{1F6A8} Malicious pattern detected in input", {
- context,
- pattern: pattern.source,
- dataLength: data.length
- });
- return validationResult;
- }
- }
validationResult.sanitizedData = this._sanitizeInputString(data);
validationResult.isValid = true;
return validationResult;
@@ -7275,8 +7264,9 @@ var EnhancedSecureWebRTCManager = class _EnhancedSecureWebRTCManager {
*/
_sanitizeInputString(str) {
if (typeof str !== "string") return str;
- str = str.replace(/\0/g, "");
- str = str.replace(/\s+/g, " ");
+ str = str.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g, "");
+ str = str.replace(/\r\n?/g, "\n");
+ str = str.replace(/\n{3,}/g, "\n\n");
str = str.trim();
return str;
}
@@ -7633,69 +7623,6 @@ var EnhancedSecureWebRTCManager = class _EnhancedSecureWebRTCManager {
rateLimitBurstSize: 10
// Burst size for rate limiting
};
- this._maliciousPatterns = [
- // Enhanced script tag detection that handles edge cases
- /\n /\n /
- /
- /