+1

Tôi xây một AI Code Reviewer. Rồi OWASP làm nó thất bại

AI coding assistant ngày càng giỏi.

Nó có thể viết code, refactor, giải thích code và thậm chí generate unit test chỉ trong vài giây.

Nhưng tôi bắt đầu tự hỏi một câu hỏi khác:

Nếu AI giúp chúng ta viết code nhanh hơn, liệu nó có thể giúp chúng ta tìm ra những lỗi mà chính chúng ta chưa nghĩ tới không?

Từ câu hỏi đó, tôi bắt đầu xây dựng EdgeGuard — một open-source VS Code extension với mục tiêu không chỉ đọc code, mà còn cố gắng tìm cách phá vỡ nó.

Ý tưởng rất đơn giản:

Try to break the code before production does.

Nhưng khi đem phiên bản đầu tiên đi test với OWASP Benchmark, tôi nhận ra EdgeGuard chưa tốt như mình nghĩ.

OWASP đã làm nó thất bại.


1. Vấn đề: AI quá tin tưởng vào code

Tôi bắt đầu thử EdgeGuard với OWASP Benchmark for Java.

Một trường hợp đơn giản có thể trông như sau:

String param = request.getParameter("id");
String bar = DatabaseHelper.doSomething(param);
String sql = "SELECT * FROM USERS WHERE ID='" + bar + "'";

Nhìn vào đoạn code này, chúng ta có thể thấy:

HTTP request
    ↓
untrusted input
    ↓
doSomething()
    ↓
SQL query

Vấn đề nằm ở doSomething().

LLM không biết chính xác method này làm gì.

Và trong lần thử nghiệm ban đầu, model đưa ra một giả định khá "đẹp":

Có thể doSomething() là một helper method dùng để sanitize input.

Kết quả là một SQL injection có thể bị đánh giá là:

SAFE

Đây chính là false negative mà tôi không muốn một security tool mắc phải.


2. Unknown code không được mặc định là safe

Sau khi debug kết quả, tôi nhận ra vấn đề không hẳn nằm ở khả năng hiểu SQL của LLM.

Vấn đề nằm ở assumption.

Khi model không biết một function làm gì, nó có xu hướng tự hoàn thiện phần còn thiếu.

Trong security analysis, đây là một assumption rất nguy hiểm.

Vì vậy tôi thay đổi cách EdgeGuard xử lý tainted data.

Một rule quan trọng được đưa vào investigation:

Nếu dữ liệu đã bị đánh dấu là tainted đi vào một function không xác định, hãy giữ nguyên trạng thái tainted cho tới khi có bằng chứng rằng dữ liệu đã được sanitize.

Với ví dụ trên, EdgeGuard sẽ theo dõi:

request.getParameter()
        ↓
    TAINTED
        ↓
doSomething()
        ↓
    TAINTED
        ↓
SQL concatenation
        ↓
Potential SQL Injection

Thay vì chỉ yêu cầu LLM trả lời:

SAFE

hoặc:

VULNERABLE

tôi muốn nó đưa ra evidence của data flow.

Ví dụ:

Step 1:
Input đến từ HTTP request nên được xem là untrusted.

Step 2:
Input đi qua một helper function không xác định.
Không có bằng chứng về việc sanitize nên taint được giữ nguyên.

Step 3:
Tainted value được nối trực tiếp vào SQL query.

Conclusion:
Potential SQL Injection.

Điểm quan trọng ở đây không phải là bắt AI "đoán đúng".

Mà là:

Hạn chế những thứ AI được phép tự giả định.


3. Vấn đề tiếp theo: Scale

Sau khi giải quyết được một phần false negative, tôi gặp một vấn đề khác.

Chi phí.

Một project lớn có thể có hàng nghìn function.

Ví dụ:

get()
set()
ToString()
Equals()
simple CRUD
DTO mapping
utility methods

Nếu gửi tất cả những function này cho LLM thì rất nhanh sẽ gặp:

  • API rate limit
  • token usage lớn
  • thời gian scan dài
  • chi phí tăng

Tôi không muốn EdgeGuard trở thành một tool mà:

Scan càng nhiều code → càng tốn tiền.

Vì vậy tôi quay lại một nguyên tắc khá đơn giản:

Start with the simplest solution, and only add complexity when the simple thing breaks.


4. Local Static Risk Screening

Thay vì để LLM xử lý toàn bộ code, EdgeGuard thêm một bước Static Risk Screening chạy local ngay bên trong VS Code.

Pipeline trở thành:

Source Code
    ↓
AST Parsing
    ↓
Static Risk Screening
    ↓
High / Medium Risk Functions
    ↓
LLM Investigation
    ↓
Evidence
    ↓
Verification

Static screening có thể tìm những dấu hiệu như:

  • Database sink
  • File-system access
  • Process execution
  • Network boundary
  • User-controlled input
  • Dangerous API
  • Missing validation

Những function rõ ràng ít rủi ro sẽ không cần gửi tới LLM.

Điều này giúp LLM tập trung vào những phần code thực sự đáng để điều tra.


5. Stress test với 7,536 functions

Sau khi có architecture mới, tôi muốn thử nó trên một project đủ lớn.

Tôi load toàn bộ OWASP Benchmark Java vào VS Code và chạy workspace scan.

Kết quả:

Files:     2,771
Functions: 7,536

Thay vì gửi toàn bộ 7,536 functions tới LLM, EdgeGuard thực hiện static screening trước.

Sau đó chỉ những function có mức risk phù hợp mới được đưa vào deeper investigation.

Trong lần test này, EdgeGuard báo cáo:

2,145 potential defects

Trong đó có các nhóm vấn đề như:

  • SQL Injection
  • Command Injection
  • Unsafe data flow
  • Input-to-sink vulnerabilities

Điều tôi quan tâm nhất không phải chỉ là con số 2,145.

Điều quan trọng hơn là architecture đã có thể chuyển từ:

Every function → LLM

sang:

Every function
      ↓
Local screening
      ↓
Interesting functions
      ↓
LLM investigation

Đây là điểm tôi thấy architecture bắt đầu có ý nghĩa.


6. Không chỉ Java

EdgeGuard không được thiết kế chỉ cho Java.

Tôi cũng thử nghiệm architecture với:

Java

OWASP Benchmark

TypeScript

OWASP Juice Shop

C#

Microsoft eShopOnWeb

Và đây lại xuất hiện một vấn đề khác.

Java, C# và TypeScript có:

  • Syntax khác nhau
  • AST khác nhau
  • Security API khác nhau
  • Project structure khác nhau

Nếu cố gắng nhét tất cả logic vào một parser chung, code sẽ nhanh chóng trở nên khó maintain.

Vì vậy tôi tách phần language-specific context khỏi investigation engine.

Ý tưởng là:

                 EdgeGuard
                     |
            Investigation Engine
                     |
       +-------------+-------------+
       |             |             |
      Java           C#       TypeScript
    Context        Context       Context
       |             |             |
      AST           AST           AST

Investigation logic có thể được dùng chung.

Nhưng context parser của từng ngôn ngữ được giữ độc lập.

Nguyên tắc tôi đang theo đuổi là:

Share the investigation logic. Isolate the language-specific context.


7. Detection chưa đủ

Trong quá trình xây EdgeGuard, tôi nhận ra một vấn đề khác.

Một AI có thể nói:

"This code might be vulnerable."

Nhưng developer vẫn phải hỏi:

"Làm sao tôi biết nó thực sự vulnerable?"

Vì vậy tôi muốn EdgeGuard tiến thêm một bước.

Thay vì chỉ đưa ra finding, agent có thể cố gắng tạo:

Potential vulnerability
        ↓
Counterexample input
        ↓
Generated test
        ↓
Execute
        ↓
Evidence

Tùy ngôn ngữ, test có thể được generate cho:

  • xUnit
  • JUnit
  • Mocha

Mục tiêu là chuyển từ:

AI nói rằng có thể có bug.

sang:

Đây là input có thể làm code thất bại, và đây là test để verify nó.

Đó cũng là lý do tôi thích một nguyên tắc:

Evidence over assumptions.


8. Điều tôi học được

Xây EdgeGuard khiến tôi thay đổi cách nhìn về AI code analysis.

Vấn đề không chỉ là:

"LLM có hiểu code không?"

Mà còn là:

"LLM đang được phép giả định điều gì?"

Nếu unknown function được mặc định là safe → có thể tạo false negative.

Nếu gửi toàn bộ code cho LLM → vấn đề scale và cost xuất hiện.

Nếu trộn context của Java, C# và TypeScript → architecture nhanh chóng trở nên khó maintain.

Vì vậy EdgeGuard đang đi theo hướng kết hợp ba lớp:

Static Analysis
      +
LLM Investigation
      +
Verification

Mỗi lớp giải quyết một vấn đề khác nhau.

Static analysis nhanh và deterministic.

LLM phù hợp với những context phức tạp và investigation khó viết rule cứng.

Verification giúp biến hypothesis thành evidence.


9. EdgeGuard đang ở đâu?

EdgeGuard hiện vẫn là một open-source project đang được phát triển.

Mục tiêu của tôi không phải xây thêm một AI coding assistant chỉ để generate code nhanh hơn.

Tôi muốn thử một hướng khác:

AI không chỉ giúp chúng ta viết code. Nó phải đủ "khó tính" để đặt câu hỏi: code này có thể sai ở đâu?

Nếu bạn muốn thử hoặc xem architecture:

GitHub: https://github.com/phucphungbk/edgeguard

Tôi rất muốn nhận feedback từ những người đang làm:

  • Software Engineering
  • Security
  • Static Analysis
  • AI coding tools
  • Unit testing

Đặc biệt tôi muốn biết:

Bạn thường tìm edge case bằng cách nào?

Bạn tin vào unit test, static analysis, code review, kinh nghiệm cá nhân hay AI?

Và quan trọng hơn:

Nếu AI nói rằng code của bạn có bug, bạn cần bằng chứng gì để tin nó?

Đó chính là vấn đề tôi đang cố gắng giải quyết với EdgeGuard.


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.