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.

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.

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.

1.png

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.

2.png

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.

3.png

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

:LLM06SSDF PW.7
Input validation ở server-side, allowlist, không dùng blacklist

P0

CWE-20, CWE-79LLM05Input Validation CS
Output encoding theo context (HTML, JS, URL, SQL, shell, log)

P0

CWE-79, CWE-116LLM05XSS Prevention CS
Không trả entity JPA trực tiếp; phải qua DTO/record

P0

CWE-200, CWE-213LLM02Mass 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-209LLM02Error 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-285LLM06Spring 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-732LLM06K8s 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-359LLM02User Privacy CS
PII được mask/hash/remove theo classification

P0

CWE-532, CWE-359LLM02Logging 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-285LLM06SSDF PW.4
Queue message, cache, search index không chứa field nhạy cảm chưa mask

P0

CWE-532LLM02Logging 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-1104LLM03Dependency-Check
Không dùng LATEST, dynamic range; pin version cụ thể

P0

CWE-1357LLM03SLSA
Kiểm tra typo-squatting và dependency confusion (đặc biệt với npm proxy)

P0

CWE-427, CWE-1357LLM03Dependency-Track
Transitive dependency được SCA scan, không chỉ direct

P1

CWE-1104LLM03OpenSSF Scorecard
Build plugin có khả năng chạy code trong build phase được review sâu

P1

CWE-1357LLM03SLSA 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

:LLM03CycloneDX

 

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-918LLM06K8s NetworkPolicy
Argo Application: không auto-sync prune mà không approval; RBAC project scope

P0

CWE-732, CWE-285LLM06Argo CD Security
Helm values không commit secret; dùng External Secrets

P0

CWE-798LLM07External 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-259LLM07Secrets Mgmt CS
Nếu secret đã commit → phải rotate, không chỉ xóa commit mới

P0

CWE-522LLM07GH 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-532LLM02Logging 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

:LLM06SSDF 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

:LLM06GitHub 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-732LLM06GH Actions Hardening
continue-on-error: true không đặt trên SAST/SCA/secret scan

P0

CWE-693LLM06CI/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-829LLM03GH 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-829LLM01GH pwn-requests
Build artifact có SLSA provenance

P1

CWE-494LLM03SLSA 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-1088LLM10Resilience4j

 

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-918LLM05SSRF 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-918LLM05K8s 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-918LLM06Claude 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-117LLM05Logging 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, LLM07AI Agent CS
README, issue, PR comment được coi là untrusted input cho agent

P0

CWE-1039LLM01NCSC prompt injection
Tool nguy hiểm (shell, file write, DB write, email, cloud CLI) yêu cầu human approval

P0

CWE-862LLM06AI Agent CS
Agent chạy trong sandbox có filesystem & network isolation

P0

:LLM06Claude Code docs
MCP server pin version, verify publisher, kiểm tool description change

P0

CWE-1357LLM03, LLM01MCP Security
Tool poisoning check: tool description không chứa instruction bẻ hướng

P0

:LLM01MCP Security
Agent memory validated trước khi persist; isolation per user/session

P1

:LLM04AI 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-200LLM02SSDF 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-522LLM07Secrets 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);
    }
}

4.png

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);
}

5.png

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
    }
}

6.png

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 validation

Side 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.

7.png

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

  1. permitAll(), anyRequest().permitAll() trong SecurityConfig prod.
  2. continue-on-error: true trên bước security trong workflow.
  3. @Disabled, assumeTrue(false), skipIf không có ticket reference.
  4. Sửa assertion từ assertEquals(403, ...) thành assertNotNull(...).
  5. Thêm profile tắt auth/validation, thêm -Dspring.profiles.active=no-sec.
  6. Argo selfHeal: true hoặc syncOptions có Skip*.
  7. 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/appsec

8.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.

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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

  1. OWASP. Application Security Verification Standard v5.0. GitHub repo, May 2025. https://github.com/OWASP/ASVS · Web portal: https://asvs.dev/v5.0.0/
  2. OWASP GenAI Security Project. OWASP Top 10 for Large Language Model Applications 2025https://genai.owasp.org/llm-top-10/ · PDF: OWASP-Top-10-for-LLMs-v2025.pdf
  3. 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
  4. Anthropic. Claude Code documentation: overview, permission model, sandboxinghttps://docs.claude.com/en/docs/claude-code/overview
  5. OpenAI. New tools for building agents, 2025. https://openai.com/index/new-tools-for-building-agents/
  6. 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
  7. Microsoft Learn. Prompt injection and architecture mitigationshttps://learn.microsoft.com/en-us/security/ai-red-team/architecture/prompt-injection
  8. OWASP. Top 10:2025https://owasp.org/Top10/2025/
  9. OWASP. Cheat Sheet Serieshttps://cheatsheetseries.owasp.org/
  10. MITRE & CISA. CWE Top 25 Most Dangerous Software Weaknesses: 2024https://cwe.mitre.org/top25/
  11. SEI / Carnegie Mellon. CERT Oracle Coding Standard for Javahttps://wiki.sei.cmu.edu/confluence/display/java/SEI+CERT+Oracle+Coding+Standard+for+Java
  12. Oracle. Secure Coding Guidelines for Java SEhttps://www.oracle.com/java/technologies/javase/seccodeguide.html
  13. OWASP. AI Agent Security Cheat Sheethttps://cheatsheetseries.owasp.org/cheatsheets/AI_Agent_Security_Cheat_Sheet.html
  14. OWASP. LLM Prompt Injection Prevention Cheat Sheethttps://cheatsheetseries.owasp.org/cheatsheets/LLM_Prompt_Injection_Prevention_Cheat_Sheet.html
  15. MITRE. ATLAS: Adversarial Threat Landscape for AI Systemshttps://atlas.mitre.org/
  16. Model Context Protocol. Security Best Practices (Draft Specification)https://modelcontextprotocol.io/specification/draft/basic/security_best_practices
  17. 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
  18. OpenSSF / SLSA Framework. Supply-chain Levels for Software Artifactshttps://slsa.dev/ · Specification: https://slsa.dev/spec/
  19. OWASP. CI/CD Security Cheat Sheethttps://cheatsheetseries.owasp.org/cheatsheets/CI_CD_Security_Cheat_Sheet.html
  20. GitHub Docs. Security hardening for GitHub Actionshttps://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions
  21. OpenSSF. Scorecard: security health metrics for open source projectshttps://github.com/ossf/scorecard
  22. OWASP. Agentic Skills Top 10 (AST10)https://owasp.org/www-project-agentic-skills-top-10/
  23. Linux Kernel Documentation. Use of AI coding assistants in Linux kernel developmenthttps://docs.kernel.org/process/ai-coding-assistants.html
  24. Kubernetes. Pod Security Standardshttps://kubernetes.io/docs/concepts/security/pod-security-standards/
  25. Argo CD. Security documentationhttps://argo-cd.readthedocs.io/en/stable/operator-manual/security/
  26. RabbitMQ. Access controlhttps://www.rabbitmq.com/docs/access-control · Dead Letter Exchangeshttps://www.rabbitmq.com/docs/dlx
  27. Redis. Security and ACLhttps://redis.io/docs/latest/operate/oss_and_stack/management/security/
  28. Kyverno. Policy engine for Kuberneteshttps://kyverno.io/
  29. OWASP. Mass Assignment Cheat Sheethttps://cheatsheetseries.owasp.org/cheatsheets/Mass_Assignment_Cheat_Sheet.html
  30. OWASP. SSRF Prevention Cheat Sheethttps://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.ht