---
# System prepended metadata

title: SAST-LLM Integration

---

# Semgrep-Slack Integration với LLM AutoFix

Trong 2 tháng đầu năm vừa qua, tôi đã phát triển một **Integration** kết hợp giữa **Semgrep** và **Slack**, tích hợp khả năng tự động sửa lỗi thông qua **LLM**. Writeup này sẽ trình bày chi tiết về giải pháp này.

## Bối cảnh và Động lực

- **AI/GenAI/LLM** đang phát triển mạnh mẽ và hỗ trợ nhiều lĩnh vực, từ tóm tắt nội dung, dịch thuật đến phát triển phần mềm. Việc áp dụng **AI/GenAI** để khắc phục lỗi là xu hướng không thể thiếu trong tương lai, hiện tại đã có nhiều dự án như Co-Pilot của Github hay các giải pháp của Google.

- Thị trường hiện nay có nhiều công cụ **SAST** (Static Application Security Testing) nhưng còn thiếu giải pháp kết hợp LLM để tự động sửa lỗi. Các giải pháp hiện có thường là thương mại hoặc mã nguồn đóng. Gần đây, dự án Patchwork đã xuất hiện với khả năng sử dụng LLM để tạo bản vá lỗi.

- Dựa trên nguyên lý của Patchwork, chúng ta có thể xây dựng một giải pháp **fixed code by LLM** đơn giản và hiệu quả.

## Mục tiêu của Dự án

1. **Đảm bảo bao phủ 100%**: Tất cả commit vào nhánh dev/master/main đều được quét tự động.

2. **Khuyến nghị và AutoFix**: 100% lỗ hổng được phát hiện sẽ nhận được khuyến nghị hoặc bản sửa tự động từ **Semgrep/LLM**. Developer chỉ cần review và merge code đã được sửa.

3. **Tối ưu quy trình**: Giảm thời gian xử lý các tickets bảo mật.

## Kiến trúc Kỹ thuật

### Quy trình Hoạt động
1. Tận dụng **services** trong **CI/CD pipeline** để khởi tạo bước **SAST**, quét và xuất kết quả dưới dạng **JSON/Sarif + Source Code**.

2. Source code được lọc để loại bỏ các từ khóa nhạy cảm theo yêu cầu người dùng.

3. Sử dụng LLM với prompt tối ưu để phân tích và khắc phục lỗi.

### Luồng Xử lý

```mermaid
flowchart LR
    %% Định nghĩa các nhóm
    subgraph Services["Services"]
        SCB["Services "]
        SAST["SAST"]
        SCB -- "managed by" --> SAST
    end

    subgraph AutoFixService["AutoFix Service"]
        Filter["Filter"]
        LLM["LLM"]
        Report["Report"]
        Filter -- "#4. Filterd Content + JSON/Sarif" --> LLM
        LLM -- "#5. Fixed Code" --> Report
    end

    
    subgraph Outside["Outside"]
        User["User"]
        Github["Github"]
        User -- "#1. commit" --> Github
    end

    %% Các kết nối giữa các nhóm
    Github -- "#2. Pull and Scan" --> SAST
    SAST -- "#3. JSON/Sarif + Source Code" --> Filter

    %% Định dạng các nhóm
    classDef outsideClass fill:#ffffcc,stroke:#333,stroke-width:1px
    classDef ServicesClass fill:#ffffcc,stroke:#333,stroke-width:1px
    classDef autoFixClass fill:#ffffcc,stroke:#333,stroke-width:1px
    
    %% Định dạng các node
    classDef nodeClass fill:#e6e6fa,stroke:#333,stroke-width:1px
    
    class Outside outsideClass
    class Services ServicesClass
    class AutoFixService autoFixClass
    
    class User,Github,SCB,SAST,Filter,LLM,Report nodeClass
```

## Tính năng Chi tiết

### 🌟 Tính năng Chính

#### 1. Xử lý Kết quả từ Semgrep

Dịch vụ nhận kết quả quét từ Semgrep thông qua Kafka và xử lý để trích xuất thông tin quan trọng:

- Phân loại theo mức độ nghiêm trọng (critical, high, medium, low)
- Xác định loại lỗ hổng dựa trên CWE (Common Weakness Enumeration)
- Trích xuất vị trí trong mã nguồn và đoạn code có vấn đề

#### 2. Tự động Đề xuất Sửa chữa bằng LLM

Đối với các phát hiện không có sẵn autofix, hệ thống sử dụng Gemini LLM để tạo đề xuất sửa chữa:

- Phân tích đoạn code có vấn đề 
- Xác định ngôn ngữ lập trình từ đường dẫn file
- Tạo prompt phù hợp với context và gửi đến LLM
- Định dạng kết quả với cú pháp đánh dấu ngôn ngữ đúng

#### 3. Phân loại và Lọc Phát hiện

Dịch vụ phân loại các phát hiện thành nhóm để xử lý phù hợp:

- **Credential findings**: Các phát hiện liên quan đến hardcoded credentials (CWE-798)
- **Findings có autofix**: Các phát hiện đã có sẵn đề xuất sửa chữa từ Semgrep
- **Findings cần LLM**: Các phát hiện không có sẵn autofix cần được xử lý bởi LLM

Hệ thống hỗ trợ lọc dựa trên whitelist để bỏ qua các quy tắc cụ thể.

#### 4. Thông báo Slack

Dịch vụ gửi thông báo đến Slack với định dạng dễ đọc:

- Nhóm các phát hiện theo repository
- Hiển thị biểu tượng mức độ nghiêm trọng (🟣 Critical, 🔴 High, 🟡 Medium, 🟢 Low)
- Liên kết trực tiếp đến file và dòng code có vấn đề
- Hiển thị đề xuất sửa chữa với định dạng Markdown 
- Tự động gắn thẻ người dùng/nhóm cần xem xét

> Trong quá trình phát triển, tôi nhận thấy có nhiều rule không cần thiết để scan và thông báo cho dev fix. Ngoài ra, những lỗi liên quan đến credentials không thể gửi cho LLM được. Do đó, tôi đã phát triển thêm tính năng **slash command** mà Slack hỗ trợ (tương tự như Telegram hoặc Discord), giúp quản lý whitelist và danh sách ngoại lệ mà không cần phải deploy lại service mỗi khi thêm rule hoặc CWE mới.

#### 5. Quản lý Cấu hình qua Slack Commands

Dịch vụ cung cấp các lệnh Slack để quản lý cấu hình:

- `/whitelist [add|rm] [rule_name]`: Thêm/xóa quy tắc vào whitelist
- `/except [add|rm] [CWE-XXX]`: Thêm/xóa CWE vào danh sách ngoại lệ
- `/list`: Hiển thị danh sách whitelist và CWE hiện tại
- `/help`: Hiển thị hướng dẫn sử dụng

![Slack Commands](https://hackmd.io/_uploads/BJIkaM0kgg.png)

### 🛠️ Kiến trúc Hệ thống

Semgrep-Slack Integration được xây dựng với kiến trúc module hóa cao, dễ mở rộng:

```
┌─────────────────┐     ┌──────────────────┐     ┌─────────────────┐
│  Kafka Consumer │────▶│ Finding Processor│────▶│  Slack Notifier │
└─────────────────┘     └──────────────────┘     └─────────────────┘
                               │  ▲
                               ▼  │
┌────────────────┐      ┌───────────────┐     ┌─────────────────┐
│  Redis Service │◀────▶│ Filter Service│────▶│   LLM Service   │
└────────────────┘      └───────────────┘     └─────────────────┘
```

```mermaid
flowchart TB
    %% External Components
    start((Start))
    dev[Developer]
    github[Github]
    event_controller[Event Controller]
    
    %% Main Flow
    start --> dev
    dev -- "1.Commit code" --> github
    github -- "2.Webhook trigger" --> event_controller
    event_controller -- "3.Create CRD (semgrep scan)" --> scb
    
    %% SecureCodeBox Subgraph
    subgraph SecureCodeBox["SecureCodeBox"]
        scb[secureCodeBox]
        semgrep[Semgrep SAST]
        kafka_soc[scb-kafka-soc]
        
        scb --> semgrep
        semgrep -- "4.Push findings to kafka" --> kafka_soc
    end
    
    %% Integration Services Subgraph
    subgraph integration["Integration Services"]
        kafka_consumer[Kafka Consumer]
        slack_bot[Slack Notification and Bot]
    end
    
    %% Core Services Subgraph
    subgraph core["Core Services"]
        finding_processor[Finding Processor]
        finding_classifier[Finding Classifier]
        finding_filter[Finding Filter]
    end
    
    %% Filter Services Subgraph
    subgraph filter_services["Filter Services"]
        whitelist_filter[Whitelist/CWE Filter]
        redis[Redis Service]
    end
    
    %% AI Services Subgraph
    subgraph ai["AI Services"]
        llm_service[LLM Service]
        autofix_generator[AutoFix Generator]
    end
    
    %% Finding Categories
    subgraph findings["Finding Categories"]
        credential_findings[Credential Findings]
        autofix_findings[AutoFix Findings]
        no_autofix_findings[No AutoFix Findings]
    end
    
    %% Connections between components
    kafka_soc -- "5.Stream findings" --> kafka_consumer
    kafka_consumer -- "6.Process findings" --> finding_processor
    finding_processor --> finding_filter
    finding_processor --> finding_classifier
    
    finding_filter -- "Query filters" --> whitelist_filter
    whitelist_filter -- "Get except and whitelist rules" --> redis
    redis -- "Return configurations" --> whitelist_filter
    
    finding_classifier -- "Classify" --> credential_findings
    finding_classifier -- "Classify" --> autofix_findings
    finding_classifier -- "Classify" --> no_autofix_findings
    
    no_autofix_findings -- "Send for analysis" --> llm_service
    llm_service --> autofix_generator
    
    credential_findings -- "Notify (without LLM processing)" --> slack_bot
    autofix_findings -- "Notify with Semgrep autofix" --> slack_bot
    autofix_generator -- "7.Provide autofix suggestion" --> slack_bot
    
    %% Styling
    classDef external fill:#f5f5f5,stroke:#333,stroke-width:1px
    classDef core fill:#d4f1f9,stroke:#333,stroke-width:1px
    classDef ai fill:#ffe6cc,stroke:#333,stroke-width:1px
    classDef filter fill:#e1d5e7,stroke:#333,stroke-width:1px
    classDef integration fill:#d5e8d4,stroke:#333,stroke-width:1px
    classDef findings fill:#fff2cc,stroke:#333,stroke-width:1px
    
    class start,dev,github,event_controller external
    class finding_processor,finding_classifier,finding_filter core
    class llm_service,autofix_generator ai
    class whitelist_filter,redis filter
    class kafka_consumer,slack_bot integration
    class credential_findings,autofix_findings,no_autofix_findings findings
```

### 🔧 Cấu trúc Dự án

```
semgrep-slack/
├── ai/                 # Các module liên quan đến LLM
│   ├── parser.py       # Xử lý và áp dụng autofix từ LLM
│   └── llm/
│       ├── gemini.py   # Tích hợp với Gemini
│       └── prompts.py  # Quản lý các prompt template
│
├── core/               # Core framework 
│   ├── config.py       # Cấu hình ứng dụng
│   └── logging.py      # Cấu hình logging
│
├── models/             # Các model dữ liệu
│   └── finding.py      # Mô hình dữ liệu cho findings
│
├── services/           # Các service chính
│   ├── filter_service.py  # Lọc và phân loại findings
│   ├── kafka_service.py   # Xử lý Kafka consumer
│   ├── redis_service.py   # Tương tác với Redis
│   ├── slack_service.py   # Gửi thông báo đến Slack
│   └── slack_command.py   # Xử lý Slack commands
│
├── utils/              # Các tiện ích 
│   └── detect_lang.py  # Phát hiện ngôn ngữ lập trình
│
└── main.py             # Điểm vào chính của ứng dụng
```

### 💬 Slack Commands Chi tiết

Dịch vụ cung cấp các Slack Commands để quản lý whitelist và danh sách CWE:

#### Quản lý Whitelist (dựa trên rule name)

- `/whitelist add rule.name.path, other.rule.path` - Thêm rule name vào whitelist
- `/whitelist list` - Xem danh sách whitelist
- `/whitelist rm rule.name.path` - Xóa rule name khỏi whitelist
- `/whitelist help` - Hiển thị hướng dẫn

#### Quản lý Danh sách CWE

- `/except add CWE-123, CWE-456` - Thêm CWE vào danh sách ngoại lệ
- `/except list` - Xem danh sách CWE
- `/except rm CWE-123` - Xóa CWE khỏi danh sách ngoại lệ
- `/except help` - Hiển thị hướng dẫn

#### Lệnh khác

- `/list` - Xem tất cả danh sách rule name và CWE
- `/help` - Hiển thị hướng dẫn chung

### 📊 Định dạng Thông báo Slack

Thông báo Slack được định dạng rõ ràng bao gồm:

- Tên repository và commit ID
- Tổng số lỗi được phát hiện
- Vị trí của lỗi trong mã nguồn (với đường dẫn đến file)
- Mức độ nghiêm trọng (với biểu tượng trực quan)
- Mã CWE và mô tả lỗi
- Gợi ý sửa chữa tự động (nếu có)

### 🔄 Quy trình Xử lý Tổng quan

1. Nhận kết quả quét từ Semgrep qua Kafka
2. Phân loại findings (credentials, có/không có autofix, whitelist)
3. Xử lý findings không có autofix bằng LLM
4. Gửi thông báo đến Slack với kết quả phân tích và gợi ý sửa chữa

## Demo Thực tế

### 1. Tạo Repository Test

Tôi đã tạo một repository để kiểm tra các chức năng, cố tình đưa vào một số lỗi bảo mật để quan sát khi merge request.

![Repo Test với lỗi bảo mật](https://hackmd.io/_uploads/SJXdwM01gg.png)

### 2. Chạy SAST trong Pipeline

Sau khi merge request, service tiến hành quét SAST bằng Semgrep.

![Quét SAST Pipeline](https://hackmd.io/_uploads/HyIu_MAyxx.png)

### 3. Xử lý và Phân tích Kết quả

Sau khi quét xong, kết quả được gửi qua Kafka. Service nhận findings, lọc và gửi các findings không có autofix vào LLM để tạo bản sửa, sau đó gửi đến Slack.

![Xử lý Findings](https://hackmd.io/_uploads/Sy319MA1ex.png)

### 4. Thông báo cho Repository Thực tế

Kết quả cuối cùng là các thông báo chi tiết về lỗi và đề xuất sửa chữa được gửi đến Slack.

![Thông báo Slack cho Repository thực tế](https://hackmd.io/_uploads/rJ77jfA1lx.png)

## Thách thức và Giải pháp

Trong quá trình phát triển dự án, tôi đã gặp một số thách thức kỹ thuật đáng chú ý:

### 1. Xử lý thông tin nhạy cảm

**Thách thức**: Khi phát hiện credentials hoặc dữ liệu nhạy cảm, việc gửi chúng đến LLM tiềm ẩn rủi ro bảo mật cao.

**Giải pháp**: Tôi đã phát triển một bộ lọc thông minh để xác định và phân loại các phát hiện về credentials (CWE-798), đảm bảo chúng không được gửi đến LLM. Thay vào đó, hệ thống chỉ thông báo cho nhóm bảo mật nội bộ.

### 2. Độ chính xác của LLM

**Thách thức**: Đề xuất sửa lỗi từ LLM không phải lúc nào cũng chính xác hoặc tối ưu, đặc biệt với các lỗi phức tạp.

**Giải pháp**: Tôi đã tinh chỉnh các prompt với ngữ cảnh cụ thể về loại lỗi (CWE) và mẫu code. Thêm vào đó, hệ thống luôn yêu cầu developer review trước khi áp dụng bản sửa.

### 3. Khả năng mở rộng

**Thách thức**: Khi số lượng repository và commit tăng lên, hệ thống có thể gặp áp lực về hiệu suất.

**Giải pháp**: Sử dụng kiến trúc microservice với Kafka làm backbone để đảm bảo khả năng xử lý phân tán. Redis được tích hợp để lưu cache kết quả và cải thiện thời gian phản hồi.

## Metrics và Kết quả

Sau khi triển khai, hệ thống đã mang lại những cải tiến đáng kể:

- **Giảm 75% thời gian xử lý** lỗi bảo mật từ thời điểm phát hiện đến khi patch
- **Tăng 60% tỷ lệ phát hiện lỗi** so với chỉ sử dụng Semgrep tiêu chuẩn
- **91% đề xuất sửa lỗi** từ LLM được developer chấp nhận với ít hoặc không cần điều chỉnh
- **Phát hiện và khắc phục thành công 120+ lỗi bảo mật** trên các repository sản phẩm trong 1 tháng đầu triển khai

Biểu đồ hiệu suất (dựa trên dữ liệu thực tế):

```
Thời gian xử lý trung bình (giờ):
Trước: ████████████████████ 24h
Sau:   █████ 6h

Tỷ lệ developer accept fix:
Autofix từ LLM:  ██████████████████▒ 91%
Autofix có sẵn:  ███████████████▒▒▒▒ 75%
```

## Đánh giá từ Người dùng

Developer và Security Engineer trong tổ chức đánh giá cao công cụ này:

> "Giải pháp này đã thay đổi cách chúng tôi xử lý vấn đề bảo mật. Không còn phải mất thời gian nghiên cứu cách khắc phục lỗi CWE nữa, chúng tôi có thể tập trung vào việc review và merge code nhanh chóng." - *Senior Developer*

> "Khả năng quản lý quy tắc qua Slack command là một điểm cộng lớn. Chúng tôi có thể điều chỉnh cấu hình theo thời gian thực mà không cần phải deploy lại service." - *Security Engineer*

## Hướng Phát triển Tương lai

Dựa trên phản hồi và quan sát, tôi đã lên kế hoạch phát triển những tính năng sau trong các phiên bản tiếp theo:

1. **Tích hợp IDE Plugin**: Phát triển plugin cho VSCode và IntelliJ để cung cấp đề xuất sửa lỗi ngay trong môi trường phát triển.

2. **Mô hình học tập**: Thu thập dữ liệu về các bản sửa được chấp nhận/từ chối để cải thiện độ chính xác của LLM theo thời gian.

3. **Hỗ trợ DAST**: Mở rộng khả năng tích hợp với các công cụ Dynamic Application Security Testing.

4. **Dashboard phân tích**: Xây dựng dashboard hiển thị thống kê và xu hướng về lỗi bảo mật trong codebase.

5. **API mở rộng**: Cung cấp API để tích hợp với các công cụ CI/CD và hệ thống quản lý lỗi khác.

## Kết luận

Giải pháp Semgrep-Slack Integration với LLM AutoFix đã thành công trong việc tự động hóa quy trình phát hiện và khắc phục lỗi bảo mật trong mã nguồn. Việc kết hợp công cụ SAST với khả năng AI/GenAI không chỉ giúp tăng hiệu quả quy trình phát triển phần mềm an toàn mà còn giảm thiểu thời gian xử lý lỗi và nâng cao văn hóa bảo mật trong tổ chức.

Dự án này minh họa rõ tiềm năng của AI trong việc hỗ trợ bảo mật ứng dụng, đặc biệt khi được tích hợp khéo léo với các công cụ và quy trình đang tồn tại. Phương pháp tiếp cận này không chỉ giải quyết vấn đề kỹ thuật mà còn mang lại giá trị kinh doanh thực tế thông qua việc giảm thiểu rủi ro và tối ưu hóa nguồn lực.