Skip to content

New use case: Security vulnerability auto-remediation pipeline via GitHub security webhook events #920

@kelos-bot

Description

@kelos-bot

🤖 Kelos Strategist Agent @gjkim42

Summary

Security vulnerability backlogs grow faster than most teams can triage and fix them. GitHub already sends structured webhook events for Dependabot alerts, CodeQL findings, and secret scanning alerts — but Kelos's githubWebhook source currently cannot extract security-specific fields from these events, limiting its usefulness for automated vulnerability remediation.

This proposal outlines a security vulnerability auto-remediation pipeline that leverages Kelos's existing webhook infrastructure and task pipeline capabilities, identifies the specific code gap preventing it from working today, and provides concrete example configurations.

Motivation

  • Scale problem: A single critical CVE can affect hundreds of dependencies across an organization. Manual triage and patching doesn't scale.
  • Speed problem: Mean time to remediation for known vulnerabilities is often weeks or months. Automated agents could cut this to hours.
  • Natural fit for Kelos: The multi-stage pipeline pattern (triage → fix → validate → PR) maps directly to Kelos's dependsOn task chains.
  • Target audience: Security-conscious teams, regulated industries (fintech, healthcare), open source maintainers, DevSecOps teams.

Current State Analysis

What works today

The githubWebhook source in kelos-webhook-server can already:

  1. Receive any GitHub webhook event type — the Events field is an untyped string array (api/v1alpha1/taskspawner_types.go:322)
  2. Verify webhook signatures via X-Hub-Signature-256
  3. Pass events through filters (action, author, excludeAuthors)
  4. Create Tasks from matched events

You can configure a TaskSpawner to listen for dependabot_alert events today:

when:
  githubWebhook:
    events: ["dependabot_alert"]
    filters:
      - event: "dependabot_alert"
        action: "created"

What doesn't work

ParseGitHubWebhook (internal/webhook/github_filter.go:40-187) has explicit handling for 6 event types:

  • IssuesEvent, PullRequestEvent, IssueCommentEvent
  • PullRequestReviewEvent, PullRequestReviewCommentEvent, PushEvent

For any other event type (including all security events), it falls into the default case (lines 171-184) which only extracts sender and action from raw JSON. This means:

  • {{.Title}} → empty (no alert title extraction)
  • {{.Body}} → empty (no alert description or CVE details)
  • {{.URL}} → empty (no link to the alert)
  • {{.Number}} → 0 (no alert number)
  • {{.ID}} → empty (no alert identifier)

The agent would receive a prompt with no context about what vulnerability to fix.

What go-github v66 supports

The go-github v66 library (already a dependency in go.mod) parses these security event types via github.ParseWebHook():

Event type Go type Key fields
dependabot_alert *github.DependabotAlertEvent Alert.SecurityAdvisory (CVE, CVSS, description), Alert.SecurityVulnerability (package, severity, version range), Alert.HTMLURL
code_scanning_alert *github.CodeScanningAlertEvent Alert.Rule (ID, description, severity), Alert.MostRecentInstance (location, message), Alert.HTMLURL
secret_scanning_alert *github.SecretScanningAlertEvent Alert.SecretType, Alert.Secret (redacted), Alert.HTMLURL

These types are already parsed correctly by github.ParseWebHook() on line 41 of github_filter.go — the data is available but discarded because there are no case branches for them.

Proposal

1. Extend ParseGitHubWebhook for security events

Add case branches for DependabotAlertEvent, CodeScanningAlertEvent, and SecretScanningAlertEvent in internal/webhook/github_filter.go. Map their fields to the standard template variables:

Template variable dependabot_alert mapping code_scanning_alert mapping
{{.ID}} Alert number Alert number
{{.Title}} Advisory summary Rule description
{{.Body}} Advisory description + CVE + severity + affected package Rule full description + instance message + location
{{.URL}} Alert HTML URL Alert HTML URL
{{.Number}} Alert number Alert number

Additionally, expose security-specific fields via the {{.Payload}} variable (which already passes RawEvent), so prompt templates can access:

  • {{.Payload.Alert.SecurityAdvisory.CVEID}}
  • {{.Payload.Alert.SecurityVulnerability.Package.Name}}
  • {{.Payload.Alert.SecurityVulnerability.Severity}}

