All posts

Streamlining Security Management: Integrating Guardian Security API with Google Sheets

In today's fast-paced cybersecurity landscape, effective vulnerability management requires both powerful tools and accessible data. While dedicated security platforms offer robust capabilities, sometimes you need a simpler way to view, share, and analyze your security data. This is where the combination of the Guardian Security Intelligence API and Google Sheets creates a powerful, flexible solution.

Guardian API-GoogleSheets

Why Integrate Guardian Security with Google Sheets?

The Guardian Security platform provides comprehensive vulnerability scanning and management, but there are several compelling reasons to bring this data into Google Sheets:

  1. Simplified Reporting: Create custom reports that focus on the metrics that matter most to your team or executives
  2. Data Analysis: Leverage Google Sheets' built-in sorting, filtering, and pivot tables to analyze vulnerability trends
  3. Collaboration: Share vulnerability data with team members who may not have access to the full Guardian platform
  4. Integration: Combine vulnerability data with other business metrics for more comprehensive risk assessments
  5. Automation: Schedule automatic refreshes to keep your security overview current

Building Our Google Sheets Integration

Using Google Apps Script, we've created a custom function that pulls vulnerability data from the Guardian Security API and formats it for easy visualization in Google Sheets.

Key Features of Our Integration

  • Risk Score Visualization: Color-coded risk scores help quickly identify high-risk assets
  • Vulnerability Counts by Severity: See critical, high, and moderate vulnerabilities at a glance
  • Conditional Formatting: Automatic color coding makes it easy to spot problems
  • One-Click Formatting: Apply professional formatting with a single menu click
  • Simple API Access: Basic function call requires just your API key

The Technical Implementation

The solution consists of three main components:

  1. Data Retrieval Function: Fetches asset information and vulnerability counts from the Guardian API
  2. Formatting Function: Applies conditional formatting based on risk scores and vulnerability counts
  3. Helper Function: Simplifies the user experience with a one-parameter function call

Here's how the data retrieval works behind the scenes:

  1. First, we get the list of assets from Guardian's API
  2. For each asset, we fetch detailed information including risk score and vulnerability counts
  3. We format the data into rows with the most important information
  4. Finally, we return a neatly organized array that Google Sheets renders as a table

Let's explore the key code sections that make this possible:


function
GUARDIAN_ASSETS_WITH_VULNERABILITIES(apiKey, baseUrl, includeAllAssets)
{ // Set default values if parameters are missing baseUrl = baseUrl || "/external"; includeAllAssets = includeAllAssets === true; // Input validation if (!apiKey) { return [["Error: API key is required"]]; } // Set up the request headers const headers = { "x-api-key": apiKey }; try { // First, get all assets with failed scans or all assets const endpoint = includeAllAssets ? "/assets" : "/assets/failed-scan"; const assetResponse = UrlFetchApp.fetch(baseUrl + endpoint, { method: "get", headers: headers, muteHttpExceptions: true }); // Parse the response if (assetResponse.getResponseCode() !== 200) { return [["Error: Failed to fetch assets. Status code: " + assetResponse.getResponseCode()]]; } const assets = JSON.parse(assetResponse.getContentText()); // Initialize the result array with headers const result = [ [ "Asset ID", "Hostname", "IP Address", "OS", "Last Analyzed", "Failed Scan Qty", "Risk Score", "Critical Vulnerabilities", "High Vulnerabilities", "Moderate Vulnerabilities" ] ]; // Process each asset... for (let i = 0; i < assets.length; i++) { const assetBasic = assets[i]; // Get detailed asset information to fetch risk_score and vulnerability counts const assetDetailResponse = UrlFetchApp.fetch(baseUrl + "/assets/" + assetBasic.id, { method: "get", headers: headers, muteHttpExceptions: true }); let riskScore = 0; let criticalCount = 0; let highCount = 0; let mediumCount = 0; let asset = assetBasic; // Default to basic asset info // Update asset with detailed information if successful if (assetDetailResponse.getResponseCode() === 200) { asset = JSON.parse(assetDetailResponse.getContentText()); riskScore = asset.risk_score || 0; criticalCount = asset.severity_critical || 0; highCount = asset.severity_high || 0; mediumCount = asset.severity_medium || 0; }

This code retrieves detailed information for each asset, including the risk score and vulnerability counts. The Guardian API provides these counts directly, saving us from having to manually count vulnerabilities and improving performance.

Once we have the detailed information, we format it and add it to our results:


// Format date for readability const lastAnalyzed = asset.last_analyzed ? new Date(asset.last_analyzed) : ""; // Add asset data to results const row = [ assetBasic.id, assetBasic.hostname || "", assetBasic.ip || "", assetBasic.os || "", lastAnalyzed, asset.failed_scan_qty || 0, riskScore, criticalCount, highCount, mediumCount ]; result.push(row); // Add brief pause to avoid hitting rate limits Utilities.sleep(100); } return result;

Setting Up the Integration

To use this integration in your own Google Sheets:

  1. Open your Google Sheet
  2. Go to Extensions > Apps Script
  3. Create a new script file and paste the complete code (shared below)
  4. Save and return to your sheet
  5. Call the function in a cell: =GUARDIAN_VULNERABILITIES("your-api-key")
  6. Use the "Guardian Security" menu to apply formatting

Visual Formatting with Conditional Rules

One of the most powerful aspects of this integration is the automatic formatting that makes vulnerabilities and risk scores visually apparent. Here's the code that handles this:


function
applyGuardianVulnerabilityFormatting()
{ const sheet = SpreadsheetApp.getActiveSheet(); const dataRange = sheet.getDataRange(); const values = dataRange.getValues(); // Skip if sheet is empty or has only headers if (values.length <= 1) return; // Find column indexes const headers = values[0]; const riskScoreIndex = headers.indexOf("Risk Score"); const criticalIndex = headers.indexOf("Critical Vulnerabilities"); const highIndex = headers.indexOf("High Vulnerabilities"); const mediumIndex = headers.indexOf("Moderate Vulnerabilities"); // Check if required columns exist if (riskScoreIndex === -1 || criticalIndex === -1 || highIndex === -1 || mediumIndex === -1) { SpreadsheetApp.getUi().alert("Required columns not found. Please run the GUARDIAN_ASSETS_WITH_VULNERABILITIES function first."); return; } // Clear existing conditional formatting rules sheet.clearConditionalFormatRules(); let rules = []; // Critical risk (80-100): Purple background let criticalRiskRule = SpreadsheetApp.newConditionalFormatRule() .whenNumberGreaterThanOrEqualTo(80) .setBackground("#E6CFFC") // Light purple .setFontColor("#7030A0") // Dark purple .setBold(true) .setRanges([sheet.getRange(2, riskScoreIndex + 1, values.length - 1, 1)]) .build(); rules.push(criticalRiskRule); // Add other conditional formatting rules for different risk levels...

This code analyzes your spreadsheet to find the relevant columns, then applies conditional formatting rules to highlight risk scores and vulnerability counts based on their severity.

Real-World Benefits

This integration has already proven valuable for several teams:

  • Security Managers: Get a quick overview of the most vulnerable assets
  • IT Teams: Prioritize patching based on risk scores and vulnerability counts
  • Executives: View simplified dashboards of security posture without technical details
  • Compliance Teams: Export formatted reports for audits and compliance reviews

Advanced Use Cases

Beyond basic reporting, this integration enables several advanced use cases:

  • Custom Dashboards: Create charts and graphs based on vulnerability data
  • Trend Analysis: Track vulnerability counts over time to measure program effectiveness
  • Risk Scoring: Combine with business impact data to create custom risk prioritization
  • Multi-Team Collaboration: Create different views for different stakeholders

Future Enhancements

We're constantly improving this integration. Future enhancements may include:

  • Historical tracking of vulnerability trends
  • Integration with patch management data
  • Automated email reports for high-risk findings
  • Custom risk scoring formulas

Conclusion

By bringing Guardian Security data into Google Sheets, we've created a flexible, accessible way to work with vulnerability information. This approach combines the robust security scanning capabilities of Guardian with the familiar, powerful analysis features of Google Sheets.

Whether you're a security professional looking for better reporting tools or an IT manager seeking to prioritize your team's efforts, this integration offers a straightforward way to leverage your security data more effectively.

Making It User-Friendly

To make the script more user-friendly, we added a simplified function call and an automatic menu:


/** * Simple wrapper function to call from a cell with just the API key. * This allows for easier use in spreadsheets. * * @param {string} apiKey - Your Guardian Security API key * @return {array} Array of assets with their details and vulnerability counts * @customfunction */ function GUARDIAN_VULNERABILITIES(apiKey) { return GUARDIAN_ASSETS_WITH_VULNERABILITIES(apiKey); } /** * Creates a menu item to apply formatting with one click. */ function onOpen() { const ui = SpreadsheetApp.getUi(); ui.createMenu('Guardian Security') .addItem('Apply Vulnerability Formatting', 'applyGuardianVulnerabilityFormatting') .addToUi(); }

The GUARDIAN_VULNERABILITIES function is a simple wrapper that makes it easier for users to call our main function without having to specify all the parameters. The onOpen function automatically adds a menu item to the Google Sheets interface when the spreadsheet is opened.

Complete Script

Here's the complete script you can copy and paste into your Google Apps Script editor:


/** * Fetches assets with vulnerability counts and risk scores from Guardian Security Intelligence API. * * @param {string} apiKey - Your Guardian Security API key * @param {string} baseUrl - Base URL for the API (default: "https://baseURL/external") * @param {boolean} includeAllAssets - Whether to include all assets or only those with failed scans (default: false) * @return {array} Array of assets with their details, vulnerability counts and risk scores * @customfunction */
function GUARDIAN_ASSETS_WITH_VULNERABILITIES(apiKey, baseUrl, includeAllAssets) { // Set default values if parameters are missing baseUrl = baseUrl || "https://baseURL/external"; includeAllAssets = includeAllAssets === true; // Input validation if (!apiKey) { return [["Error: API key is required"]]; } // Set up the request headers const headers = { "x-api-key": apiKey }; try { // First, get all assets with failed scans or all assets const endpoint = includeAllAssets ? "/assets" : "/assets/failed-scan"; const assetResponse = UrlFetchApp.fetch(baseUrl + endpoint, { method: "get", headers: headers, muteHttpExceptions: true }); // Parse the response if (assetResponse.getResponseCode() !== 200) { return [["Error: Failed to fetch assets. Status code: " + assetResponse.getResponseCode()]]; } const assets = JSON.parse(assetResponse.getContentText()); // Initialize the result array with headers const result = [ [ "Asset ID", "Hostname", "IP Address", "OS", "Last Analyzed", "Failed Scan Qty", "Risk Score", "Critical Vulnerabilities", "High Vulnerabilities", "Moderate Vulnerabilities" ] ]; // Process each asset for (let i = 0; i < assets.length; i++) { const assetBasic = assets[i]; // Get detailed asset information to fetch risk_score and vulnerability counts const assetDetailResponse = UrlFetchApp.fetch(baseUrl + "/assets/" + assetBasic.id, { method: "get", headers: headers, muteHttpExceptions: true }); let riskScore = 0; let criticalCount = 0; let highCount = 0; let mediumCount = 0; let asset = assetBasic; // Default to basic asset info // Update asset with detailed information if successful if (assetDetailResponse.getResponseCode() === 200) { asset = JSON.parse(assetDetailResponse.getContentText()); riskScore = asset.risk_score || 0; criticalCount = asset.severity_critical || 0; highCount = asset.severity_high || 0; mediumCount = asset.severity_medium || 0; } // Format date for readability const lastAnalyzed = asset.last_analyzed ? new Date(asset.last_analyzed) : ""; // Add asset data to results const row = [ assetBasic.id, assetBasic.hostname || "", assetBasic.ip || "", assetBasic.os || "", lastAnalyzed, asset.failed_scan_qty || 0, riskScore, criticalCount, highCount, mediumCount ]; result.push(row); // Add brief pause to avoid hitting rate limits Utilities.sleep(100); } return result; } catch (error) { return [["Error: " + error.toString()]]; } } /** * Helper function to apply conditional formatting based on vulnerability severity and risk scores. * Call this function from your spreadsheet to automatically format the results. */ function applyGuardianVulnerabilityFormatting() { const sheet = SpreadsheetApp.getActiveSheet(); const dataRange = sheet.getDataRange(); const values = dataRange.getValues(); // Skip if sheet is empty or has only headers if (values.length <= 1) return; // Find column indexes const headers = values[0]; const riskScoreIndex = headers.indexOf("Risk Score"); const criticalIndex = headers.indexOf("Critical Vulnerabilities"); const highIndex = headers.indexOf("High Vulnerabilities"); const mediumIndex = headers.indexOf("Moderate Vulnerabilities"); // Check if required columns exist if (riskScoreIndex === -1 || criticalIndex === -1 || highIndex === -1 || mediumIndex === -1) { SpreadsheetApp.getUi().alert("Required columns not found. Please run the GUARDIAN_ASSETS_WITH_VULNERABILITIES function first."); return; } // Clear existing conditional formatting rules sheet.clearConditionalFormatRules(); let rules = []; // Add rule for Risk Score (higher is worse) // Risk score column const riskScoreRange = sheet.getRange(2, riskScoreIndex + 1, values.length - 1, 1); // Critical risk (80-100): Purple background let criticalRiskRule = SpreadsheetApp.newConditionalFormatRule() .whenNumberGreaterThanOrEqualTo(80) .setBackground("#E6CFFC") // Light purple .setFontColor("#7030A0") // Dark purple .setBold(true) .setRanges([riskScoreRange]) .build(); rules.push(criticalRiskRule); // High risk (60-79): Red background let highRiskRule = SpreadsheetApp.newConditionalFormatRule() .whenNumberBetween(60, 79) .setBackground("#FFCCCB") // Light red .setFontColor("#CC0000") // Dark red .setBold(true) .setRanges([riskScoreRange]) .build(); rules.push(highRiskRule); // Medium risk (40-59): Orange background let mediumRiskRule = SpreadsheetApp.newConditionalFormatRule() .whenNumberBetween(40, 59) .setBackground("#FFDCB0") // Light orange .setFontColor("#FF6600") // Dark orange .setBold(true) .setRanges([riskScoreRange]) .build(); rules.push(mediumRiskRule); // Low risk (1-39): Green background let lowRiskRule = SpreadsheetApp.newConditionalFormatRule() .whenNumberBetween(1, 39) .setBackground("#E6F4EA") // Light green .setFontColor("#38761D") // Dark green .setBold(true) .setRanges([riskScoreRange]) .build(); rules.push(lowRiskRule); // Vulnerability severity formatting // Critical vulnerabilities - purple const criticalRange = sheet.getRange(2, criticalIndex + 1, values.length - 1, 1); let criticalRule = SpreadsheetApp.newConditionalFormatRule() .whenNumberGreaterThan(0) .setBackground("#E6CFFC") // Light purple .setFontColor("#7030A0") // Dark purple .setBold(true) .setRanges([criticalRange]) .build(); rules.push(criticalRule); // High vulnerabilities - red const highRange = sheet.getRange(2, highIndex + 1, values.length - 1, 1); let highRule = SpreadsheetApp.newConditionalFormatRule() .whenNumberGreaterThan(0) .setBackground("#FFCCCB") // Light red .setFontColor("#CC0000") // Dark red .setBold(true) .setRanges([highRange]) .build(); rules.push(highRule); // Medium/Moderate vulnerabilities - orange const mediumRange = sheet.getRange(2, mediumIndex + 1, values.length - 1, 1); let mediumRule = SpreadsheetApp.newConditionalFormatRule() .whenNumberGreaterThan(0) .setBackground("#FFDCB0") // Light orange .setFontColor("#FF6600") // Dark orange .setBold(true) .setRanges([mediumRange]) .build(); rules.push(mediumRule); // Apply all rules sheet.setConditionalFormatRules(rules); } /** * Simple wrapper function to call from a cell with just the API key. * This allows for easier use in spreadsheets. * * @param {string} apiKey - Your Guardian Security API key * @return {array} Array of assets with their details and vulnerability counts * @customfunction */ function GUARDIAN_VULNERABILITIES(apiKey) { return GUARDIAN_ASSETS_WITH_VULNERABILITIES(apiKey); } /** * Creates a menu item to apply formatting with one click. */ function onOpen() { const ui = SpreadsheetApp.getUi(); ui.createMenu('Guardian Security') .addItem('Apply Vulnerability Formatting', 'applyGuardianVulnerabilityFormatting') .addToUi(); }

Note: This integration uses the Guardian Security API and requires a valid API key. Contact your Codenotary sales representative for API access if you don't already have it.