uplink-cli 0.1.29 → 0.1.30

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,230 @@
1
+ # Security Assessment: Phase 1 & Recommendations
2
+
3
+ **Last Updated:** January 2025
4
+ **Phase 1 Status:** ✅ Completed and deployed
5
+
6
+ ---
7
+
8
+ ## 🔒 Phase 1 Security Improvements
9
+
10
+ ### 1. **Hardened On-Demand TLS Endpoint** (`/internal/allow-tls`)
11
+ - ✅ **Secret Protection**: Requires `RELAY_INTERNAL_SECRET` (header or query param)
12
+ - ✅ **Hostname Validation**: Validates token format (`/^[a-zA-Z0-9]{3,64}$/`) and alias format (`ALIAS_REGEX`)
13
+ - ✅ **Reserved Alias Protection**: Blocks reserved aliases (`www`, `api`, `x`, `t`, etc.)
14
+ - ✅ **Database Verification**: Checks token/alias existence before allowing TLS issuance
15
+ - ✅ **Rate Limiting**: 120 requests/minute per IP (prevents enumeration/DoS)
16
+
17
+ ### 2. **System Diagnostics** (`/v1/admin/system/status`)
18
+ - ✅ **Configuration Visibility**: Detects missing `RELAY_INTERNAL_SECRET`
19
+ - ✅ **Relay Health Check**: Verifies relay connectivity and connection count
20
+ - ✅ **TLS Mode Detection**: Reports DNS-01 wildcard vs on-demand TLS status
21
+ - ✅ **No Secret Exposure**: Returns only boolean flags, never raw secrets
22
+
23
+ ### 3. **Production Security Enforcement**
24
+ - ✅ **Required Secrets**: Production fails to start without `RELAY_INTERNAL_SECRET` and `CONTROL_PLANE_TOKEN_PEPPER`
25
+ - ✅ **Token Hashing**: Uses HMAC-SHA256 with server-side pepper (prevents offline brute-force if DB leaks)
26
+ - ✅ **Environment Isolation**: Systemd services load secrets from `.env` file
27
+
28
+ ### 4. **Caddy Integration**
29
+ - ✅ **On-Demand TLS Ask Block**: Caddy validates hosts via backend before issuing certs
30
+ - ✅ **Rate Limits**: `interval 2m`, `burst 5` prevents certificate spam
31
+ - ✅ **Primary Fallback**: DNS-01 wildcard remains primary; on-demand is optional enhancement
32
+
33
+ ---
34
+
35
+ ## ✅ Existing Security Measures (Pre-Phase 1)
36
+
37
+ ### Authentication & Authorization
38
+ - ✅ **Token-Based Auth**: Bearer tokens with role-based access control (admin/user)
39
+ - ✅ **Token Revocation**: Tokens can be revoked and expire
40
+ - ✅ **Audit Logging**: All auth attempts logged (success/failure with IP)
41
+ - ✅ **Break-Glass Admin**: `ADMIN_TOKENS` env var for emergency access (deprecated in favor of DB tokens)
42
+
43
+ ### Rate Limiting
44
+ - ✅ **API Routes**: 100 requests/15min per IP
45
+ - ✅ **Auth Endpoints**: 10 attempts/15min per IP
46
+ - ✅ **Token Creation**: 20/hour per IP
47
+ - ✅ **Tunnel Creation**: 50/hour per IP
48
+ - ✅ **Signup**: 5/hour per IP (strictest)
49
+
50
+ ### Input Validation
51
+ - ✅ **Schema Validation**: Zod-based validation middleware
52
+ - ✅ **SQL Injection Protection**: Parameterized queries (via `pool.query()`)
53
+ - ✅ **Alias Validation**: Regex + reserved name checks
54
+ - ✅ **Port Validation**: Numeric range checks
55
+
56
+ ### HTTP Security
57
+ - ✅ **Helmet.js**: Security headers (X-Content-Type-Options, X-Frame-Options, HSTS, etc.)
58
+ - ✅ **Body Size Limits**: 10MB max request body
59
+ - ✅ **Compression**: Gzip/deflate with threshold
60
+ - ✅ **CORS**: Configured for public endpoints only
61
+
62
+ ### Infrastructure
63
+ - ✅ **HTTPS Only**: Caddy enforces TLS (DNS-01 wildcard certs)
64
+ - ✅ **Secret Scanning**: GitHub Actions scans for committed secrets
65
+ - ✅ **Error Handling**: Generic error messages (no stack traces in production)
66
+
67
+ ---
68
+
69
+ ## ⚠️ Remaining Security Gaps & Recommendations
70
+
71
+ ### 🔴 High Priority
72
+
73
+ #### 1. **Internal Communication Not Encrypted** ✅ Partially Addressed
74
+ **Issue**: Backend ↔ Relay communication is HTTP (not HTTPS) on localhost
75
+ **Risk**: If localhost is compromised, internal secrets could be intercepted
76
+ **Status**: ✅ **Request signing middleware implemented** (optional, can be enabled)
77
+ **Remaining Work**:
78
+ - Use HTTPS with self-signed certs for internal communication (future)
79
+ - Or use Unix domain sockets with file permissions (future)
80
+ - ✅ Request signing (HMAC) middleware available but not enforced (for Caddy compatibility)
81
+
82
+ #### 2. **Token Enumeration via `/internal/allow-tls`** ✅ Improved
83
+ **Issue**: Even with rate limiting, attackers can enumerate valid tokens by probing hostnames
84
+ **Risk**: Discover active tunnel tokens
85
+ **Status**: ✅ **Rate limit reduced from 120/min to 60/min**
86
+ **Status**: ✅ **IP allowlist added** (defaults to localhost only, configurable via `INTERNAL_IP_ALLOWLIST`)
87
+ **Remaining Work**:
88
+ - Consider progressive delays after failed attempts (future enhancement)
89
+
90
+ #### 3. **Secret in Query String** ✅ Improved
91
+ **Issue**: `RELAY_INTERNAL_SECRET` can be passed in query string (for Caddy compatibility)
92
+ **Risk**: May appear in logs, browser history, referrer headers
93
+ **Status**: ✅ **Secrets now redacted in logs** (query params, headers automatically sanitized)
94
+ **Remaining Work**:
95
+ - Prefer header-only in future (requires Caddy module support)
96
+
97
+ ### 🟡 Medium Priority
98
+
99
+ #### 4. **No Request Timeouts** ✅ Fixed
100
+ **Issue**: Long-running requests can tie up server resources
101
+ **Risk**: DoS via slow requests
102
+ **Status**: ✅ **Request timeout middleware added** (30 seconds default, 5 minutes for long operations)
103
+ **Implementation**: `backend/src/middleware/timeout.ts`
104
+
105
+ #### 5. **No Token Rotation Enforcement** ✅ Improved
106
+ **Issue**: Tokens can be long-lived without forced rotation
107
+ **Risk**: Compromised tokens remain valid indefinitely
108
+ **Status**: ✅ **Max token lifetime enforced** (90 days default, configurable via `MAX_TOKEN_LIFETIME_DAYS`)
109
+ **Status**: ✅ **Hard limit of 365 days** (never exceed 1 year)
110
+ **Remaining Work**:
111
+ - Add `uplink token rotate` command (future)
112
+ - Warn users when tokens approach expiry (future)
113
+
114
+ #### 6. **No IP Allowlisting for Internal Endpoints** ✅ Fixed
115
+ **Issue**: Internal endpoints rely solely on secret, not source IP
116
+ **Risk**: If secret leaks, any IP can access internal endpoints
117
+ **Status**: ✅ **IP allowlist middleware added** (defaults to localhost, configurable via `INTERNAL_IP_ALLOWLIST`)
118
+ **Implementation**: `backend/src/middleware/ip-allowlist.ts`
119
+ **Usage**: Supports IP addresses and CIDR ranges (e.g., `127.0.0.1,10.0.0.0/8`)
120
+
121
+ #### 7. **No Request Signing for Internal Endpoints** ✅ Implemented (Optional)
122
+ **Issue**: Internal endpoints use simple secret comparison
123
+ **Risk**: Replay attacks if secret is intercepted
124
+ **Status**: ✅ **HMAC request signing middleware implemented** (optional, not enforced for Caddy compatibility)
125
+ **Implementation**: `backend/src/middleware/request-signing.ts`
126
+ **Note**: Can be enabled for relay-to-backend communication, but Caddy may not support custom headers
127
+
128
+ ### 🟢 Low Priority
129
+
130
+ #### 8. **No CSRF Protection**
131
+ **Issue**: API-only service, but no explicit CSRF tokens
132
+ **Risk**: Low (APIs typically don't need CSRF), but worth noting
133
+ **Status**: Not needed for API-only service
134
+ **Recommendation**: Add CSRF tokens if web UI is added
135
+
136
+ #### 9. **No Per-Endpoint Request Size Limits** ✅ Fixed
137
+ **Issue**: Global 10MB limit may be too large for some endpoints
138
+ **Risk**: Memory exhaustion on large uploads
139
+ **Status**: ✅ **Per-endpoint body size limits added**
140
+ **Implementation**: `backend/src/middleware/body-size.ts`
141
+ **Usage**: Tunnel creation limited to 1MB, other endpoints can use `small` (1MB), `medium` (5MB), or `large` (50MB)
142
+
143
+ #### 10. **No Account Lockout**
144
+ **Issue**: Rate limiting prevents brute force, but no progressive delays
145
+ **Risk**: Determined attackers can still attempt over long periods
146
+ **Recommendation**: Add exponential backoff after repeated failures
147
+
148
+ #### 11. **Dev Token Still Available**
149
+ **Issue**: `AGENTCLOUD_TOKEN_DEV` works in SQLite mode
150
+ **Risk**: Low (dev-only), but could be accidentally enabled in production
151
+ **Recommendation**: Remove dev token support or require explicit `NODE_ENV=development`
152
+
153
+ ---
154
+
155
+ ## 📊 Security Posture Summary
156
+
157
+ | Category | Status | Notes |
158
+ |----------|--------|-------|
159
+ | **Authentication** | ✅ Strong | Token hashing with pepper, revocation, expiry |
160
+ | **Authorization** | ✅ Good | Role-based access control, admin/user separation |
161
+ | **Rate Limiting** | ✅ Good | Comprehensive limits on all endpoints |
162
+ | **Input Validation** | ✅ Good | Schema validation, SQL injection protection |
163
+ | **TLS/HTTPS** | ✅ Good | DNS-01 wildcard certs, on-demand TLS protected |
164
+ | **Internal Secrets** | 🟡 Moderate | Protected but could be stronger (IP allowlist, mTLS) |
165
+ | **Audit Logging** | ✅ Good | Auth attempts, token operations logged |
166
+ | **Error Handling** | ✅ Good | Generic errors, no stack traces in production |
167
+ | **Infrastructure** | 🟡 Moderate | HTTP for internal comms, no request signing |
168
+
169
+ ---
170
+
171
+ ## 🎯 Recommended Next Steps
172
+
173
+ ### ✅ Completed (Phase 2)
174
+ 1. ✅ **Reduced `/internal/allow-tls` rate limit** to 60/min (from 120/min)
175
+ 2. ✅ **Added request timeouts** (30s default, 5min for long ops)
176
+ 3. ✅ **Redacted secrets in logs** (query params, headers automatically sanitized)
177
+ 4. ✅ **Added IP allowlisting** for internal endpoints (configurable via `INTERNAL_IP_ALLOWLIST`)
178
+ 5. ✅ **Enforced token max lifetime** (90 days default, configurable via `MAX_TOKEN_LIFETIME_DAYS`)
179
+ 6. ✅ **Implemented request signing** middleware (optional, available for relay-to-backend)
180
+ 7. ✅ **Added per-endpoint body size limits** (1MB/5MB/50MB presets)
181
+
182
+ ### Short Term (Next Sprint)
183
+ 1. **Enable request signing** for relay-to-backend communication (if relay supports custom headers)
184
+ 2. **Add progressive rate limiting** (exponential backoff after repeated failures)
185
+
186
+ ### Long Term (Future Phases)
187
+ 3. **Migrate internal comms to HTTPS** (self-signed certs or mTLS)
188
+ 4. **Add token rotation CLI command** (`uplink token rotate`)
189
+ 5. **Add token expiry warnings** (notify users when tokens approach expiry)
190
+
191
+ ---
192
+
193
+ ## 🔍 How to Verify Security
194
+
195
+ ### Manual Checks
196
+ ```bash
197
+ # 1. Verify internal secret is set
198
+ curl -H "Authorization: Bearer $ADMIN_TOKEN" \
199
+ https://api.uplink.spot/v1/admin/system/status | jq '.hasInternalSecret'
200
+
201
+ # 2. Test rate limiting on /internal/allow-tls
202
+ for i in {1..130}; do
203
+ curl -s -o /dev/null -w "%{http_code}\n" \
204
+ "https://api.uplink.spot/internal/allow-tls?domain=test.x.uplink.spot"
205
+ done | sort | uniq -c
206
+
207
+ # 3. Verify security headers
208
+ curl -I https://api.uplink.spot/health | grep -i "x-content-type-options\|x-frame-options\|strict-transport-security"
209
+
210
+ # 4. Test token enumeration protection
211
+ # Should return 403 for invalid tokens, rate-limited after burst
212
+ ```
213
+
214
+ ### Automated Checks
215
+ ```bash
216
+ # Run security audit script
217
+ API_BASE=https://api.uplink.spot node scripts/security-audit.mjs
218
+ ```
219
+
220
+ ---
221
+
222
+ ## 📝 Notes
223
+
224
+ - **Phase 1 Focus**: Internal secret protection and TLS hardening
225
+ - **Current Threat Model**: Assumes localhost is trusted (backend/relay on same host)
226
+ - **Future Considerations**: Multi-host deployments may require stronger internal auth (mTLS, request signing)
227
+
228
+ ---
229
+
230
+ **Questions or concerns?** Review this document and prioritize based on your threat model and deployment architecture.
@@ -0,0 +1,169 @@
1
+ # Security Improvements - Phase 2
2
+
3
+ **Date:** January 2025
4
+ **Status:** ✅ Completed
5
+
6
+ ---
7
+
8
+ ## Overview
9
+
10
+ Phase 2 implements additional security hardening measures identified in the Phase 1 security assessment. These improvements address token enumeration, request timeouts, secret exposure in logs, IP allowlisting, request signing, token lifetime limits, and per-endpoint body size limits.
11
+
12
+ ---
13
+
14
+ ## ✅ Implemented Improvements
15
+
16
+ ### 1. **Reduced Rate Limit for `/internal/allow-tls`**
17
+ - **Before**: 120 requests/minute per IP
18
+ - **After**: 60 requests/minute per IP
19
+ - **File**: `backend/src/middleware/rate-limit.ts`
20
+ - **Impact**: Reduces token enumeration attack surface by 50%
21
+
22
+ ### 2. **Request Timeout Middleware**
23
+ - **Default**: 30 seconds for all requests
24
+ - **Long operations**: 5 minutes (for database provisioning, etc.)
25
+ - **File**: `backend/src/middleware/timeout.ts`
26
+ - **Impact**: Prevents slow-request DoS attacks
27
+
28
+ ### 3. **Secret Redaction in Logs**
29
+ - **Automatic**: Secrets, tokens, passwords redacted from all logs
30
+ - **Scope**: Query params, headers, nested objects
31
+ - **File**: `backend/src/utils/logger.ts`
32
+ - **Impact**: Prevents secret exposure in log files, even if query params contain secrets
33
+
34
+ ### 4. **IP Allowlisting for Internal Endpoints**
35
+ - **Default**: Localhost only (`127.0.0.1`, `::1`)
36
+ - **Configurable**: Via `INTERNAL_IP_ALLOWLIST` env var (comma-separated IPs or CIDR ranges)
37
+ - **File**: `backend/src/middleware/ip-allowlist.ts`
38
+ - **Usage**: `INTERNAL_IP_ALLOWLIST=127.0.0.1,10.0.0.0/8`
39
+ - **Impact**: Adds defense-in-depth for internal endpoints (even if secret leaks)
40
+
41
+ ### 5. **Request Signing Middleware (Optional)**
42
+ - **Algorithm**: HMAC-SHA256 with timestamp
43
+ - **Replay protection**: Rejects requests older than 5 minutes
44
+ - **File**: `backend/src/middleware/request-signing.ts`
45
+ - **Status**: Implemented but not enforced (for Caddy compatibility)
46
+ - **Impact**: Available for relay-to-backend communication if needed
47
+
48
+ ### 6. **Token Max Lifetime Enforcement**
49
+ - **Default**: 90 days (configurable via `MAX_TOKEN_LIFETIME_DAYS`)
50
+ - **Hard limit**: 365 days (never exceed 1 year)
51
+ - **File**: `backend/src/schemas/validation.ts`
52
+ - **Impact**: Prevents indefinitely-lived tokens, reduces risk of long-term compromise
53
+
54
+ ### 7. **Per-Endpoint Body Size Limits**
55
+ - **Small**: 1MB (tunnel creation, token operations)
56
+ - **Medium**: 5MB (database operations)
57
+ - **Large**: 50MB (file uploads, bulk data)
58
+ - **File**: `backend/src/middleware/body-size.ts`
59
+ - **Usage**: Applied to tunnel creation route (1MB limit)
60
+ - **Impact**: Prevents memory exhaustion from oversized requests
61
+
62
+ ---
63
+
64
+ ## 📝 Configuration
65
+
66
+ ### New Environment Variables
67
+
68
+ ```bash
69
+ # IP allowlist for internal endpoints (optional, defaults to localhost)
70
+ INTERNAL_IP_ALLOWLIST=127.0.0.1,10.0.0.0/8
71
+
72
+ # Max token lifetime in days (optional, defaults to 90)
73
+ MAX_TOKEN_LIFETIME_DAYS=90
74
+ ```
75
+
76
+ ### Existing Variables (Still Required)
77
+
78
+ ```bash
79
+ # Required in production
80
+ RELAY_INTERNAL_SECRET=your-secret-here
81
+ CONTROL_PLANE_TOKEN_PEPPER=your-pepper-here
82
+ ```
83
+
84
+ ---
85
+
86
+ ## 🔍 Testing
87
+
88
+ ### Verify Rate Limiting
89
+ ```bash
90
+ # Should return 429 after 60 requests in 1 minute
91
+ for i in {1..65}; do
92
+ curl -s -o /dev/null -w "%{http_code}\n" \
93
+ "https://api.uplink.spot/internal/allow-tls?domain=test.x.uplink.spot"
94
+ done | sort | uniq -c
95
+ ```
96
+
97
+ ### Verify IP Allowlisting
98
+ ```bash
99
+ # From non-localhost IP, should return 403
100
+ curl -H "x-relay-internal-secret: $RELAY_INTERNAL_SECRET" \
101
+ https://api.uplink.spot/internal/allow-tls?domain=test.x.uplink.spot
102
+ ```
103
+
104
+ ### Verify Token Lifetime Enforcement
105
+ ```bash
106
+ # Should fail with validation error if expiresInDays > 90
107
+ curl -X POST https://api.uplink.spot/v1/admin/tokens \
108
+ -H "Authorization: Bearer $ADMIN_TOKEN" \
109
+ -H "Content-Type: application/json" \
110
+ -d '{"role":"user","expiresInDays":365}'
111
+ ```
112
+
113
+ ### Verify Secret Redaction
114
+ ```bash
115
+ # Check logs - secrets should appear as "[REDACTED]"
116
+ # Query params and headers with "secret", "token", "password" are automatically redacted
117
+ ```
118
+
119
+ ---
120
+
121
+ ## 📊 Security Posture Update
122
+
123
+ | Category | Before Phase 2 | After Phase 2 |
124
+ |----------|----------------|---------------|
125
+ | **Rate Limiting** | ✅ Good | ✅ Excellent (stricter limits) |
126
+ | **Request Timeouts** | ❌ None | ✅ Implemented |
127
+ | **Secret Exposure** | 🟡 Moderate (logs) | ✅ Protected (redacted) |
128
+ | **IP Allowlisting** | ❌ None | ✅ Implemented |
129
+ | **Request Signing** | ❌ None | ✅ Available (optional) |
130
+ | **Token Lifetime** | 🟡 Moderate (no limit) | ✅ Enforced (90 days) |
131
+ | **Body Size Limits** | 🟡 Moderate (global only) | ✅ Per-endpoint limits |
132
+
133
+ ---
134
+
135
+ ## 🚀 Deployment Notes
136
+
137
+ 1. **Backward Compatible**: All changes are backward compatible
138
+ 2. **Optional Features**: IP allowlisting and request signing are optional (fail-open if not configured)
139
+ 3. **No Breaking Changes**: Existing tokens and configurations continue to work
140
+ 4. **Environment Variables**: New env vars are optional (sensible defaults provided)
141
+
142
+ ---
143
+
144
+ ## 📚 Files Changed
145
+
146
+ - `backend/src/middleware/rate-limit.ts` - Reduced rate limit
147
+ - `backend/src/middleware/timeout.ts` - New file
148
+ - `backend/src/middleware/ip-allowlist.ts` - New file
149
+ - `backend/src/middleware/request-signing.ts` - New file
150
+ - `backend/src/middleware/body-size.ts` - New file
151
+ - `backend/src/utils/logger.ts` - Added secret redaction
152
+ - `backend/src/server.ts` - Integrated new middlewares
153
+ - `backend/src/schemas/validation.ts` - Added token lifetime enforcement
154
+ - `backend/src/routes/tunnels.ts` - Applied body size limit
155
+ - `docs/SECURITY_ASSESSMENT.md` - Updated with Phase 2 status
156
+
157
+ ---
158
+
159
+ ## 🎯 Next Steps (Future Phases)
160
+
161
+ 1. **Enable request signing** for relay-to-backend (if relay supports custom headers)
162
+ 2. **Add progressive rate limiting** (exponential backoff)
163
+ 3. **Migrate internal comms to HTTPS** (self-signed certs or mTLS)
164
+ 4. **Add token rotation CLI command** (`uplink token rotate`)
165
+ 5. **Add token expiry warnings** (notify users when tokens approach expiry)
166
+
167
+ ---
168
+
169
+ **Questions?** See `docs/SECURITY_ASSESSMENT.md` for detailed security analysis.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uplink-cli",
3
- "version": "0.1.29",
3
+ "version": "0.1.30",
4
4
  "description": "Expose localhost to the internet in seconds. Interactive terminal UI, permanent custom domains, zero config. A modern ngrok alternative.",
5
5
  "keywords": [
6
6
  "tunnel",