2. Example: Single-stage vulnerability fixer

A minimal TaskSpawner that creates a fix PR for each new Dependabot alert:

apiVersion: kelos.dev/v1alpha1
kind: TaskSpawner
metadata:
  name: security-fixer
spec:
  when:
    githubWebhook:
      events: ["dependabot_alert"]
      repository: "myorg/myrepo"
      filters:
        - event: "dependabot_alert"
          action: "created"
  maxConcurrency: 2
  taskTemplate:
    type: claude-code
    credentials:
      type: api-key
      secretRef:
        name: claude-credentials
    workspaceRef:
      name: my-workspace
    branch: "security/fix-{{.ID}}"
    promptTemplate: |
      A new security vulnerability has been detected.

      ## Alert Details
      - **Title**: {{.Title}}
      - **URL**: {{.URL}}

      ## Description
      {{.Body}}

      ## Task
      1. Identify the affected dependency and vulnerable code paths
      2. Update the dependency to a patched version
      3. Run `make test` to verify nothing breaks
      4. If tests fail, investigate and fix the breakage
      5. Commit changes and create a PR referencing this alert

      Keep changes minimal — only update what is needed to remediate the vulnerability.
    ttlSecondsAfterFinished: 3600
    metadata:
      labels:
        kelos.dev/trigger: "security"

3. Example: Multi-stage remediation pipeline

For high-severity vulnerabilities, a pipeline with triage, fix, and validation stages:

# Stage 1: Triage — assess severity and impact
apiVersion: kelos.dev/v1alpha1
kind: Task
metadata:
  name: triage-vuln
spec:
  type: claude-code
  credentials:
    type: api-key
    secretRef:
      name: claude-credentials
  workspaceRef:
    name: my-workspace
  branch: "security/vuln-{{.ID}}"
  prompt: |
    A security vulnerability has been reported: {{.Title}}

    Details: {{.Body}}

    Analyze this vulnerability:
    1. Search the codebase for usage of the affected dependency
    2. Determine if the vulnerable code path is reachable
    3. Assess the blast radius (which services/endpoints are affected)

    Output your findings as a structured summary.
---
# Stage 2: Fix — apply the remediation
apiVersion: kelos.dev/v1alpha1
kind: Task
metadata:
  name: fix-vuln
spec:
  type: claude-code
  credentials:
    type: api-key
    secretRef:
      name: claude-credentials
  workspaceRef:
    name: my-workspace
  branch: "security/vuln-{{.ID}}"
  dependsOn:
    - triage-vuln
  prompt: |
    The triage stage found that the vulnerability "{{.Title}}" affects this codebase.
    Triage output: {{index .Deps "triage-vuln" "Results" "branch"}}

    Apply the fix:
    1. Update the affected dependency to a patched version
    2. Adapt any code that relied on changed APIs
    3. Run `make build` and `make test` to verify
    4. Commit and push changes
---
# Stage 3: Validate — run extended checks and create PR
apiVersion: kelos.dev/v1alpha1
kind: Task
metadata:
  name: validate-and-pr
spec:
  type: claude-code
  credentials:
    type: api-key
    secretRef:
      name: claude-credentials
  workspaceRef:
    name: my-workspace
  branch: "security/vuln-{{.ID}}"
  dependsOn:
    - fix-vuln
  prompt: |
    The vulnerability fix has been applied on branch {{index .Deps "fix-vuln" "Results" "branch"}}.

    Validate the fix:
    1. Run the full test suite: `make test`
    2. Verify the vulnerable dependency version is no longer present
    3. Check that no new vulnerabilities were introduced by the update

    If everything passes, create a PR:
    - Title: "fix(security): remediate {{.Title}}"
    - Reference the original alert URL
    - Label with `security` and `priority/critical`

Scope of Code Changes

The core enablement is small and focused:

  • internal/webhook/github_filter.go: Add ~40 lines of case branches in ParseGitHubWebhook for *github.DependabotAlertEvent, *github.CodeScanningAlertEvent, and *github.SecretScanningAlertEvent
  • internal/webhook/github_filter_test.go: Add test cases for each security event type
  • Example: Add examples/12-security-remediation/ with a TaskSpawner config and README

No CRD changes, no controller changes, no new dependencies.

Relationship to Existing Issues

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions