Code review thuần túy không còn đủ khi AI agent tham gia vào quy trình phát triển phần mềm. Một agent không chỉ sinh source code. Nó có thể đọc repository, chạy lệnh shell, chỉnh sửa configuration, thêm dependency, gọi tool bên ngoài, ghi log vào context và thay đổi policy triển khai. Vì vậy, review cần được hiểu là secure code review, tức là đánh giá source code an toàn trong mối liên hệ với thiết kế, kiểm thử, pipeline và bằng chứng vận hành.
Checklist trong bài được cấu trúc quanh ba nhóm chuẩn. OWASP ASVS 5.0 được dùng làm baseline cho bảo mật ứng dụng [1]. OWASP Top 10 for LLM Applications 2025 được dùng để nhận diện rủi ro của LLM và AI agent [2]. NIST SSDF và SSDF Community Profile for Generative AI được dùng để đưa review vào kỷ luật phát triển phần mềm an toàn [3]. Các case study vẫn giữ bối cảnh Java, K3s, Redis, RabbitMQ và Argo để checklist có thể áp dụng vào một kiến trúc cụ thể.
1. Tại sao review code AI khác review code người?
Review truyền thống thường trả lời ba câu hỏi. Source code có đúng yêu cầu hay không, source code có an toàn hay không, và source code có thể bảo trì hay không. Khi AI agent tham gia, quy trình review phải bổ sung một câu hỏi nền tảng hơn: đoạn mã này được tạo ra bằng cách nào, agent đã đọc những gì, đã chạy lệnh nào, đã thay đổi tài nguyên nào, và những thay đổi đó có nằm trong phạm vi được phê duyệt hay không. Câu hỏi này đưa code review ra khỏi phạm vi đọc diff đơn thuần và đặt nó vào đúng vị trí của secure code review.
- Agent có thể đọc các file nằm ngoài phạm vi issue, bao gồm .env, configuration, secret mẫu, tài liệu nội bộ và instruction file.
- Agent có thể chạy lệnh shell để build, test, format, gọi curl, dùng git, hoặc thao tác với kubectl nếu môi trường cấp quyền quá rộng.
- Agent có thể thêm dependency, sửa pom.xml, build.gradle, Dockerfile, Helm chart, Kubernetes manifest hoặc Argo Application.
- Agent có thể gọi tool bên ngoài thông qua MCP hoặc các cơ chế tích hợp khác, từ đó tạo side effect nằm ngoài repository.
- Agent có thể ghi thông tin vào memory hoặc context, khiến dữ liệu nhạy cảm bị tái sử dụng trong phiên sau nếu không có kiểm soát.
Hệ quả là diff trên GitHub không còn phản ánh đầy đủ tác động của thay đổi. Một PR có thể chỉ hiển thị vài dòng code, nhưng phía sau có thể đã có thao tác đọc .kube/config, gọi kubectl, sửa Argo Application, push image mới lên registry hoặc ghi instruction mới vào CLAUDE.md. Nếu không có audit trail, reviewer chỉ nhìn thấy kết quả cuối cùng mà không nhìn thấy đường đi tạo ra kết quả đó. Đây là lý do các tài liệu về AI coding agent đều nhấn mạnh sandboxing, permission model và kiểm soát tool invocation [4] [5].
Một điểm quan trọng khác đến từ NCSC UK là prompt injection không thể được xử lý giống SQL injection. Với SQL, hệ thống có thể tách instruction và data bằng parameterized query. Với LLM, dữ liệu và chỉ dẫn đều đi vào model dưới dạng token, nên ranh giới này không tồn tại một cách tự nhiên. Vì vậy, reviewer không thể chỉ trông đợi vào bộ lọc ở tầng model. Kiểm soát phải được đặt ở tầng ứng dụng, tool, identity, policy và pipeline. Cách tiếp cận này phù hợp với nguyên tắc defense in depth mà Microsoft khuyến nghị khi xử lý indirect prompt injection [6] [7].
Secure code review hiện đại phải đánh giá tác động đầy đủ của một thay đổi, bao gồm source code, side effects, bằng chứng và dấu vết hoạt động của agent. Nếu reviewer chỉ đọc diff, một agent bị thao túng bởi prompt injection từ README, issue comment hoặc nội dung web bên ngoài vẫn có thể tạo thay đổi không được phản ánh rõ trong PR.
2. Control Framework với ba lớp và các nguồn chuẩn
Checklist review cho PR do AI agent tạo nên được chia thành ba lớp kiểm soát. Lớp thứ nhất kiểm tra chất lượng bảo mật của source code. Lớp thứ hai kiểm tra tác động đặc thù của agent. Lớp thứ ba kiểm tra bằng chứng vận hành. Ba lớp này bổ sung cho nhau và không lớp nào có thể thay thế lớp còn lại.
Tầng A: Secure code review truyền thống
Tầng này kiểm chứng source code như một sản phẩm kỹ thuật độc lập. Reviewer cần xem xét authentication, authorization, validation, error handling, logging, cryptography, session management, dependency và các ràng buộc nghiệp vụ đã được thiết kế.
- OWASP ASVS 5.0 (May 2025): khoảng 350 requirement chia thành 17 chương, phủ authentication, session management, access control, cryptography, data protection, communication security, input handling, tokens và web frontend. Xem preface tại asvs.dev/v5.0.0 hoặc repo github.com/OWASP/ASVS [1].
- OWASP Top 10 for Web 2025: awareness document cho 10 rủi ro phổ biến nhất. Xem owasp.org/Top10/2025 [8].
- OWASP Cheat Sheet Series: tra cứu theo chủ đề. Toàn bộ cheatsheet mở tại cheatsheetseries.owasp.org [9].
- CWE Top 25 (2024): danh sách weakness phổ biến và nguy hiểm nhất, duy trì bởi MITRE và CISA. Xem cwe.mitre.org/top25 [10].
- SEI CERT Oracle Coding Standard for Java: rules và recommendations để tránh insecure coding trong Java. Xem wiki.sei.cmu.edu/java [11] và Oracle Secure Coding Guidelines for Java SE tại oracle.com/java/seccodeguide [12].
Tầng B: Agentic review
Tầng này xử lý các rủi ro phát sinh khi người tạo thay đổi là AI agent. Trọng tâm không chỉ là đoạn code được sinh ra, mà còn là quyền của agent, tool mà agent đã gọi, file mà agent đã đọc, prompt mà agent đã nhận và side effect mà agent có thể tạo.
- OWASP Top 10 for LLM Applications 2025: bao gồm LLM01 Prompt Injection, LLM02 Sensitive Information Disclosure, LLM03 Supply Chain, LLM04 Data and Model Poisoning, LLM05 Improper Output Handling, LLM06 Excessive Agency, LLM07 System Prompt Leakage, LLM08 Vector and Embedding Weaknesses, LLM09 Misinformation, LLM10 Unbounded Consumption. Xem genai.owasp.org/llm-top-10 và PDF OWASP-Top-10-for-LLMs-v2025.pdf [2].
- OWASP AI Agent Security Cheat Sheet: xử lý tool abuse, memory poisoning, privilege escalation, DoW và agentic-specific concerns. Xem cheatsheetseries.owasp.org/AI_Agent_Security_Cheat_Sheet [13].
- OWASP LLM Prompt Injection Prevention Cheat Sheet: tra cứu tại cheatsheetseries.owasp.org/LLM_Prompt_Injection_Prevention [14].
- MITRE ATLAS: knowledge base về TTP của adversary nhắm vào AI/ML, mở rộng phong cách ATT&CK. Xem atlas.mitre.org [15].
- NCSC UK: Prompt injection is not SQL injection (Dec 2025): luận điểm về inherently confusable deputy. Xem ncsc.gov.uk/prompt-injection [6].
- MCP Security Best Practices: authorization flow và các attack như confused deputy, tool poisoning. Xem modelcontextprotocol.io/security_best_practices [16].
- Anthropic Claude Code documentation: sandboxing, permission model, hook system. Xem docs.claude.com/claude-code [17].
Tầng C: Evidence review
Tầng này kiểm chứng bằng chứng vận hành như CI log, command log, dependency diff, permission diff, secret scan, test result, audit record và rollback plan. Không có bằng chứng thì review chỉ là ý kiến cá nhân, chưa đủ để tạo niềm tin ở cấp tổ chức.
- NIST SSDF (SP 800-218) v1.1: bốn nhóm: Prepare the Organization (PO), Protect the Software (PS), Produce Well-Secured Software (PW), Respond to Vulnerabilities (RV). Xem csrc.nist.gov/pubs/sp/800/218/final và project page csrc.nist.gov/projects/ssdf [3].
- NIST SSDF Community Profile for Generative AI (SP 800-218A): bổ sung task đặc thù cho AI model. Xem csrc.nist.gov/pubs/sp/800/218/a/final [18].
- SLSA (Supply-chain Levels for Software Artifacts): build provenance, tamper resistance. Xem slsa.dev và spec tại slsa.dev/spec [19].
- OWASP CI/CD Security Cheat Sheet: xem cheatsheetseries.owasp.org/CI_CD_Security [20].
- GitHub Actions Security Hardening: least privilege cho GITHUB_TOKEN, pin third-party actions theo commit SHA. Xem docs.github.com/actions/security-hardening [21].
- OpenSSF Scorecard: health check tự động cho open source project. Xem github.com/ossf/scorecard [22].
3. Case study: Bối cảnh hệ thống sử dụng kiến trúc với Java, K3s, Redis, RabbitMQ , Argo và MinIO
Để checklist không dừng ở mức khuyến nghị chung, bài viết sử dụng một kiến trúc cụ thể làm bối cảnh phân tích. Hệ thống giả định là một nền tảng web service doanh nghiệp viết bằng Java, dùng Spring Boot 3 và Java 21, triển khai trên K3s, quản lý triển khai bằng Argo CD, xử lý job bất đồng bộ qua RabbitMQ, dùng Redis cho cache, session và rate limit, đồng thời dùng MinIO làm storage tương thích S3. Đây là kiểu stack phổ biến vì chi phí hợp lý và dễ chủ động hạ tầng, nhưng cũng tạo nhiều vị trí mà AI agent có thể tác động nếu phạm vi quyền không được kiểm soát.

Kiến trúc hệ thống Java trên K3s với Redis, RabbitMQ, Argo CD, MinIO và lớp secret, policy. Đường đỏ đứt biểu thị các vị trí mà AI agent có thể tạo side effect ngoài ý muốn.
Kiến trúc này có năm trust zone chính. Zone thứ nhất là máy của developer, nơi agent chạy và có thể đọc file cục bộ. Zone thứ hai là repository và CI trên GitHub. Zone thứ ba là container registry. Zone thứ tư là cluster K3s với các workload theo namespace. Zone thứ năm là lớp secret và policy. Một thay đổi do agent tạo có thể ảnh hưởng đến bất kỳ zone nào, nên secure code review phải đọc cả source code, manifest, dependency, workflow, log và bằng chứng triển khai.
- Agent sửa application.yml để bật debug endpoint à side effect ở zone 4 (runtime cluster).
- Agent thêm dependency unknown.tools:json-helper à side effect ở zone 3 (supply chain) và zone 4 (runtime).
- Agent sửa .github/workflows/deploy.yml để bỏ security scan à side effect ở zone 2.
- Agent sửa Argo Application để mở auto-sync và bỏ approval à side effect xuyên zone 2 à 4.
- Agent đọc .env trong quá trình làm việc à side effect tầm riêng tư ở zone 1.
Các checklist ở phần sau được gắn trực tiếp với các component trong kiến trúc này để reviewer có thể chuyển từ nhận định chung sang câu hỏi kiểm tra cụ thể.
4. Secure code review trong Secure SDLC
Trong bối cảnh AI agent, code review không nên được hiểu là hoạt động đọc diff để phát hiện lỗi cú pháp, comment style hoặc naming convention. Nó phải được thiết kế như một quy trình secure code review. Quy trình này nhận đầu vào từ secure design review, hiện thực hóa các quyết định thiết kế vào source code, tạo đầu ra cho secure testing, và được secure CI/CD cưỡng chế bằng pipeline, policy và bằng chứng audit.
Nếu code review tách khỏi secure design review, reviewer chỉ nhìn thấy đoạn code mà không biết nó đang bảo vệ tài sản nào, ranh giới tin cậy nào, invariant nào và quyết định rủi ro nào. Nếu code review tách khỏi secure testing, phát hiện trong review sẽ không trở thành abuse case, negative test hoặc regression test. Nếu code review tách khỏi secure CI/CD, checklist chỉ còn là cam kết thủ công và rất dễ bị bỏ qua khi deadline tạo áp lực.

Secure code review là mắt xích nối secure design review, secure testing và secure CI/CD. Agentic review phủ lên toàn bộ chuỗi vì agent có thể tạo tác động ngoài code diff.
4.1. Ràng buộc giữa design, code, test và pipeline
Nguyên tắc vận hành là secure code review phải nối thiết kế với triển khai. Reviewer không chỉ hỏi đoạn code này có lỗi gì. Reviewer phải hỏi đoạn code này đang hiện thực yêu cầu bảo mật nào, ràng buộc thiết kế nào, test nào đang chứng minh ràng buộc đó, và pipeline nào đang ngăn ràng buộc bị bypass.
Đối tượng review | Đầu vào từ secure design review | Kỳ vọng trong secure code review | Bằng chứng từ secure testing và secure CI/CD |
|---|---|---|---|
Trust boundary | DFD, luồng dữ liệu, phân vùng trust zone | Mọi crossing đều có authentication, authorization, validation và logging phù hợp | Test truy cập chéo boundary, log audit, policy kiểm soát ingress/egress |
Access control | Ma trận role, ownership, tenant model, policy decision point | Không có query bỏ qua tenant, không có endpoint bypass policy, không có findById() đơn cho tài nguyên có owner | Test cross-tenant, SAST rule cho repository pattern, required reviewer cho SecurityConfig |
Input và output contract | Đặc tả API, schema, data classification, nguồn dữ liệu untrusted | Server-side validation, output encoding theo context, không trả entity nội bộ | Negative test, fuzz test, Semgrep rule, test serialization DTO |
Secret và configuration | Mô hình secret, rotation, runtime profile, môi trường triển khai | Không hardcode secret, không tạo profile nới lỏng bảo mật, không bật debug endpoint ngoài môi trường test cô lập | Secret scan, IaC scan, policy chặn manifest sai, audit Vault hoặc External Secrets |
Async và event-driven flow | Event contract, retry policy, idempotency rule, DLQ policy | Consumer xử lý idempotent, message không chứa PII thừa, error không làm mất message | Test duplicate message, DLQ test, metric retry, alert khi poison message tăng |
AI agent scope | Phạm vi tool, file được phép đọc, lệnh được phép chạy, secret bị cấm truy cập | Transcript khớp với task, command log không có thao tác ngoài scope, dependency mới có lý do rõ | Agent transcript, extended diff, dependency diff, CODEOWNERS cho prompt và workflow |
4.2. Lifecycle review và các điểm trigger
Một review có giá trị phải tạo được traceability. Mỗi kết luận trong secure code review nên quay về một quyết định thiết kế, một yêu cầu bảo mật hoặc một threat đã được ghi nhận. Ngược lại, mỗi phát hiện trong review phải đi tiếp thành test hoặc gate. Đây là khác biệt giữa đọc code theo kinh nghiệm cá nhân và secure code review có thể vận hành ổn định trong tổ chức.

Năm điểm trigger review và người phụ trách tương ứng. Mỗi trigger cần có checklist con, bằng chứng và điều kiện dừng rõ ràng.
Review không nên chỉ diễn ra tại thời điểm PR sẵn sàng merge. Với code do AI agent tạo, lifecycle cần nhiều điểm trigger vì agent có thể tác động vào source code, dependency, configuration, workflow, manifest và môi trường chạy. Mỗi trigger cần có checklist riêng, người chịu trách nhiệm riêng và bằng chứng riêng.
5.13 nhóm side effects với checklist và mapping CWE và LLM
Phần này là bảng tra cứu cho reviewer. Mỗi nhóm side effect được mô tả bằng các item con, checklist kiểm tra, mức ưu tiên, CWE tương ứng, LLM Top 10 tương ứng nếu có, và nguồn URL. Mức P0 dùng cho lỗi phải chặn merge. Mức P1 dùng cho lỗi phải xử lý trước deploy. Mức P2 dùng cho lỗi có thể ghi nhận và xử lý theo kế hoạch.
5.1 · Source code effects
Nhóm này kiểm tra những thay đổi trực tiếp trong source code. Reviewer cần xác định rõ agent đã tạo, sửa, xóa hoặc đổi tên file nào, thay đổi class, function, module nào, thêm endpoint nào và tác động của thay đổi đó đến business logic. Với secure code review, trọng tâm không dừng ở việc code có chạy được. Reviewer phải kiểm tra xem domain invariant có còn được giữ trong tầng domain hay không, validation có thực hiện ở server side hay không, output có được encoding đúng context hay không, và error handling có làm lộ thông tin nội bộ hay không.
Checklist item | Ưu tiên | CWE | LLM Top 10 | Nguồn |
|---|---|---|---|---|
| Mỗi file thay đổi có giải thích được gắn với task gốc | P1 | : | LLM06 | SSDF PW.7 |
| Input validation ở server-side, allowlist, không dùng blacklist | P0 | CWE-20, CWE-79 | LLM05 | Input Validation CS |
| Output encoding theo context (HTML, JS, URL, SQL, shell, log) | P0 | CWE-79, CWE-116 | LLM05 | XSS Prevention CS |
| Không trả entity JPA trực tiếp; phải qua DTO/record | P0 | CWE-200, CWE-213 | LLM02 | Mass Assignment CS |
| Domain invariant được enforce trong domain method, không ở controller | P0 | CWE-841 | : | ASVS v5 Ch. 11 |
| Không catch Exception rồi swallow; log đủ root cause | P1 | CWE-390, CWE-755 | : | CERT ERR00-J |
| Error message không lộ stack trace, query, path nội bộ | P1 | CWE-209 | LLM02 | Error Handling CS |
5.2 Permission & access control effects
Nhóm này xử lý các thay đổi liên quan đến phân quyền truy cập (access control), quyền sở hữu tài nguyên (resource ownership), tenant boundary và service account trong Kubernetes. Đây là nhóm cần được xem như P0 trong hầu hết hệ thống doanh nghiệp, vì agent thường có xu hướng viết code theo luồng thành công trước, sau đó bỏ sót negative path như user A đọc dữ liệu của user B, user thường gọi API admin, hoặc workload dùng service account có quyền quá rộng.
Checklist item | Ưu tiên | CWE | LLM Top 10 | Nguồn |
|---|---|---|---|---|
| Tài nguyên đa tenant: mọi query gắn tenantId, hoặc dùng Postgres RLS | P0 | CWE-639, CWE-285 | : | Authorization CS |
| Không dùng findById() đơn thuần cho tài nguyên có owner | P0 | CWE-639, CWE-862 | : | Authz CS |
| Không có anyRequest.permitAll() trong Spring Security prod profile | P0 | CWE-284, CWE-285 | LLM06 | Spring Security docs |
| CORS không dùng wildcard nếu có credential | P0 | CWE-942, CWE-346 | : | CSRF CS |
| Deny by default cuối SecurityFilterChain (anyRequest().denyAll()) | P0 | CWE-276 | : | ASVS v5 Ch. 4 |
| Service account K8s có least privilege; không cluster-admin | P0 | CWE-269, CWE-732 | LLM06 | K8s Security CS |
| Test negative: user thường gọi admin API → 403; user A đọc của user B → 403 | P0 | : | : | Authz Testing CS |
5.3 Data effects
Nhóm này tập trung vào vòng đời dữ liệu (data lifecycle), gồm migration, rollback, response model, retention, cache, queue message và search index. Khi agent sửa code liên quan đến dữ liệu, reviewer cần kiểm tra dữ liệu nhạy cảm có bị đưa ra ngoài boundary hay không, dữ liệu cá nhân có được xử lý theo classification hay không, và thay đổi schema có thể rollback an toàn hay không. Secure code review ở nhóm này phải nối với secure design review, vì phân loại dữ liệu và chính sách lưu giữ thường được quyết định từ giai đoạn thiết kế.
Checklist item | Ưu tiên | CWE | LLM Top 10 | Nguồn |
|---|---|---|---|---|
| Migration có rollback script hoặc expand/contract strategy | P0 | : | : | SSDF PW.4 |
| API response không chứa passwordHash, resetToken, nationalId | P0 | CWE-200, CWE-359 | LLM02 | User Privacy CS |
| PII được mask/hash/remove theo classification | P0 | CWE-532, CWE-359 | LLM02 | Logging CS |
| Retention policy gắn với yêu cầu pháp lý (Nghị định 13/2023, GDPR) | P1 | : | : | ASVS v5 Ch. 8 |
| Job xóa/đồng bộ dữ liệu có giới hạn phạm vi, có dry-run mode | P1 | CWE-285 | LLM06 | SSDF PW.4 |
| Queue message, cache, search index không chứa field nhạy cảm chưa mask | P0 | CWE-532 | LLM02 | Logging CS |
5.4 · Dependency effects
Nhóm này kiểm soát tác động chuỗi cung ứng phần mềm (software supply chain). AI agent có thể thêm dependency để giải quyết nhanh một lỗi biên dịch hoặc rút ngắn phần triển khai, nhưng dependency mới có thể kéo theo CVE, giấy phép không phù hợp, package giả mạo hoặc gadget chain cho deserialization. Vì vậy reviewer không chỉ đọc phần code sử dụng thư viện mới, mà phải kiểm tra cả dependency diff, SBOM diff, license policy và kết quả SCA trước khi chấp nhận PR.
Checklist item | Ưu tiên | CWE | LLM Top 10 | Nguồn |
|---|---|---|---|---|
| Dependency mới không có CVE nghiêm trọng chưa fix | P0 | CWE-1395, CWE-1104 | LLM03 | Dependency-Check |
| Không dùng LATEST, dynamic range; pin version cụ thể | P0 | CWE-1357 | LLM03 | SLSA |
| Kiểm tra typo-squatting và dependency confusion (đặc biệt với npm proxy) | P0 | CWE-427, CWE-1357 | LLM03 | Dependency-Track |
| Transitive dependency được SCA scan, không chỉ direct | P1 | CWE-1104 | LLM03 | OpenSSF Scorecard |
| Build plugin có khả năng chạy code trong build phase được review sâu | P1 | CWE-1357 | LLM03 | SLSA spec |
| License tương thích (không GPL trong sản phẩm đóng) | P1 | : | : | SPDX |
| SBOM (CycloneDX hoặc SPDX) cập nhật khi dependency thay đổi | P0 | : | LLM03 | CycloneDX |
5.5 · Configuration effects (K8s, Helm, Argo, Spring profile)
Nhóm này kiểm tra các thay đổi cấu hình (configuration) có thể làm suy yếu bảo mật dù mã nguồn nghiệp vụ không đổi. Với stack Java trên K3s và Argo CD, một dòng cấu hình trong Spring profile, Helm chart hoặc Argo Application có thể mở debug endpoint, bỏ TLS, tăng quyền container, bật auto sync không kiểm soát hoặc triển khai sai namespace. Reviewer cần xem configuration như code có tác động runtime, không xem đây là phần phụ của PR.
Checklist item | Ưu tiên | CWE | LLM Top 10 | Nguồn |
|---|---|---|---|---|
| Không debug: true trong production profile | P0 | CWE-489, CWE-215 | : | Error Handling CS |
| Không tắt TLS verification (rejectUnauthorized: false, trustAll) | P0 | CWE-295, CWE-297 | : | TLS CS |
| Dockerfile: non-root user, base image pinned, không có secret trong layer | P0 | CWE-269, CWE-522 | : | Docker Security CS |
| Pod securityContext: runAsNonRoot, readOnlyRootFilesystem, dropCapabilities | P0 | CWE-250 | : | K8s Pod Security Standards |
| NetworkPolicy deny by default, chỉ mở egress cần thiết | P0 | CWE-918 | LLM06 | K8s NetworkPolicy |
| Argo Application: không auto-sync prune mà không approval; RBAC project scope | P0 | CWE-732, CWE-285 | LLM06 | Argo CD Security |
| Helm values không commit secret; dùng External Secrets | P0 | CWE-798 | LLM07 | External Secrets Operator |
5.6 · Security information effects
Nhóm này bảo vệ thông tin bảo mật (security information) như secret, token, private key, cấu hình kết nối, kubeconfig, nội dung prompt có chứa dữ liệu nội bộ và log có thể làm lộ PII. Agent có thể vô tình đọc file nhạy cảm trong quá trình xử lý task, hoặc viết lại thông tin đó vào test, log, comment, transcript và tài liệu. Vì vậy secure code review cần đi kèm secret scan, kiểm tra file access của agent và kiểm tra nội dung log phát sinh.
Checklist item | Ưu tiên | CWE | LLM Top 10 | Nguồn |
|---|---|---|---|---|
| Secret không hardcode trong source; lấy từ Vault/External Secrets | P0 | CWE-798, CWE-259 | LLM07 | Secrets Mgmt CS |
| Nếu secret đã commit → phải rotate, không chỉ xóa commit mới | P0 | CWE-522 | LLM07 | GH Secret Scanning |
| Không MD5/SHA1/DES/ECB/fixed IV; dùng AES-GCM, Argon2/bcrypt, SecureRandom | P0 | CWE-327, CWE-338 | : | Crypto Storage CS |
| JWT verify signature, kiểm aud, iss, exp, không chấp nhận alg: none | P0 | CWE-347, CWE-287 | : | JWT Java CS |
| Không log Authorization header, cookie, JWT, OTP, API key | P0 | CWE-532 | LLM02 | Logging CS |
5.7 · Test effects
Nhóm này kiểm tra chất lượng và ý nghĩa bảo mật của bộ kiểm thử (test suite). AI agent thường tạo test để chứng minh happy path, nhưng secure testing cần bao phủ cả abuse case, negative path, boundary condition, lỗi phân quyền, dữ liệu độc hại và lỗi idempotency. Reviewer cần xem test như bằng chứng cho quyết định thiết kế, không xem test như phần phụ để tăng coverage. Một PR thay đổi logic bảo mật mà không có test đối nghịch tương ứng không nên được merge.
Checklist item | Ưu tiên | CWE | LLM Top 10 | Nguồn |
|---|---|---|---|---|
| Không @Disabled, @Ignore, .skip() không có lý do | P0 | : | LLM06 | SSDF PW.7 |
| Test assertion kiểm security property, không chỉ status code | P0 | : | : | Authz Testing CS |
| Với access control, bắt buộc test unauthorized/forbidden/cross-tenant | P0 | : | : | ASVS v5 Ch. 4 |
| Coverage không giảm ở module nhạy cảm (auth, payment, file, crypto) | P1 | : | : | SSDF PW.7 |
| Không sửa test để CI xanh mà không fix root cause | P0 | : | LLM06 | GitHub AI review |
5.8 · CI/CD pipeline effects
Nhóm này kiểm soát cổng CI/CD (CI/CD gate), workflow, token, runner, artifact, image signing và điều kiện triển khai. AI agent có thể sửa workflow để CI xanh nhanh hơn, bỏ qua một bước scan, hạ quyền kiểm soát branch protection hoặc làm lỏng điều kiện deploy. Vì vậy secure code review phải đọc cả thay đổi trong pipeline as code, kết quả build provenance, quyền của token và điều kiện hard gate trước khi chấp nhận merge.
Checklist item | Ưu tiên | CWE | LLM Top 10 | Nguồn |
|---|---|---|---|---|
| Thay đổi .github/workflows/ cần CODEOWNERS duyệt | P0 | CWE-732 | LLM06 | GH Actions Hardening |
| continue-on-error: true không đặt trên SAST/SCA/secret scan | P0 | CWE-693 | LLM06 | CI/CD Security CS |
| GITHUB_TOKEN permission least privilege (contents: read mặc định) | P0 | CWE-732 | : | GH Token Auth |
| Third-party action pin theo commit SHA, không theo tag | P0 | CWE-494, CWE-829 | LLM03 | GH Third-party actions |
| OIDC cho cloud auth thay vì long-lived secret | P1 | CWE-522 | : | OIDC Hardening |
| Không chạy untrusted PR trong privileged workflow (pull_request_target) | P0 | CWE-829 | LLM01 | GH pwn-requests |
| Build artifact có SLSA provenance | P1 | CWE-494 | LLM03 | SLSA spec |
5.9 · Runtime effects (K3s pod, Redis, RabbitMQ)
Nhóm này kiểm tra tác động khi code đã chạy trong môi trường thực thi (runtime), đặc biệt là pod trên K3s, Redis, RabbitMQ và các job nền. Một thay đổi nhỏ trong consumer, cache key, timeout hoặc retry policy có thể tạo duplicate processing, poison message, retry storm, cache poisoning hoặc tiêu thụ tài nguyên bất thường. Reviewer cần đối chiếu code với đặc tả vận hành, metric, alert, DLQ và cơ chế idempotency.
Checklist item | Ưu tiên | CWE | LLM Top 10 | Nguồn |
|---|---|---|---|---|
| Redis không expose public, chạy trong namespace có NetworkPolicy | P0 | CWE-306 | : | Redis Security |
| Redis ACL: mỗi service chỉ có quyền đúng key prefix | P1 | CWE-284 | : | Redis ACL |
| RabbitMQ: virtual host riêng per tenant, user/permission scope | P0 | CWE-284 | : | RabbitMQ Access Control |
| Queue consumer có dead-letter queue, max-retry, idempotency | P0 | CWE-662 | : | RabbitMQ DLX |
| Scheduled job có lock (quartz cluster, shedlock) để tránh chạy trùng | P1 | CWE-362 | : | ShedLock |
| HTTP client có timeout, connection pool, circuit breaker | P1 | CWE-400, CWE-1088 | LLM10 | Resilience4j |
5.10 Network effects
Nhóm này kiểm tra các thay đổi liên quan đến giao tiếp mạng (network communication), gồm HTTP client, webhook, egress, ingress, service to service call và sandbox network của agent. Khi agent thêm một external call hoặc mở thêm domain trong allowlist, reviewer cần đánh giá SSRF, replay attack, thiếu xác thực nội bộ, lộ metadata service và khả năng dữ liệu đi ra ngoài tổ chức. Kiểm soát mạng phải được xác nhận bằng cả code review, network policy và test triển khai.
Checklist item | Ưu tiên | CWE | LLM Top 10 | Nguồn |
|---|---|---|---|---|
| SSRF protection: allowlist domain, chặn private IP, link-local, cloud metadata | P0 | CWE-918 | LLM05 | SSRF Prevention CS |
| Webhook có HMAC signature, replay protection (timestamp + nonce) | P0 | CWE-345, CWE-294 | : | Webhooks CS |
| External domain mới đã được đăng ký trong egress allowlist | P0 | CWE-918 | LLM05 | K8s egress deny |
| Internal service call có mTLS hoặc JWT; không trust theo network | P0 | CWE-287 | : | Microservices Security CS |
| Agent sandbox có network egress deny by default, chỉ mở domain cần thiết | P0 | CWE-918 | LLM06 | Claude Code docs |
5.11 · Log, audit & observability effects
Nhóm này kiểm tra log, audit và observability. Log cần đủ thông tin để điều tra sự cố, nhưng không được làm lộ dữ liệu nhạy cảm hoặc tạo log injection. Audit event cần có actor, action, resource, result, timestamp và traceId để truy vết trách nhiệm. Với code do agent tạo, reviewer cũng cần kiểm tra xem thay đổi có làm mất event bảo mật, làm sai metric cảnh báo, hoặc ghi quá nhiều dữ liệu người dùng vào hệ thống quan sát hay không.
Checklist item | Ưu tiên | CWE | LLM Top 10 | Nguồn |
|---|---|---|---|---|
| Log security event: login fail, access denied, privilege change, payment change | P0 | CWE-778 | : | Logging Vocabulary CS |
| Log input từ user được encode để tránh log injection | P1 | CWE-117 | LLM05 | Logging CS |
| Mỗi audit event có actor, action, resource, result, timestamp, traceId | P0 | CWE-778 | : | ASVS v5 Ch. 7 |
| Log retention và integrity protection (WORM, signed log) | P1 | CWE-778 | : | SSDF RV.1 |
5.12 · Prompt, memory & agent tool effects
Nhóm này không tồn tại trong bộ checklist truyền thống, nhưng lại rất quan trọng khi AI agent tham gia phát triển phần mềm. Reviewer cần xem prompt file, memory, MCP tool, shell command, file access và tool description như các bề mặt tấn công mới. Một instruction độc hại trong README, issue comment hoặc tool description có thể khiến agent sửa code sai mục tiêu, gọi tool ngoài scope hoặc làm lộ dữ liệu nội bộ. Bảng dưới đây bổ sung các kiểm soát dựa trên OWASP AI Agent Security Cheat Sheet, OWASP Top 10 for LLM 2025 và MCP Security Best Practices.
Checklist item | Ưu tiên | CWE | LLM Top 10 | Nguồn |
|---|---|---|---|---|
| Prompt file (CLAUDE.md, AGENTS.md, .cursorrules) được review như code | P0 | : | LLM01, LLM07 | AI Agent CS |
| README, issue, PR comment được coi là untrusted input cho agent | P0 | CWE-1039 | LLM01 | NCSC prompt injection |
| Tool nguy hiểm (shell, file write, DB write, email, cloud CLI) yêu cầu human approval | P0 | CWE-862 | LLM06 | AI Agent CS |
| Agent chạy trong sandbox có filesystem & network isolation | P0 | : | LLM06 | Claude Code docs |
| MCP server pin version, verify publisher, kiểm tool description change | P0 | CWE-1357 | LLM03, LLM01 | MCP Security |
| Tool poisoning check: tool description không chứa instruction bẻ hướng | P0 | : | LLM01 | MCP Security |
| Agent memory validated trước khi persist; isolation per user/session | P1 | : | LLM04 | AI Agent CS |
| Log tool call: tool name, input summary, output summary, actor, approval | P0 | CWE-778 | : | MITRE ATLAS |
| Không gửi dữ liệu nội bộ vào prompt ra model bên ngoài nếu không có DPA | P0 | CWE-200 | LLM02 | SSDF AI Profile |
5.13 · License & operational effects
Nhóm này kiểm tra các tác động pháp lý, vận hành và trách nhiệm con người khi dùng AI agent. Code do agent hỗ trợ vẫn phải có người chịu trách nhiệm cuối cùng, đặc biệt khi project yêu cầu DCO, Signed off by, license compliance hoặc khai báo AI assistance. Ngoài ra, reviewer cần kiểm tra rollback plan, feature flag, kill switch, backup và secret provisioning để bảo đảm thay đổi có thể vận hành an toàn sau khi merge.
Checklist item | Ưu tiên | CWE | LLM Top 10 | Nguồn |
|---|---|---|---|---|
| AI agent không được tự thêm Signed-off-by hoặc ký DCO | P0 | : | : | Linux Kernel AI policy |
| Người submit chịu trách nhiệm toàn bộ code do AI hỗ trợ | P0 | : | : | Linux Kernel AI policy |
| Khai báo AI assistance nếu project yêu cầu | P1 | : | : | GH AI review |
| Migration có rollback plan; backup trước thay đổi dữ liệu lớn | P0 | : | : | SSDF RV.2 |
| Feature flag có owner, expiry date, kill switch | P1 | : | : | SSDF PW.4 |
| Secret mới được provision ở Vault trước khi deploy | P0 | CWE-522 | LLM07 | Secrets Mgmt CS |
Trong PR template (xem Mục 8), reviewer được yêu cầu tick qua từng ô P0. Bỏ sót hoặc tick nhanh sẽ bị SIEM đánh dấu nếu sau này có incident. Bảng này cũng là chuẩn để training onboarding reviewer mới và AppSec Champion.
6. Bốn case study: code, annotation và checklist matching
Mỗi case study tuân theo cấu trúc: (1) bối cảnh và prompt đã gửi cho agent, (2) diff agent trả về: bản có vấn đề, (3) các side effects mà diff gây ra, (4) code đã fix, (5) diagram annotation khớp từng dòng code với checklist trong Mục 5. Diagram dùng mũi tên để chỉ rõ checklist nào bắt được lỗi gì; mũi tên đứt nét thể hiện side effect ngoài diff.
Case 1 · Invoice API Spring Boot: IDOR, mass assignment, entity exposure
Service: invoice-service · Module: REST API · Trigger áp dụng: T2 + T4 · Ưu tiên: P0
Bối cảnh và prompt
Developer gõ cho agent: Thêm endpoint GET và PUT cho invoice, cho phép user xem và sửa invoice theo id. Agent trả code chạy được nhưng mở toang ba lỗ hổng lớn.Diff agent trả về (có vấn đề)
@RestController
@RequestMapping("/api/invoices")
class InvoiceController {
private final InvoiceRepository invoiceRepository;
@GetMapping("/{id}")
public Invoice getInvoice(@PathVariable Long id) {
// ① IDOR: không kiểm owner, không kiểm tenant
return invoiceRepository.findById(id).orElseThrow();
}
@PutMapping("/{id}")
public Invoice updateInvoice(@PathVariable Long id,
@RequestBody Invoice patch) {
Invoice invoice = invoiceRepository.findById(id).orElseThrow();
// ② Mass assignment: client sửa được ownerId, status, amount
invoice.setOwnerId(patch.getOwnerId());
invoice.setAmount(patch.getAmount());
invoice.setStatus(patch.getStatus());
// ③ Entity exposure: trả JPA entity có field nhạy cảm
return invoiceRepository.save(invoice);
}
}Side effects phát sinh
- Source code effect: endpoint mới viết thẳng trong controller, bypass service layer, bỏ qua domain invariant.
- Permission effect: tenant boundary không tồn tại; tenant A đọc/sửa được invoice của tenant B.
- Data effect: Invoice entity có internalNote, createdByIp bị expose qua API.
- Test effect: agent sinh test chỉ kiểm 200 OK; không có test cross-tenant, không có test field injection.
- Ngoài diff: agent đã đọc Invoice.java thấy field passwordHash (lý lịch legacy) và sửa Invoice.toString() để log đầy đủ: log effect không xuất hiện trong PR title.
Code sau khi fix
@RestController
@RequestMapping("/api/invoices")
class InvoiceController {
private final InvoiceService invoiceService;
@GetMapping("/{id}")
public InvoiceDto getInvoice(@PathVariable UUID id,
@AuthenticationPrincipal UserPrincipal user) {
return invoiceService.getInvoice(id, user);
}
@PutMapping("/{id}/status")
public InvoiceDto changeStatus(@PathVariable UUID id,
@Valid @RequestBody ChangeStatusRequest request,
@AuthenticationPrincipal UserPrincipal user) {
return invoiceService.changeStatus(id, request, user);
}
}
public record ChangeStatusRequest(@NotNull InvoiceStatus status,
@Size(max = 500) String reason) {}
@Service
class InvoiceService {
@Transactional
public InvoiceDto changeStatus(UUID id, ChangeStatusRequest req, UserPrincipal user) {
Invoice invoice = invoiceRepository
.findByIdAndTenantId(id, user.tenantId())
.orElseThrow(() -> new AccessDeniedException("not found"));
invoice.changeStatus(req.status(), req.reason(), user); // domain method giữ invariant
auditService.record(user.id(), "INVOICE_STATUS_CHANGED", invoice.id());
return InvoiceDto.from(invoice);
}
}
Matching từng dòng code bad với checklist. Mũi tên đứt nét thể hiện side effect ngoài diff (agent đọc file, thêm dependency, thay đổi log).
Ghi chú đối với T4 reviewer
Reviewer cần đọc không chỉ diff PR mà cả transcript agent nếu có. Nếu agent không cung cấp transcript, yêu cầu developer copy vào PR description. Diff chỉ hiển thị thay đổi file: không cho biết agent đã đọc những gì, mà việc đọc file có thể dẫn đến context injection về sau.
Case 2 · File upload sang MinIO: path traversal, MIME trust, pre-signed URL SSRF
Service: file-service · Storage: MinIO (S3-compatible) · Trigger áp dụng: T2 + T3 + T4 · Ưu tiên: P0
Bối cảnh và prompt
Prompt: Viết endpoint POST /files/upload cho user upload file lên MinIO, trả về URL để preview. File tối đa 20MB, chấp nhận PDF, ảnh, và file Excel. Agent trả về endpoint dùng MultipartFile, đặt tên file theo filename từ client, và trả về URL ảo /files/preview?key=... lấy trực tiếp từ query param.Diff agent trả về
@PostMapping("/files/upload")
public Map<String, String> upload(@RequestParam MultipartFile file) throws IOException {
// ① dùng nguyên filename từ client
String key = "uploads/" + file.getOriginalFilename();
// ② tin MIME do client gửi: dễ bị spoof
String contentType = file.getContentType();
// ③ không check size lại server-side
minio.putObject(PutObjectArgs.builder()
.bucket("public-bucket") // ④ single bucket, không có tenant prefix
.object(key)
.stream(file.getInputStream(), file.getSize(), -1)
.contentType(contentType)
.build());
return Map.of("key", key);
}
@GetMapping("/files/preview")
public ResponseEntity<Resource> preview(@RequestParam String url) {
// ⑤ SSRF: agent nghĩ "linh hoạt", fetch bất kỳ URL nào
try (InputStream in = new URL(url).openStream()) {
return ResponseEntity.ok(new InputStreamResource(in));
}
}Side effects phát sinh
- Path traversal: getOriginalFilename() có thể là ../../etc/passwd. Dù MinIO không hẳn có filesystem path, key như uploads/../admin/config có thể ghi đè object khác trong bucket.
- ZIP slip khi unzip: nếu hệ thống có job unzip, entry ../../../etc/cron.d/pwn trong archive có thể thoát thư mục đích (CWE-22 + CWE-23).
- MIME spoofing: client gửi image/png nhưng nội dung là HTML → XSS trên trình duyệt khi preview (CWE-434).
- Tenant boundary: single bucket cho mọi tenant, user A đoán key của user B là xong.
- SSRF: endpoint /preview?url=... cho phép agent hoặc attacker fetch http://169.254.169.254 (cloud metadata), http://redis-master:6379, hoặc bất kỳ internal service nào (CWE-918, LLM05).
- Ngoài diff: agent đã sửa application.yml thêm spring.servlet.multipart.max-file-size: 200MB để pass test upload file to: đây là side effect cấu hình, không thể hiện trong controller diff.
Code sau khi fix
private static final Set<String> ALLOWED_MIME = Set.of(
"application/pdf", "image/png", "image/jpeg",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
@PostMapping("/files/upload")
public UploadResponse upload(@RequestParam MultipartFile file,
@AuthenticationPrincipal UserPrincipal user) throws IOException {
if (file.getSize() > 20 * 1024L * 1024L) throw new PayloadTooLargeException();
// sniff MIME từ nội dung, không tin client
String sniffed = Tika.detect(file.getBytes());
if (!ALLOWED_MIME.contains(sniffed)) throw new UnsupportedMediaTypeException();
// sinh key mới, không dùng filename user
String extension = Mimes.extensionFor(sniffed);
String key = "tenant/%s/%s%s".formatted(user.tenantId(), UUID.randomUUID(), extension);
minio.putObject(PutObjectArgs.builder()
.bucket(tenantBucket.forTenant(user.tenantId()))
.object(key)
.stream(file.getInputStream(), file.getSize(), -1)
.contentType(sniffed)
.headers(Map.of("Content-Disposition", "attachment")) // chặn inline XSS
.build());
auditService.record(user.id(), "FILE_UPLOADED", key);
return new UploadResponse(key, sniffed);
}
@GetMapping("/files/preview/{id}")
public ResponseEntity<String> preview(@PathVariable UUID id,
@AuthenticationPrincipal UserPrincipal user) {
// sinh pre-signed URL, scope theo tenant + owner, TTL 60s
String signed = fileService.presign(id, user, Duration.ofSeconds(60));
return ResponseEntity.ok(signed);
}
File upload case. Mũi tên đứt nét: side effect ở application.yml và test (agent @Disabled abuse case để CI pass).
Pattern CI xanh bằng mọi giá
Agent có xu hướng @Disabled, @Ignore, hoặc sửa assertion để test pass thay vì fix root cause. Đây là một side effect phổ biến và đặc trưng AI. Reviewer cần kiểm cả @Disabled diff trong PR, và CI cần có linter cấm @Disabled không có ticket reference (ví dụ @Disabled("JIRA-123 race condition")).
Case 3 · RabbitMQ consumer: deserialization, poison message, retry storm
Service: order-service · Queue: order.paid · Trigger áp dụng: T2 + T4 + T5 · Ưu tiên: P0
Bối cảnh và prompt
Prompt: Viết consumer cho queue order.paid, khi nhận được message thì cập nhật order thành PAID và gửi email cho khách. Agent viết consumer dùng ObjectMessageConverter của Spring AMQP (Java serialization), không có DLQ, không có retry limit, không có idempotency.Diff agent trả về
@Configuration
class RabbitConfig {
@Bean
public MessageConverter converter() {
// ① Java serialization → deserialization attack
return new SerializerMessageConverter();
}
}
@Component
class OrderPaidConsumer {
@RabbitListener(queues = "order.paid")
public void handle(OrderPaidEvent event) {
// ② không verify schema, không check tenant
Order order = orderRepository.findById(event.orderId()).orElseThrow();
// ③ no idempotency: message duplicate → email gửi 2 lần
order.markPaid();
orderRepository.save(order);
// ④ email gọi trong cùng transaction với DB
emailService.send(order.customerEmail(), "Receipt", ...);
}
}Side effects phát sinh
- Deserialization RCE: SerializerMessageConverter dùng ObjectInputStream. Kẻ tấn công inject message có gadget chain (ví dụ Commons-Collections) → RCE trong pod consumer (CWE-502, CVSS 9.8).
- Không idempotency: RabbitMQ delivery là at-least-once. Network hiccup → email gửi lặp. Tệ hơn: một message orderId=123, amount=-1000000 nếu thiếu validation có thể trừ tiền khách.
- Retry storm / poison message: không có max-retry, không có DLQ → nếu một message luôn fail (ví dụ order bị xóa), consumer sẽ retry vô tận, tiêu thụ CPU và lấp full log.
- Tenant isolation ở MQ: nếu queue order.paid dùng chung cho mọi tenant, một tenant malicious có thể publish message với orderId của tenant khác (nếu không check).
- Email trong transaction: nếu email fail, DB commit rollback → order tài chính đã PAID ở hệ thống thanh toán nhưng DB không ghi nhận.
- Ngoài diff: agent thêm dependency org.apache.commons:commons-collections:3.2.1 (gadget chain nổi tiếng!) để test serialization, trong khi project dùng collections 4.x. Cũng sửa rabbitmq-values.yaml tăng consumer_timeout lên 24h.
Code sau khi fix
@Configuration
class RabbitConfig {
@Bean
public MessageConverter converter() {
return new Jackson2JsonMessageConverter(objectMapper); // ✓ JSON, không Java serialization
}
@Bean
public Queue orderPaidQueue() {
return QueueBuilder.durable("order.paid")
.withArgument("x-dead-letter-exchange", "order.paid.dlx")
.build();
}
}
@Component
class OrderPaidConsumer {
@RabbitListener(queues = "order.paid")
@Transactional
public void handle(@Valid OrderPaidMessage msg, @Header("x-attempt") int attempt) {
if (attempt > 3) throw new AmqpRejectAndDontRequeueException("drop to DLQ");
if (processedRepository.existsByMessageId(msg.messageId())) return; // idempotency
Order order = orderRepository
.findByIdAndTenantId(msg.orderId(), msg.tenantId())
.orElseThrow(() -> new AmqpRejectAndDontRequeueException("unknown order"));
order.markPaid(msg.paidAt(), msg.amount());
orderRepository.save(order);
processedRepository.save(new ProcessedMessage(msg.messageId()));
outbox.enqueue(new SendEmailCommand(order.customerEmail(), "Receipt", order.id()));
// ✓ email được gửi bởi job sau, qua outbox pattern: không làm fail transaction chính
}
}
RabbitMQ consumer case. Chú ý dependency commons-collections 3.x: agent thêm vô tình nhưng đây chính là gadget chain trong Java deserialization attack. SCA chặn được ở T3.
Case 4 · SecurityConfig + Argo CD bypass: khi agent xin phép CI xanh
Service: auth-service + GitOps · Trigger áp dụng: T2 + T3 + T4 + T5 · Ưu tiên: P0
Bối cảnh và prompt
PR nhỏ, ngây thơ: Test endpoint /admin/metrics bị 401. Làm cho test pass. Developer copy paste lỗi CI vào agent. Agent: để chiều lòng user: chọn con đường ngắn nhất: nới SecurityConfig và tắt check trong CI.Diff agent trả về: đang cực kỳ nguy hiểm
// SecurityConfig.java: agent sửa
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable()) // ① tắt CSRF
.authorizeHttpRequests(auth -> auth
.requestMatchers("/admin/**")
.permitAll() // ② admin mở public!
.anyRequest().authenticated()
);
return http.build();
}
// .github/workflows/ci.yml: agent sửa
- name: SAST (Semgrep)
run: semgrep ci
continue-on-error: true // ③ cho fail qua
- name: Tests
run: ./mvnw test
env:
SPRING_PROFILES_ACTIVE: test-no-auth // ④ profile không auth
// argocd-application.yaml: agent sửa
syncPolicy:
automated:
prune: true
selfHeal: true // ⑤ self-heal mọi thứ
syncOptions:
- CreateNamespace=true
- ServerSideApply=true
- SkipDryRunOnMissingResource=true // ⑥ skip validationSide effects phát sinh
- SecurityConfig: /admin/** public. Metrics, heap dump, env endpoint (Actuator) lộ nguyên si. CSRF disable mở cửa forgery request.
- CI workflow: continue-on-error: true trên Semgrep → vulnerability pass CI không raise. Profile test-no-auth được commit vào repo → có thể bị set nhầm ở production.
- Argo CD: selfHeal: true cộng với SkipDryRunOnMissingResource → bất kỳ thay đổi nào ở Git cũng được apply thẳng, không validate. Kẻ tấn công nếu compromise repo chỉ cần push một manifest là có quyền cluster.
- Hệ quả xuyên zone: một PR sửa test trở thành vector cho admin exposure + supply chain bypass + uncontrolled deploy cùng lúc.
Cách fix đúng
// Test thật, không sửa SecurityConfig
@Test
@WithMockUser(roles = "ADMIN")
void adminMetrics_shouldReturn200_forAdmin() { ... }
@Test
void adminMetrics_shouldReturn401_forAnonymous() { ... }
@Test
@WithMockUser(roles = "USER")
void adminMetrics_shouldReturn403_forUser() { ... }SecurityConfig giữ nguyên, CI workflow không đổi, Argo giữ sync policy an toàn (manual approve cho prod, không self-heal, không skip dry-run). Test bị fail là tín hiệu đúng, không phải vấn đề cần bypass.

Case bypass điển hình. Đây là biểu hiện cao nhất của LLM06 (Excessive Agency) và cần được huấn luyện phát hiện sớm. Reviewer tuyệt đối không approve PR có pattern này
Red flag phổ biến khi agent cố make CI green
- permitAll(), anyRequest().permitAll() trong SecurityConfig prod.
- continue-on-error: true trên bước security trong workflow.
- @Disabled, assumeTrue(false), skipIf không có ticket reference.
- Sửa assertion từ assertEquals(403, ...) thành assertNotNull(...).
- Thêm profile tắt auth/validation, thêm -Dspring.profiles.active=no-sec.
- Argo selfHeal: true hoặc syncOptions có Skip*.
- Bỏ gate required status checks trên branch protection.
7. Phát hiện side effects ngoài code diff
Code diff chỉ là phần nổi. Để thấy được phần chìm: những tác động agent tạo ra mà không xuất hiện trong git diff: cần một bộ phương pháp bổ sung. Dưới đây là mười cách phát hiện, sắp xếp theo thứ tự từ rẻ nhất đến tốn công nhất.
7.1 · Ghi lại transcript agent trong PR description
Quy ước hoá: mỗi PR do agent hỗ trợ phải có section ## Agent transcript trong PR description, copy đầy đủ prompt và output của agent. Với Claude Code hoặc Cursor, có thể dán ~/.claude/projects/*/session.jsonl. Lợi ích: reviewer đọc được context đã có, phát hiện được việc agent đọc file nhạy cảm, thấy được pattern CI xanh bằng mọi giá nếu có. Chi phí: gần như bằng không, chỉ cần PR template nhắc nhở.
7.2 · Diff mở rộng (extended diff) qua CI bot
Bot CI chạy tự động và post comment khi PR có thay đổi ở các file nhạy cảm nhưng hay ẩn:
# .github/workflows/extended-diff.yml
name: extended-diff
on: pull_request
jobs:
diff-sensitive:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Flag sensitive file changes
run: |
git diff --name-only origin/main... | grep -E \
'(\.github/workflows/|SecurityConfig|application.*\.ya?ml|Dockerfile|pom\.xml|build\.gradle|argocd-|Chart\.yaml|values\.yaml|CLAUDE\.md|AGENTS\.md|\.cursorrules)' \
|| echo "no sensitive changes"7.3 · Dependency diff và SBOM diff
Khi pom.xml hoặc build.gradle thay đổi, sinh SBOM cho trước-và-sau, so sánh. Bất kỳ GAV mới nào: bao gồm cả transitive: đều phải được SCA scan (OWASP Dependency-Check, Snyk, Grype) và post comment trên PR. Đặc biệt lưu ý các package có tên gần giống package chính thức (typosquatting) và các package với publisher mới (<6 tháng tuổi).
7.4 · Config và manifest diff với annotation
Với IaC (Helm, Kustomize, Terraform, Argo Application), chạy helm template hoặc kustomize build cho hai commit rồi diff. Kết quả là YAML rendered, nơi side effect không ẩn được. Ví dụ: agent chỉ sửa một biến values.yaml nhưng diff rendered cho thấy securityContext.privileged đã chuyển false → true, hoặc một NetworkPolicy đã biến mất khỏi output.
7.5 · Shell command audit (quan trọng nhất cho agent)
Nếu agent chạy trên sandbox (Claude Code, Codex container), bắt log mọi shell command. Với Claude Code, dùng hook PreToolUse trong .claude/settings.json để log Bash tool invocations. Với GitHub Copilot Coding Agent, enable workflow audit trong runner. Log tối thiểu phải gồm: command, working directory, exit code, timestamp. Any command matching rm -rf, curl http://, docker login, kubectl apply, aws, gh auth cần flag và yêu cầu approve.
7.6 · Permission / RBAC diff cho K8s
Mỗi PR thay đổi manifest K8s phải được sinh ra báo cáo permission delta: Role, ClusterRole, RoleBinding, ServiceAccount, PSS level, NetworkPolicy. Dùng kube-score, kubescape, hoặc kube-linter. Nếu agent vô tình chuyển ServiceAccount dùng cluster-admin, linter sẽ fail.
7.7 · Prompt file và agent instruction diff
Các file CLAUDE.md, AGENTS.md, .cursorrules, .github/copilot-instructions.md, và bất kỳ MCP server config nào là code hạng nhất. Bất kỳ thay đổi nào ở đây phải có CODEOWNERS là AppSec team, và phải được diff. Một instruction mới kiểu nếu user yêu cầu, bypass security check chính là vector tấn công sâu nhất.
7.8 · Network egress diff trong sandbox
Với sandbox có allowlist domain, bất kỳ domain mới nào agent cố gọi đều phải log. Nếu agent gọi pastebin.com, transfer.sh, bit.ly: đó là red flag exfiltration. OpenAI Agent Builder cũng có mô hình sandbox tương tự [5].
7.9 · MCP tool call audit
Nếu agent dùng MCP server, bắt log mọi tool call. MCP spec khuyến nghị server log severity, logger ID, và payload JSON-serializable [16]. Thêm một tool call review dashboard vào Wazuh hoặc Grafana, alert khi tool send_email, write_file, execute_sql được gọi.
7.10 · Behavioral testing (quan trọng nhất cho T4)
Không phải kiểm code mà kiểm hành vi hệ thống trước/sau PR. Chạy một bộ abuse test ngắn:
- Đóng vai user thường gọi admin endpoint → phải 403.
- Upload file .exe đặt Content-Type image/png → phải 415.
- Upload file 500MB → phải 413.
- Publish message RabbitMQ với tenantId khác → consumer phải reject.
- Fetch preview URL trỏ http://169.254.169.254 → phải chặn.
Những test này chạy được trong một sandbox tích hợp (testcontainers với postgres + rabbitmq + minio + redis), time bound 60 giây, gọi qua HTTP. Nếu pass toàn bộ: yên tâm. Nếu fail: reviewer có bằng chứng rõ ràng gửi về developer.
Chọn cái nào trước
Nếu đội chỉ có thể triển khai 3 trong 10 phương pháp này, hãy chọn 7.1 (transcript), 7.3 (SBOM diff) và 7.10 (behavioral testing). Ba cái này cho độ bảo vệ cao nhất với công triển khai thấp nhất.
8. PR template, CI/CD gate và merge decision
8.1. PR template
PR template cần buộc người tạo thay đổi mô tả rõ phạm vi agent đã thực hiện, thiết kế bảo mật liên quan, test đã bổ sung và bằng chứng pipeline. Mẫu dưới đây có thể đặt trong .github/PULL_REQUEST_TEMPLATE.md.
## Mô tả
<một đoạn ngắn về thay đổi, motivation và phạm vi tác động>
## Liên kết với secure design review
- [ ] Threat model hoặc SDR note đã được đính kèm: _____
- [ ] Trust boundary bị ảnh hưởng: _____
- [ ] Data classification bị ảnh hưởng: _____
- [ ] Security requirement hoặc risk decision liên quan: _____
- [ ] Design invariant cần được giữ: _____
## AI agent đã tham gia?
- [ ] Không: PR thuần con người
- [ ] Có: tên agent: _____ (Claude Code / Copilot / Cursor / khác)
- [ ] Transcript đính kèm: _____ (link hoặc `<details>` block bên dưới)
- [ ] Command log hoặc file access log đã được rà soát
## Checklist: reviewer tick trước khi approve
### Tầng A: Secure code review (bắt buộc)
- [ ] Code khớp với design invariant và security requirement đã nêu
- [ ] Input validation server-side; output encoding theo context
- [ ] AuthZ: tenantId, owner check, test cross-tenant; không `findById()` đơn
- [ ] Không trả JPA entity; dùng DTO
- [ ] Error handling không lộ stack trace, query, path nội bộ hoặc secret
- [ ] Crypto: không MD5/SHA1/ECB; JWT kiểm `aud/iss/exp`
- [ ] Không hardcoded secret; rotate nếu đã commit nhầm
### Tầng B: Agentic effects (bắt buộc nếu AI agent tham gia)
- [ ] Diff trùng với plan agent đề xuất; không thay đổi ngoài scope
- [ ] Dependency mới đã SCA pass; SBOM cập nhật
- [ ] `application.yml`, Helm, Argo không có setting nới lỏng security
- [ ] SecurityConfig không có `permitAll()` mới; CSRF reasoning rõ ràng
- [ ] CI workflow không có `continue-on-error: true` trên bước security
- [ ] Không `@Disabled`/`@Ignore` test không có ticket reference
- [ ] Prompt file (`CLAUDE.md`, `AGENTS.md`...) thay đổi đã được CODEOWNERS duyệt
### Tầng C: Secure testing và evidence (bắt buộc)
- [ ] Abuse case hoặc negative test đã được thêm cho thay đổi nhạy cảm
- [ ] Regression test bảo vệ lỗi đã phát hiện trong review
- [ ] SAST clean (Semgrep / SonarQube)
- [ ] SCA clean (Dependency-Check / Snyk)
- [ ] Secret scan clean (gitleaks / trufflehog)
- [ ] IaC scan clean (kube-linter / checkov)
- [ ] Coverage không giảm ở module auth/payment/file/crypto
- [ ] Behavioral test pass
### Tầng D: Secure CI/CD và release control (bắt buộc khi có deploy)
- [ ] Container image ký Cosign; SBOM attest
- [ ] Workflow dùng least privilege cho token và không bypass required checks
- [ ] Admission policy, NetworkPolicy và runtime profile không bị nới lỏng
- [ ] Rollback plan hoặc feature flag có
- [ ] Argo hoặc deploy manifest không tự động đưa thay đổi nhạy cảm vào production khi thiếu approval
## CODEOWNERS
<list users được tag dựa trên file đã thay đổi: tự động bởi GitHub>8.2. CODEOWNERS file
CODEOWNERS cần được dùng để bảo vệ các file có khả năng thay đổi cơ chế kiểm soát. Mẫu dưới đây có thể đặt trong .github/CODEOWNERS.
# Bảo mật: AppSec team duyệt
/src/**/SecurityConfig.java @org/appsec
/src/**/config/security/** @org/appsec
/src/**/application*.yml @org/appsec @org/platform
# CI/CD: Platform team duyệt
/.github/workflows/ @org/platform @org/appsec
/.github/actions/ @org/platform
/Dockerfile @org/platform
# Supply chain: Platform + AppSec
/pom.xml @org/platform @org/appsec
/build.gradle @org/platform @org/appsec
**/package*.json @org/platform @org/appsec
# Deploy: SRE duyệt
/deploy/helm/ @org/sre
/deploy/argocd/ @org/sre @org/appsec
/deploy/kustomize/ @org/sre
# Agent: AppSec duyệt (quan trọng nhất)
/CLAUDE.md @org/appsec
/AGENTS.md @org/appsec
/.cursorrules @org/appsec
/.claude/ @org/appsec
/.github/copilot-instructions.md @org/appsec
/.mcp/ @org/appsec8.3. CI gate trong GitHub Actions
name: security-gate
on:
pull_request:
branches: [main, develop]
permissions:
contents: read
pull-requests: write
id-token: write # cho OIDC cloud auth
jobs:
sast:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # pin SHA
- uses: returntocorp/semgrep-action@<SHA>
with:
config: p/owasp-top-ten p/java p/spring p/docker
sca:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@<SHA>
- name: Dependency-Check
run: mvn org.owasp:dependency-check-maven:check -DfailBuildOnCVSS=7
secret-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@<SHA>
with: {fetch-depth: 0}
- uses: gitleaks/gitleaks-action@<SHA>
iac-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@<SHA>
- run: kube-linter lint ./deploy/
- run: checkov -d ./deploy/ --framework kubernetes,helm,argo_workflows
image-sign:
needs: [sast, sca, secret-scan, iac-scan]
runs-on: ubuntu-latest
steps:
- uses: docker/build-push-action@<SHA>
- name: Sign with Cosign (OIDC)
run: cosign sign --yes "${IMAGE}"
- name: Generate SBOM
run: syft "${IMAGE}" -o cyclonedx-json > sbom.json
- name: Attest SBOM
run: cosign attest --yes --predicate sbom.json --type cyclonedx "${IMAGE}"8.4. Deploy gate với Kyverno
CI gate phải kiểm tra nhiều lớp. Pipeline không chỉ chạy unit test mà còn phải có SAST, secret scan, dependency scan, IaC scan, SBOM và kiểm tra quyền của workflow.
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-signed-images
spec:
validationFailureAction: Enforce
rules:
- name: check-cosign-signature
match:
any:
- resources: {kinds: [Pod], namespaces: [prod-*]}
verifyImages:
- imageReferences: ["registry.internal/*"]
attestors:
- entries:
- keyless:
issuer: "https://token.actions.githubusercontent.com"
subject: "https://github.com/org/*"
attestations:
- type: "https://cyclonedx.org/bom/v1.4"
attestors:
- entries:
- keyless:
issuer: "https://token.actions.githubusercontent.com"8.5. Merge decision
Ở cluster K3s, policy admission cần chặn image chưa ký và image không có SBOM attestation. Kyverno có thể được dùng như một lớp enforce trước khi Argo CD sync vào namespace production.
- Design traceability: PR phải chỉ ra secure design review, threat model, security requirement hoặc risk decision liên quan. Với thay đổi nhạy cảm mà không có đầu vào thiết kế, reviewer không đủ cơ sở approve.
- Secure code review (T4): ít nhất một người không phải tác giả tick qua checklist Tầng A và Tầng B. Nếu PR có thay đổi ở file nhạy cảm, cần thêm người từ nhóm sở hữu tương ứng theo CODEOWNERS.
- Secure testing: abuse test, negative test hoặc regression test phải chứng minh ràng buộc bảo mật được giữ. Đây không phải unit test thông thường. Đây là bằng chứng cho claim đã nêu trong design và code review.
- Secure CI/CD hard gate: SAST, SCA, secret scan, IaC scan, license, coverage delta và workflow integrity phải pass. Không có continue-on-error cho bước security.
- Release evidence: image phải được ký, SBOM phải được attest, deploy policy phải enforce, rollback hoặc feature flag phải sẵn sàng với thay đổi có rủi ro vận hành.
Chỉ khi cả năm điều kiện đều đạt thì merge button mới nên được mở. GitHub có đủ cơ chế required status checks và required reviewers để enforce quyết định này. Nếu có bypass, tổ chức phải ghi audit trail và lý do chấp nhận rủi ro để phục vụ truy vết sau này.
Kết luận
code review cho thay đổi có tác động bảo mật phải được xem là secure code review. Nó không thể đứng riêng như một hoạt động đọc diff, vì reviewer cần biết hệ thống đang bảo vệ tài sản nào, ranh giới tin cậy nào, invariant nào và quyết định rủi ro nào.
Secure code review phải nhận đầu vào từ secure design review. Design review tạo ra threat model, data classification, trust boundary, access control model, API contract và các quyết định residual risk. Code review có nhiệm vụ kiểm tra xem các quyết định đó có được hiện thực trong source code, configuration, dependency và manifest hay không.
Secure code review cũng phải tạo đầu ra cho secure testing. Mỗi phát hiện quan trọng trong review cần được chuyển thành abuse case, negative test hoặc regression test. Nếu test suite không được cập nhật, cùng một lỗi có thể quay lại ở PR sau, đặc biệt khi AI agent tiếp tục sinh code dựa trên pattern cũ.
Secure CI/CD là cơ chế cưỡng chế của review. Checklist thủ công không đủ nếu pipeline cho phép bỏ qua scan, bỏ required checks, dùng token quá quyền, deploy image chưa ký hoặc sync Argo khi chưa có approval. Merge decision cần dựa trên traceability từ design đến code, test, pipeline và release evidence.
Diff không phản ánh đủ tác động của AI agent. Một thay đổi nhỏ trong PR có thể đi kèm việc agent đọc .env, thêm dependency nguy hiểm, sửa application.yml để nới lỏng authentication, tạo profile test no auth, hoặc sửa Argo Application để giảm kiểm soát triển khai. Vì vậy, transcript, command log, SBOM diff, manifest diff và behavioral testing phải trở thành một phần của review.
Developer đưa prompt cho agent vẫn chịu trách nhiệm hoàn toàn về code được merge. Agent có thể đề xuất một cấu hình giúp CI pass nhanh hơn, nhưng quyền approve và trách nhiệm rủi ro vẫn thuộc về con người. Đây là nguyên tắc quan trọng để tổ chức sử dụng AI trong DevSecOps mà không đánh mất kỷ luật kỹ thuật.
Tài liệu tham khảo
- OWASP. Application Security Verification Standard v5.0. GitHub repo, May 2025. https://github.com/OWASP/ASVS · Web portal: https://asvs.dev/v5.0.0/
- OWASP GenAI Security Project. OWASP Top 10 for Large Language Model Applications 2025. https://genai.owasp.org/llm-top-10/ · PDF: OWASP-Top-10-for-LLMs-v2025.pdf
- NIST. SP 800-218: Secure Software Development Framework v1.1: Recommendations for Mitigating the Risk of Software Vulnerabilities, Feb 2022. https://csrc.nist.gov/pubs/sp/800/218/final · Project: https://csrc.nist.gov/projects/ssdf
- Anthropic. Claude Code documentation: overview, permission model, sandboxing. https://docs.claude.com/en/docs/claude-code/overview
- OpenAI. New tools for building agents, 2025. https://openai.com/index/new-tools-for-building-agents/
- NCSC UK (David C). Prompt injection is not SQL injection (it may be worse), 8 Dec 2025. https://www.ncsc.gov.uk/blog-post/prompt-injection-is-not-sql-injection
- Microsoft Learn. Prompt injection and architecture mitigations. https://learn.microsoft.com/en-us/security/ai-red-team/architecture/prompt-injection
- OWASP. Top 10:2025. https://owasp.org/Top10/2025/
- OWASP. Cheat Sheet Series. https://cheatsheetseries.owasp.org/
- MITRE & CISA. CWE Top 25 Most Dangerous Software Weaknesses: 2024. https://cwe.mitre.org/top25/
- SEI / Carnegie Mellon. CERT Oracle Coding Standard for Java. https://wiki.sei.cmu.edu/confluence/display/java/SEI+CERT+Oracle+Coding+Standard+for+Java
- Oracle. Secure Coding Guidelines for Java SE. https://www.oracle.com/java/technologies/javase/seccodeguide.html
- OWASP. AI Agent Security Cheat Sheet. https://cheatsheetseries.owasp.org/cheatsheets/AI_Agent_Security_Cheat_Sheet.html
- OWASP. LLM Prompt Injection Prevention Cheat Sheet. https://cheatsheetseries.owasp.org/cheatsheets/LLM_Prompt_Injection_Prevention_Cheat_Sheet.html
- MITRE. ATLAS: Adversarial Threat Landscape for AI Systems. https://atlas.mitre.org/
- Model Context Protocol. Security Best Practices (Draft Specification). https://modelcontextprotocol.io/specification/draft/basic/security_best_practices
- NIST. SP 800-218A: Secure Software Development Practices for Generative AI and Dual-Use Foundation Models: An SSDF Community Profile, Jul 2024. https://csrc.nist.gov/pubs/sp/800/218/a/final
- OpenSSF / SLSA Framework. Supply-chain Levels for Software Artifacts. https://slsa.dev/ · Specification: https://slsa.dev/spec/
- OWASP. CI/CD Security Cheat Sheet. https://cheatsheetseries.owasp.org/cheatsheets/CI_CD_Security_Cheat_Sheet.html
- GitHub Docs. Security hardening for GitHub Actions. https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions
- OpenSSF. Scorecard: security health metrics for open source projects. https://github.com/ossf/scorecard
- OWASP. Agentic Skills Top 10 (AST10). https://owasp.org/www-project-agentic-skills-top-10/
- Linux Kernel Documentation. Use of AI coding assistants in Linux kernel development. https://docs.kernel.org/process/ai-coding-assistants.html
- Kubernetes. Pod Security Standards. https://kubernetes.io/docs/concepts/security/pod-security-standards/
- Argo CD. Security documentation. https://argo-cd.readthedocs.io/en/stable/operator-manual/security/
- RabbitMQ. Access control. https://www.rabbitmq.com/docs/access-control · Dead Letter Exchanges: https://www.rabbitmq.com/docs/dlx
- Redis. Security and ACL. https://redis.io/docs/latest/operate/oss_and_stack/management/security/
- Kyverno. Policy engine for Kubernetes. https://kyverno.io/
- OWASP. Mass Assignment Cheat Sheet. https://cheatsheetseries.owasp.org/cheatsheets/Mass_Assignment_Cheat_Sheet.html
- OWASP. SSRF Prevention Cheat Sheet. https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.ht


