Skip to main content
Glama
cookie-security.test.ts9.96 kB
/* * This file is part of BrowserLoop. * * BrowserLoop is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * BrowserLoop is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with BrowserLoop. If not, see <https://www.gnu.org/licenses/>. */ import { strict as assert } from 'node:assert'; import { describe, test } from 'node:test'; import { ScreenshotService } from '../../src/screenshot-service.js'; import { createTestScreenshotOptions, createTestScreenshotServiceConfig, createTestServer, } from '../../src/test-utils.js'; import type { Cookie } from '../../src/types.js'; describe('Cookie Security Integration', () => { describe('Domain Validation', () => { test('should filter cookies with mismatched domains', async () => { const serviceConfig = createTestScreenshotServiceConfig(); const service = new ScreenshotService(serviceConfig); await service.initialize(); try { const testServer = createTestServer(); await testServer.start(); const port = testServer.port; // Create cookies with wrong domain that will be filtered out const cookies: Cookie[] = [ { name: 'evil_cookie', value: 'evil_value', domain: 'attacker.com', // Different from localhost - will be filtered }, ]; const options = createTestScreenshotOptions({ url: `http://localhost:${port}/simple.html`, cookies, }); // Should succeed but cookies are filtered out due to domain mismatch const result = await service.takeScreenshot(options); assert.ok(result.data, 'Should return screenshot data'); assert.strictEqual( result.mimeType, 'image/webp', 'Should return WebP format' ); await testServer.stop(); } finally { await service.cleanup(); } }); test('should allow cookies with correct domain', async () => { const serviceConfig = createTestScreenshotServiceConfig(); const service = new ScreenshotService(serviceConfig); await service.initialize(); try { const testServer = createTestServer(); await testServer.start(); const port = testServer.port; // Create cookies with correct domain const cookies: Cookie[] = [ { name: 'valid_cookie', value: 'valid_value', domain: 'localhost', // Matches URL domain }, ]; const options = createTestScreenshotOptions({ url: `http://localhost:${port}/simple.html`, cookies, }); // Should not throw with correct domain const result = await service.takeScreenshot(options); assert.ok(result.data, 'Should return screenshot data'); await testServer.stop(); } finally { await service.cleanup(); } }); test('should allow subdomain cookies for development', async () => { const serviceConfig = createTestScreenshotServiceConfig(); const service = new ScreenshotService(serviceConfig); await service.initialize(); try { const testServer = createTestServer(); await testServer.start(); const port = testServer.port; // Create cookies with .localhost domain (subdomain pattern) const cookies: Cookie[] = [ { name: 'subdomain_cookie', value: 'subdomain_value', domain: '.localhost', // Should be allowed for localhost }, ]; const options = createTestScreenshotOptions({ url: `http://localhost:${port}/simple.html`, cookies, }); // Should not throw with subdomain pattern const result = await service.takeScreenshot(options); assert.ok(result.data, 'Should return screenshot data'); await testServer.stop(); } finally { await service.cleanup(); } }); test('should allow 127.0.0.1 for localhost development', async () => { const serviceConfig = createTestScreenshotServiceConfig(); const service = new ScreenshotService(serviceConfig); await service.initialize(); try { const testServer = createTestServer(); await testServer.start(); const port = testServer.port; // Create cookies with 127.0.0.1 domain const cookies: Cookie[] = [ { name: 'ip_cookie', value: 'ip_value', domain: '127.0.0.1', // Should be allowed for localhost URLs }, ]; const options = createTestScreenshotOptions({ url: `http://localhost:${port}/simple.html`, cookies, }); // Should not throw with IP address const result = await service.takeScreenshot(options); assert.ok(result.data, 'Should return screenshot data'); await testServer.stop(); } finally { await service.cleanup(); } }); }); describe('Error Message Sanitization', () => { test('should handle cookies with sensitive values safely', async () => { const serviceConfig = createTestScreenshotServiceConfig(); const service = new ScreenshotService(serviceConfig); await service.initialize(); try { const testServer = createTestServer(); await testServer.start(); const port = testServer.port; // Create cookies with sensitive data that will be filtered out const cookies: Cookie[] = [ { name: 'secret_cookie', value: 'very_secret_value_that_should_not_appear_in_logs', domain: 'evil.com', // Will be filtered out due to domain mismatch }, ]; const options = createTestScreenshotOptions({ url: `http://localhost:${port}/simple.html`, cookies, }); // Should succeed - cookies are filtered out silently const result = await service.takeScreenshot(options); assert.ok(result.data, 'Should return screenshot data'); assert.strictEqual( result.mimeType, 'image/webp', 'Should return WebP format' ); await testServer.stop(); } finally { await service.cleanup(); } }); test('should sanitize validation error messages', async () => { const serviceConfig = createTestScreenshotServiceConfig(); const service = new ScreenshotService(serviceConfig); await service.initialize(); try { const testServer = createTestServer(); await testServer.start(); const port = testServer.port; // Create cookies with suspicious content const cookies: Cookie[] = [ { name: 'xss_cookie', value: '<script>alert("xss")</script>', domain: 'localhost', }, ]; const options = createTestScreenshotOptions({ url: `http://localhost:${port}/simple.html`, cookies, }); try { await service.takeScreenshot(options); assert.fail('Should have thrown validation error'); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); // Verify that the suspicious script content is not exposed assert.ok( !errorMessage.includes('<script>alert("xss")</script>'), 'Error message should not contain suspicious cookie value' ); // But should still contain useful debugging info assert.ok( errorMessage.includes('Cookie injection failed') || errorMessage.includes('validation'), 'Error message should indicate validation failure' ); } await testServer.stop(); } finally { await service.cleanup(); } }); }); describe('Memory Cleanup Verification', () => { test('should clear sensitive data during normal operation', async () => { const serviceConfig = createTestScreenshotServiceConfig(); const service = new ScreenshotService(serviceConfig); await service.initialize(); try { const testServer = createTestServer(); await testServer.start(); const port = testServer.port; // Create cookies with sensitive data that will be processed normally const cookies: Cookie[] = [ { name: 'sensitive_token', value: 'super_secret_token_123456789', domain: 'localhost', // Valid domain }, ]; const options = createTestScreenshotOptions({ url: `http://localhost:${port}/simple.html`, cookies, }); // Should succeed and clean up memory after use const result = await service.takeScreenshot(options); assert.ok(result.data, 'Should return screenshot data'); assert.strictEqual( result.mimeType, 'image/webp', 'Should return WebP format' ); // Memory cleanup should have occurred after successful injection // Note: This is hard to test directly, but the test verifies the code path is exercised assert.ok(true, 'Memory cleanup should have been called'); await testServer.stop(); } finally { await service.cleanup(); } }); }); });

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/mattiasw/browserloop'

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