DEV Community

Cover image for Your Daily CVE Reminder 🦸🏻‍♀️
Sena Yakut for AWS Community Builders

Posted on • Originally published at Medium

Your Daily CVE Reminder 🦸🏻‍♀️

Common Vulnerabilities and Exposures (CVE) lists publicly disclosed security vulnerabilities and exposures. Every day, there are lots of vulnerabilities published and it’s hard to track all of them. We need to know what the critical/high ones are, whether are we affected, what should we do, etc. To achieve this, we will construct a daily reminder mechanism for critical and high CVEs using Slack and AWS Serverless technologies. If you’re using Slack I highly recommend integrating this as soon as possible. If you’re not, you can update the code easily with other notification channels, still highly recommended. You can get all the code from here. Let’s start together!

🫀 AWS Services & Technologies that we’ve used:

  • AWS CDK
  • AWS Lambda
  • Amazon EventBridge
  • Slack Webhook
  • NIST Vulnerability API, you can reach from here.

Image description

👩🏻‍💻 In our CDK code, I want to explain some parts that can you understand and update easily. In lib/cve-daily-reminder-lambda.ts we’re creating Lambda function and EventBridge rule. I set the reminder schedule as every day at 8 AM with UTC+3. If you want to change, you need to do this from this code. Also, you need to add your Slack Webhook URL in there. If you don’t know how to generate your webhook URL, you can check here.

import {Stack, StackProps, Duration} from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { Construct } from 'constructs';
import * as events from 'aws-cdk-lib/aws-events';
import * as targets from 'aws-cdk-lib/aws-events-targets';

export class CveDailyReminder extends Stack {

  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id);

    const myLambda = new lambda.Function(this, 'LambdaFunction', {

      environment: {
        SLACK_WEBHOOK_PATH: '',  //add your SLACK_WEBHOOK_PATH here.
      },
      runtime: lambda.Runtime.NODEJS_LATEST, 
      code: lambda.Code.fromAsset('lib/lambda'),  // directory containing your Lambda code
      handler: 'index.handler',
      timeout: Duration.minutes(15) 
    });


    const rule = new events.Rule(this, 'Rule', {
      schedule: events.Schedule.cron({ 
        // Scheduled to run every day at 8 AM Turkey time (UTC+3)
        // Note: CloudWatch cron uses UTC time
        minute: '0',
        hour: '5', // 5 AM UTC is equivalent to 8 AM Turkey time (UTC+3)
        day: '*',
        month: '*',
        year: '*',
      }),
    });

    // Add the Lambda function as the rule's target
    rule.addTarget(new targets.LambdaFunction(myLambda));


  }
  }
Enter fullscreen mode Exit fullscreen mode

In our Lambda code logic, we will only get Critical and High CVEs for now. If you want you can customize the logic and get all of them. Lambda source code in lambda/index.mjs file:

      if (jsonData.vulnerabilities && Array.isArray(jsonData.vulnerabilities)) {
          const extractedData = jsonData.vulnerabilities.map(cveObj => {
            const { id, vulnStatus, descriptions, references, metrics } = cveObj.cve;
            const description = descriptions.find(desc => desc.lang === "en")?.value || 'Description not available';
            const baseScore = metrics?.cvssMetricV31?.[0]?.cvssData?.baseScore;
            const baseSeverity = metrics?.cvssMetricV31?.[0]?.cvssData?.baseSeverity;
            if (baseScore && baseSeverity) {
              return {
                cveId: id,
                vulnStatus: vulnStatus,
                description: description,
                baseScore: baseScore,
                baseSeverity: baseSeverity,
                references: references.map(ref => ref.url),
              };

            }
            return null;
          }).filter(item => item);
          const highAndCritical = extractedData.filter(item =>
            item.baseSeverity === 'HIGH' || item.baseSeverity === 'CRITICAL');

          highAndCritical.forEach(item => {

            let text = '';
            const firstSentence = getFirstSentence(item.description);
            text += `:large_red_square: *CVE ID*: ${item.cveId}\n*Base Score*: ${item.baseScore}\n*Base Severity*: ${item.baseSeverity}\n*Description*: ${firstSentence}\n*References*: ${item.references.join(', ').substring(0, 3000)}\n\n`;

            sendToSlack(text);

          });
        }
Enter fullscreen mode Exit fullscreen mode

Notes for updates in Lambda: Slack webhooks are expecting a JSON type that you need to send. If you don’t send this, you will get errors. You can get all the details from there.

After deploying the solution with AWS CDK, you can get daily CVEs and details in your Slack channel successfully.

Daily CVEs in Slack Channel

We need to review all of them daily. If our systems are affected, we need to take action about it. Stay safe! 🤞

Top comments (0)