Skip to main content
Glama

Personupplysning MCP Server

REMEDIATION-GUIDE.md9.86 kB
# Personupplysning MCP Server - Remediation Guide **Date:** 2025-12-01 **Priority:** HIGH/MEDIUM issues identified in audit --- ## Quick Fix Summary ### 🔴 HIGH Priority (Fix This Week) **4 HIGH severity XSS vulnerabilities + 5 MEDIUM validation issues** **Estimated Time:** 3-4 hours total --- ## Fix #1: XSS Filter Enhancement (30 minutes) ### Issue Current XSS filter in `src/utils/validators.ts` does not detect: - `onload=` events - `onfocus=` events - SVG-based XSS - Inline JavaScript expressions ### Solution **File:** `src/utils/validators.ts` **Lines:** 52-55 **BEFORE:** ```typescript .refine( (val) => !/<script|javascript:|onerror=|onclick=/i.test(val), 'Invalid characters detected in search query' ) ``` **AFTER:** ```typescript .refine( (val) => !/(<script|javascript:|on\w+=|<iframe|<svg|<embed|<object|eval\(|atob\()/i.test(val), 'Potentially dangerous patterns detected in search query' ) ``` ### Test ```bash # Run security tests to verify fix npx tsx testing-audit/security-tests.ts ``` **Expected:** All 10 XSS tests should now pass --- ## Fix #2: Organization Number Validation (2 hours) ### Issue Luhn checksum algorithm has 4 edge cases failing: - Valid numbers rejected: `5560001712`, `556000-1712` - Invalid numbers accepted: `0000000000`, `9999999999` ### Solution Option A: Use External Library (Recommended) ```bash npm install personnummer ``` **File:** `src/utils/validators.ts` ```typescript import { personnummer } from 'personnummer'; export const OrganisationsnummerSchema = z .string() .trim() .regex(/^\d{10}$|^\d{6}-\d{4}$/, 'Invalid format') .transform((val) => val.replace(/[^0-9]/g, '')) .refine((val) => { try { // personnummer library validates Swedish org numbers return personnummer.valid(val); } catch { return false; } }, 'Invalid Swedish organization number'); ``` ### Solution Option B: Fix Luhn Algorithm Research the correct implementation for Swedish organizational numbers. The current alternating pattern may need adjustment. **Test fixtures to add:** ```typescript // Known valid org numbers (test against Bolagsverket API) const VALID_ORG_NUMBERS = [ '5560001712', // Spotify '5560743089', // IKEA '5560283201', // H&M ]; // Known invalid checksums const INVALID_ORG_NUMBERS = [ '5560001713', // Wrong checksum '0000000000', // All zeros '9999999999', // All nines ]; ``` ### Test ```bash # Run validation tests npx tsx -e " import { OrganisationsnummerSchema } from './src/utils/validators.js'; const tests = [ { input: '5560001712', expected: true }, { input: '556000-1712', expected: true }, { input: '0000000000', expected: false }, { input: '9999999999', expected: false }, ]; tests.forEach(t => { try { const result = OrganisationsnummerSchema.parse(t.input); console.log(\`✅ \${t.input}: \${t.expected ? 'PASS' : 'FAIL (should reject)'}\`); } catch (e) { console.log(\`✅ \${t.input}: \${!t.expected ? 'PASS' : 'FAIL (should accept)'}\`); } }); " ``` --- ## Fix #3: Database Query Performance (1 hour) ### Issue Local search P95 latency: 4,279ms (target: <100ms) ### Solution **Step 1: Add Full-Text Search Index** Create file: `sql/004-create-search-index.sql` ```sql -- Full-text search index for Swedish company names CREATE INDEX idx_companies_name_tsvector ON companies USING gin(to_tsvector('swedish', organisationsnamn)); -- Analyze table for optimal query planning ANALYZE companies; ``` **Step 2: Run Migration** ```bash # Connect to Supabase and run migration psql $SUPABASE_URL -f sql/004-create-search-index.sql ``` **Step 3: Update Query (Optional)** If you want to use the index explicitly: **File:** `src/services/company-data-service.ts` (line 314-318) **BEFORE:** ```typescript .or(`organisationsnamn.ilike.%${query}%,organisationsidentitet.eq.${query}`) ``` **AFTER:** ```typescript .or(`organisationsnamn.ilike.%${query}%,organisationsidentitet.eq.${query}`) // Note: Supabase will automatically use the index for ILIKE queries ``` ### Test ```bash # Run performance tests npx tsx testing-audit/performance-tests.ts ``` **Expected:** P95 should drop below 200ms (with index) --- ## Fix #4: HTTP Authentication (Optional - 2 hours) ### Issue HTTP endpoint at `/mcp` has no authentication ### Solution **Step 1: Add Environment Variable** `.env`: ```bash MCP_API_KEY=your-secure-random-key-here-min-32-chars ``` **Step 2: Add Middleware** **File:** `src/index.ts` (insert after line 757, before SSE connection) ```typescript // MCP endpoint - Supports both GET (SSE) and POST (JSON-RPC) if (req.url === '/mcp') { // Authenticate request const apiKey = req.headers['x-api-key']; const expectedKey = process.env.MCP_API_KEY; if (!expectedKey) { logger.warn('MCP_API_KEY not configured - authentication disabled'); } else if (apiKey !== expectedKey) { res.writeHead(401, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Unauthorized', message: 'Valid API key required in X-API-Key header' })); return; } // ... rest of existing code ``` **Step 3: Update Documentation** Update `README.md` with authentication instructions: ```markdown ## HTTP Transport Authentication When using HTTP transport, include your API key in the `X-API-Key` header: ```bash curl -H "X-API-Key: your-key-here" \ https://personupplysning-mcp.onrender.com/mcp ``` ``` ### Test ```bash # Test unauthorized request curl -v https://personupplysning-mcp.onrender.com/mcp # Expected: 401 Unauthorized # Test authorized request curl -v -H "X-API-Key: your-key-here" \ https://personupplysning-mcp.onrender.com/mcp # Expected: 200 OK (SSE connection) ``` --- ## Fix #5: Rate Limiting (Optional - 2 hours) ### Issue No rate limiting on HTTP endpoint ### Solution **Step 1: Install Dependency** ```bash npm install express-rate-limit ``` **Step 2: Add Rate Limiter** **File:** `src/index.ts` ```typescript import rateLimit from 'express-rate-limit'; // Add near top of file const limiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 100, // limit each IP to 100 requests per 15 minutes message: { error: 'Too many requests', message: 'Rate limit exceeded. Please try again later.', retryAfter: '15 minutes' }, standardHeaders: true, // Return rate limit info in headers legacyHeaders: false, }); ``` **Step 3: Apply to HTTP Server** ```typescript async function startHTTPServer() { const PORT = parseInt(process.env.PORT || '3000'); const HOST = process.env.HOST || '0.0.0.0'; const httpServer = http.createServer(async (req, res) => { // Apply rate limiting const rateLimitMiddleware = limiter(req, res, () => {}); if (rateLimitMiddleware === false) { return; // Rate limit exceeded, already handled by limiter } // ... rest of existing code ``` ### Test ```bash # Send 101 requests in quick succession for i in {1..101}; do curl -s -o /dev/null -w "%{http_code}\n" \ -H "X-API-Key: your-key" \ https://personupplysning-mcp.onrender.com/health done # First 100 should return 200 # 101st should return 429 (Too Many Requests) ``` --- ## Deployment Checklist ### Before Deploying Fixes - [ ] Create backup of current production code - [ ] Run all tests locally - [ ] Verify TypeScript compilation: `npm run build` - [ ] Test in development environment - [ ] Update environment variables (if adding API key) ### Deployment Steps 1. **Backup Production** ```bash mkdir -p backups/session-start/2025-12-01_pre-security-fixes cp -r src/ backups/session-start/2025-12-01_pre-security-fixes/ ``` 2. **Apply Fixes** - Fix #1: XSS filter (required) - Fix #2: Org number validation (required) - Fix #3: Database index (recommended) - Fix #4: HTTP auth (optional) - Fix #5: Rate limiting (optional) 3. **Test** ```bash npm run build npx tsx testing-audit/security-tests.ts ./testing-audit/smoke-test.sh ``` 4. **Deploy** ```bash git add . git commit -m "security: Fix XSS vulnerabilities and validation issues" git push origin main # Render will auto-deploy ``` 5. **Verify Production** ```bash curl https://personupplysning-mcp.onrender.com/health # Should return {"status":"healthy",...} ``` ### After Deployment - [ ] Monitor logs for errors - [ ] Verify cache statistics - [ ] Test search functionality - [ ] Check performance metrics - [ ] Re-run security tests against production --- ## Rollback Procedure If issues arise after deployment: ```bash # Revert to previous version git revert HEAD git push origin main # Or restore from backup cp -r backups/session-start/2025-12-01_pre-security-fixes/src/ src/ npm run build git add . git commit -m "rollback: Restore previous version" git push origin main ``` --- ## Monitoring After Fixes ### Key Metrics to Watch 1. **Error Rate** - Should remain < 1% - Watch for validation errors 2. **Response Time** - Search P95 should be < 200ms (with index) - Cache hits should be < 50ms 3. **Cache Hit Rate** - Should be > 90% after warm-up - Monitor via `get_cache_stats` tool 4. **Security Events** - Watch logs for blocked XSS attempts - Monitor invalid org number rejections ### Logging ```bash # View production logs (Render) # Dashboard → Logs # Filter for security events # Search for: "Invalid characters detected" # Search for: "Validation error" ``` --- ## Support If you encounter issues during remediation: 1. Check test output for specific failures 2. Review error logs for details 3. Verify environment variables are set 4. Ensure database migrations ran successfully 5. Test individual fixes in isolation --- **Document Version:** 1.0 **Last Updated:** 2025-12-01 **Next Review:** After all fixes deployed

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/isakskogstad/personupplysning-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server