5.8 KiB
🚨 CRITICAL SITE ISOLATION BUG FIX
Issue Summary
Severity: CRITICAL
Date: November 22, 2025
Reporter: User
Status: FIXED ✅
Problem Description
All sites in the application (sites 5, 10, 14, 15) were showing IDENTICAL integration settings and content types. This is a critical data isolation bug where:
- Site 5 (homeg8.com) integration data was being shown for ALL sites
- Sites 10, 14, and 15 were displaying the SAME content types and sync data as site 5
- This violates fundamental data isolation principles and could lead to:
- Data leakage between different sites
- Incorrect content being synced to wrong sites
- Security and privacy concerns
Root Cause Analysis
Backend Issue
In igny8/backend/igny8_core/api/base.py, the SiteSectorModelViewSet.get_queryset() method was checking for site_id query parameter:
site_id = query_params.get('site_id') # Line 268
Frontend Issue
In igny8/frontend/src/services/integration.api.ts, the getSiteIntegrations() method was passing site (not site_id):
const response = await fetchAPI(`/v1/integration/integrations/?site=${siteId}`); // Line 37
The Bug
Parameter Mismatch:
- Frontend sends:
?site=5 - Backend expects:
?site_id=5 - Result: Backend IGNORES the site filter and returns ALL integrations for ALL sites!
This meant:
- When site 5 requests integrations, it gets ALL integrations
- When site 10 requests integrations, it gets ALL integrations
- When site 14 requests integrations, it gets ALL integrations
- Since they all return the first WordPress integration (integration ID 1), all sites display the SAME data
The Fix
File Modified
igny8/backend/igny8_core/api/base.py (Lines 261-272)
Change Made
Updated the query parameter check to accept BOTH site_id and site:
# OLD CODE (BROKEN):
site_id = query_params.get('site_id')
# NEW CODE (FIXED):
site_id = query_params.get('site_id') or query_params.get('site')
This ensures backwards compatibility and proper filtering regardless of which parameter is used.
Why This Fix Works
- Accepts both parameters: Now works with
?site=5OR?site_id=5 - Proper isolation: Each site now only sees its OWN integrations
- No breaking changes: Existing code using
site_idcontinues to work - Fixes the frontend: The existing frontend code now works correctly
Impact
Before Fix (BROKEN)
GET /api/v1/integration/integrations/?site=5
→ Returns ALL integrations (no filtering)
→ Site 5 sees integration ID 1 (homeg8.com)
GET /api/v1/integration/integrations/?site=10
→ Returns ALL integrations (no filtering)
→ Site 10 ALSO sees integration ID 1 (homeg8.com) ❌
After Fix (CORRECT)
GET /api/v1/integration/integrations/?site=5
→ Returns ONLY site 5's integrations
→ Site 5 sees its OWN integration
GET /api/v1/integration/integrations/?site=10
→ Returns ONLY site 10's integrations
→ Site 10 sees its OWN integration ✅
Testing Steps
-
Verify site isolation:
# Site 5 curl "https://app.igny8.com/api/v1/integration/integrations/?site=5" # Should return ONLY site 5 integrations # Site 10 curl "https://app.igny8.com/api/v1/integration/integrations/?site=10" # Should return ONLY site 10 integrations (different from site 5) -
Check content types:
- Navigate to https://app.igny8.com/sites/5/settings?tab=content-types
- Navigate to https://app.igny8.com/sites/10/settings?tab=content-types
- Verify they show DIFFERENT data (not the same)
-
Check integration tab:
- Navigate to https://app.igny8.com/sites/5/settings?tab=integrations
- Navigate to https://app.igny8.com/sites/10/settings?tab=integrations
- Verify they show DIFFERENT API keys and settings
Deployment Instructions
Backend Deployment
cd igny8/backend
# Deploy the updated base.py file
# Restart Django server
python manage.py collectstatic --no-input
systemctl restart igny8-backend # Or your deployment method
No Frontend Changes Needed
The frontend code is already correct and will work once the backend is deployed.
Post-Deployment Verification
- Clear browser cache
- Test all URLs mentioned in "Testing Steps"
- Verify each site shows its own unique data
Security Implications
Data Leakage Risk (BEFORE FIX)
- ❌ Site A could see Site B's integration data
- ❌ Site A could trigger syncs that affect Site B
- ❌ Content from Site A could be pushed to Site B
- ❌ API keys from one site visible to other sites
Data Isolation (AFTER FIX)
- ✅ Each site only sees its own integrations
- ✅ Syncs are properly isolated per site
- ✅ Content stays within its designated site
- ✅ API keys properly scoped to their site
Related Issues
Connection Test Bug (Also Fixed)
The connection test was showing "connected" even when the plugin was deactivated because it only checked if WordPress REST API was reachable, not if the plugin could communicate back.
Fix: Modified WordPressIntegrationForm.tsx to check fully_functional instead of just success.
Files Changed
igny8/backend/igny8_core/api/base.py- Site filtering parameter fixigny8/frontend/src/components/sites/WordPressIntegrationForm.tsx- Connection test improvement
Conclusion
This was a CRITICAL data isolation bug that violated fundamental multi-tenancy principles. The fix is simple but essential:
Always verify that query parameter names match between frontend and backend!
The bug has been fixed and proper site isolation is now enforced throughout the application.
Priority: DEPLOY IMMEDIATELY
Risk: HIGH (data isolation violation)
Complexity: LOW (single line change)
Testing: REQUIRED before production deployment