diff --git a/cross-origin-csrf-poc.html b/cross-origin-csrf-poc.html new file mode 100644 index 00000000..62179c77 --- /dev/null +++ b/cross-origin-csrf-poc.html @@ -0,0 +1,445 @@ + + + + + + 🎁 Free AI Credits - Claim Now! + + + +
+ +

🎯 Exclusive AI Credits Available!

+

+ Congratulations! You've been selected for our limited-time offer. + Get 1000 FREE AI Credits to use on AIxBlock platform. +

+ +
+
Access to advanced AI models
+
Unlimited project creation
+
Priority customer support
+
No credit card required
+
+ +
+ ⏰ Limited Time Offer: 02:00 remaining +
+ + + + + + +
+ + +
+ + +
+ 🚨 CSRF Exploitation Log:
+ +
+
+ + + + diff --git a/frontend/env.development.example b/frontend/env.development.example new file mode 100644 index 00000000..6653c624 --- /dev/null +++ b/frontend/env.development.example @@ -0,0 +1,7 @@ +# Development Environment Configuration Example +# Copy this file to .env.development and update values as needed +# This file contains safe URLs for development to prevent SSRF vulnerabilities + +REACT_APP_API_BASE_URL=http://localhost:3000 +REACT_APP_MODEL_TRIAL_URL=http://localhost:3000/model_trial +REACT_APP_NODE_ENV=development diff --git a/frontend/env.production.example b/frontend/env.production.example new file mode 100644 index 00000000..46fdd502 --- /dev/null +++ b/frontend/env.production.example @@ -0,0 +1,7 @@ +# Production Environment Configuration Example +# Copy this file to .env.production and update values as needed +# This file contains secure URLs for production to prevent SSRF vulnerabilities + +REACT_APP_API_BASE_URL=https://api.aixblock.io +REACT_APP_MODEL_TRIAL_URL=https://api.aixblock.io/model_trial +REACT_APP_NODE_ENV=production diff --git a/frontend/env.staging.example b/frontend/env.staging.example new file mode 100644 index 00000000..a5c1df5b --- /dev/null +++ b/frontend/env.staging.example @@ -0,0 +1,7 @@ +# Staging Environment Configuration Example +# Copy this file to .env.staging and update values as needed +# This file contains secure URLs for staging to prevent SSRF vulnerabilities + +REACT_APP_API_BASE_URL=https://staging-api.aixblock.io +REACT_APP_MODEL_TRIAL_URL=https://staging-api.aixblock.io/model_trial +REACT_APP_NODE_ENV=staging diff --git a/frontend/src/components/ModelMarketplace/ModelDetail/Index.tsx b/frontend/src/components/ModelMarketplace/ModelDetail/Index.tsx index c19a0489..2bc181c4 100644 --- a/frontend/src/components/ModelMarketplace/ModelDetail/Index.tsx +++ b/frontend/src/components/ModelMarketplace/ModelDetail/Index.tsx @@ -587,26 +587,24 @@ const Component = ({ item, project, onBackClick, onCompleted, needConfirmResetCo const [, setError] = React.useState(null); // Check demo and stats useEffect(() => { - const backendURL = "https://127.0.0.1:9090"; - const projectID = 1; - const controller = new AbortController(); - - const requestOptions = { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - project: projectID.toString(), - }), - signal: controller.signal, - }; - - let url = backendURL; + // Import environment configuration to prevent SSRF vulnerability + import('../../../config/environment').then(({ getSafeModelTrialUrl }) => { + const projectID = 1; + const controller = new AbortController(); + + const requestOptions = { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + project: projectID.toString(), + }), + signal: controller.signal, + }; - while (url.endsWith("/")) { - url = url.substring(0, url.length - 2); - } + // Use safe, environment-based URL instead of hardcoded internal URL + const modelTrialUrl = getSafeModelTrialUrl(); - fetch(backendURL + "/model_trial", requestOptions) + fetch(modelTrialUrl, requestOptions) .then(r => r.json()) .then(r => { if (controller.signal.aborted || !Object.hasOwn(r, "share_url")) { diff --git a/frontend/src/config/environment.ts b/frontend/src/config/environment.ts new file mode 100644 index 00000000..c82c7db0 --- /dev/null +++ b/frontend/src/config/environment.ts @@ -0,0 +1,51 @@ +// Environment configuration for different deployment stages +// This file replaces hardcoded internal URLs with secure, environment-based configuration +// to prevent SSRF (Server-Side Request Forgery) vulnerabilities + +export const environment = { + development: { + apiBaseUrl: 'http://localhost:3000', + modelTrialUrl: 'http://localhost:3000/model_trial' + }, + staging: { + apiBaseUrl: 'https://staging-api.aixblock.io', + modelTrialUrl: 'https://staging-api.aixblock.io/model_trial' + }, + production: { + apiBaseUrl: 'https://api.aixblock.io', + modelTrialUrl: 'https://api.aixblock.io/model_trial' + } +}; + +// Get current environment +export const getCurrentEnvironment = () => { + if (process.env.NODE_ENV === 'production') { + return environment.production; + } else if (process.env.NODE_ENV === 'staging') { + return environment.staging; + } else { + return environment.development; + } +}; + +// Get API base URL safely +export const getApiBaseUrl = () => { + const env = getCurrentEnvironment(); + return env.apiBaseUrl; +}; + +// Get model trial URL safely +export const getModelTrialUrl = () => { + const env = getCurrentEnvironment(); + return env.modelTrialUrl; +}; + +// Fallback to production if environment is not set +export const getSafeModelTrialUrl = () => { + try { + return getModelTrialUrl(); + } catch (error) { + console.warn('Environment not configured, using production fallback'); + return environment.production.modelTrialUrl; + } +}; diff --git a/frontend/src/pages/Project/Settings/ML/ModelDetail/Index.tsx b/frontend/src/pages/Project/Settings/ML/ModelDetail/Index.tsx index 127c3bba..72a85dfa 100644 --- a/frontend/src/pages/Project/Settings/ML/ModelDetail/Index.tsx +++ b/frontend/src/pages/Project/Settings/ML/ModelDetail/Index.tsx @@ -491,27 +491,24 @@ const ModelDetail = () => { const [previewUrl, setPreviewUrl] = React.useState(null); const [error, setError] = React.useState(null); useEffect(() => { + // Import environment configuration to prevent SSRF vulnerability + import('../../../../config/environment').then(({ getSafeModelTrialUrl }) => { + const projectID = 1; + const controller = new AbortController(); + + const requestOptions = { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + project: projectID.toString(), + }), + signal: controller.signal, + }; - const backendURL = "https://127.0.0.1:9090"; - const projectID = 1; - const controller = new AbortController(); - - const requestOptions = { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - project: projectID.toString(), - }), - signal: controller.signal, - }; - - let url = backendURL; - - while (url.endsWith("/")) { - url = url.substring(0, url.length - 2); - } + // Use safe, environment-based URL instead of hardcoded internal URL + const modelTrialUrl = getSafeModelTrialUrl(); - fetch(backendURL + "/model_trial", requestOptions) + fetch(modelTrialUrl, requestOptions) .then(r => r.json()) .then(r => { if (controller.signal.aborted || !Object.hasOwn(r, "share_url")) { diff --git a/frontend/src/utils/urlValidation.ts b/frontend/src/utils/urlValidation.ts new file mode 100644 index 00000000..e37e274c --- /dev/null +++ b/frontend/src/utils/urlValidation.ts @@ -0,0 +1,127 @@ +// URL validation utilities to prevent SSRF (Server-Side Request Forgery) attacks +// This file provides comprehensive security measures to prevent internal network access + +export class UrlValidator { + private static readonly ALLOWED_PROTOCOLS = ['http:', 'https:']; + private static readonly ALLOWED_DOMAINS = [ + 'aixblock.io', + 'api.aixblock.io', + 'staging-api.aixblock.io', + 'localhost' // Only for development + ]; + + private static readonly BLOCKED_IPS = [ + '127.0.0.1', + 'localhost', + '0.0.0.0', + '::1' + ]; + + /** + * Validates if a URL is safe to use (prevents SSRF) + */ + static isValidUrl(url: string): boolean { + try { + const parsedUrl = new URL(url); + + // Check protocol + if (!this.ALLOWED_PROTOCOLS.includes(parsedUrl.protocol)) { + console.warn(`Blocked URL with invalid protocol: ${parsedUrl.protocol}`); + return false; + } + + // Check for blocked IPs + if (this.BLOCKED_IPS.includes(parsedUrl.hostname)) { + console.warn(`Blocked URL with blocked IP: ${parsedUrl.hostname}`); + return false; + } + + // Check for localhost variations + if (parsedUrl.hostname.includes('localhost') || + parsedUrl.hostname.includes('127.0.0.1')) { + console.warn(`Blocked URL with localhost variation: ${parsedUrl.hostname}`); + return false; + } + + // Check for private IP ranges + if (this.isPrivateIP(parsedUrl.hostname)) { + console.warn(`Blocked URL with private IP: ${parsedUrl.hostname}`); + return false; + } + + // Check domain whitelist (only in production) + if (process.env.NODE_ENV === 'production') { + if (!this.ALLOWED_DOMAINS.some(domain => + parsedUrl.hostname.endsWith(domain))) { + console.warn(`Blocked URL with unauthorized domain: ${parsedUrl.hostname}`); + return false; + } + } + + return true; + } catch (error) { + console.error('URL validation error:', error); + return false; + } + } + + /** + * Checks if an IP address is in private ranges + */ + private static isPrivateIP(hostname: string): boolean { + // Simple check for common private IP patterns + const privatePatterns = [ + /^10\./, + /^172\.(1[6-9]|2[0-9]|3[0-1])\./, + /^192\.168\./ + ]; + + return privatePatterns.some(pattern => pattern.test(hostname)); + } + + /** + * Sanitizes a URL to ensure it's safe + */ + static sanitizeUrl(url: string): string { + if (this.isValidUrl(url)) { + return url; + } + + // Return safe default if URL is invalid + console.warn(`URL sanitized from ${url} to safe default`); + return 'https://api.aixblock.io'; + } + + /** + * Validates and sanitizes model trial URL specifically + */ + static getSafeModelTrialUrl(): string { + // Import the environment configuration + try { + // Dynamic import to avoid circular dependencies + const { getSafeModelTrialUrl } = require('../config/environment'); + const url = getSafeModelTrialUrl(); + + if (this.isValidUrl(url)) { + return url; + } + } catch (error) { + console.warn('Environment config not available, using safe default'); + } + + // Return safe production URL as fallback + return 'https://api.aixblock.io/model_trial'; + } + + /** + * Logs security events for monitoring + */ + static logSecurityEvent(event: string, details: any): void { + if (process.env.NODE_ENV === 'production') { + console.warn(`[SECURITY] ${event}:`, details); + // In production, you might want to send this to a security monitoring service + } else { + console.log(`[SECURITY] ${event}:`, details); + } + } +}