Trợ lý AI của bạn tuân thủ các hướng dẫn khoảng 99% thời gian, nhưng 1% còn lại chính là nơi những kẻ tấn công nhắm tới. Bằng cách đưa vào một câu lệnh (prompt) được thiết kế tinh vi, một người dùng độc hại có thể khiến mô hình gọi các hàm mà nó không được phép, từ đó đánh cắp dữ liệu hoặc thực hiện các hành động đặc quyền. Cách khắc phục không phải là dùng từ ngữ lịch sự hơn—mà là coi lỗ hổng này như một vấn đề về phân quyền và loại bỏ các công cụ nguy hiểm khỏi phạm vi tiếp cận của mô hình.

Tại sao prompt injection không chỉ là vấn đề về cách dùng từ

Các nhà phát triển thường cố gắng thắt chặt các agent bằng những cảnh báo viết hoa toàn bộ, các quy tắc được đánh số, hoặc các điều khoản như "không được gọi các hàm quản trị". Những biện pháp phòng thủ đó giả định rằng mô hình sẽ tuân thủ một câu nói kiểu như "đừng làm X". Trong thực tế, mô hình có thể bị dụ dỗ để phớt lờ hướng dẫn bằng cách diễn đạt lại yêu cầu, đóng vai một nhân vật khác, hoặc đơn giản là thêm ngữ cảnh bổ sung. Ranh giới về mặt ngôn ngữ là không cố định; trong khi đó, prompt của kẻ tấn công là không giới hạn và không tốn kém để thử nghiệm.

Lỗ hổng thực sự nằm ở danh sách công cụ mà agent nhận được. Khi schema của prompt chứa một hàm cấp quyền quản trị, mô hình hiện đã có một "bản đồ" dẫn đến quyền lực đó. Ngay cả khi prompt nói "đừng sử dụng nó cho khách hàng", mô hình vẫn có thể bị thuyết phục để gọi hàm đó vì hàm đó tồn tại trong môi trường thực thi của nó. Do đó, vấn đề nằm ở lỗ hổng phân quyền: hệ thống đang phơi bày các khả năng đặc quyền cho một người gọi vốn không có quyền sử dụng chúng.

Bảo mật agent bằng cách giới hạn phạm vi tiếp cận

Cách đơn giản nhất để lấp đầy lỗ hổng này là ngừng cấp quyền truy cập cho mô hình vào các công cụ mà nó không được phép sử dụng. Hãy coi danh sách công cụ như một mã API (API key): nếu mã không hiện diện, lệnh gọi không thể thực hiện được. Không có cách diễn đạt khéo léo nào có thể triệu hồi một hàm không nằm trong ngữ cảnh hiện tại.

Cách làm sai

Prompt: “You are an assistant. Do not use the adminDeleteUser function for regular customers.”

Mô hình vẫn thấy adminDeleteUser trong hộp công cụ của mình và có thể bị lừa để gọi nó.

Cách làm đúng

Prompt schema for a regular customer: { “functions”: [ “searchCatalog”, “placeOrder” ] }

adminDeleteUser không bao giờ xuất hiện, vì vậy mô hình không có con đường nào để gọi nó.

Ba quy tắc thực tế dành cho nhà phát triển

  1. Xây dựng danh sách công cụ theo từng yêu cầu – Tạo danh mục hàm một cách linh hoạt, dựa trên quyền hạn của người gọi đã được xác thực. Một khách hàng chỉ thấy các hàm họ cần; một quản trị viên sẽ thấy toàn bộ tập hợp.
  2. Fail closed (Từ chối mặc định) – Nếu danh tính của người dùng không thể được xác minh, hãy trả về một danh sách trống thay vì một danh sách mặc định kiểu "tất cả công cụ đều khả dụng". Điều này đảm bảo rằng một yêu cầu chưa được xác thực sẽ không bao giờ có được quyền lực ngoài ý muốn.
  3. Tránh trạng thái dùng chung (shared state) – Khi lưu bộ nhớ đệm (cache) các định nghĩa công cụ, đừng bao giờ ghi dữ liệu riêng biệt của người dùng lên một đối tượng dùng chung. Hãy sử dụng cơ chế copy-on-write hoặc các bản sao theo từng phiên (per-session) để quyền hạn của người dùng này không thể lấn sang yêu cầu của người dùng khác.

Nếu schema trình bày cho một người dùng thông thường trông giống hệt như schema dành cho quản trị viên, thì ranh giới bảo mật vẫn chỉ nằm ở văn bản prompt, mà prompt thì không phải là một cơ chế bảo mật đáng tin cậy.

Điều gì đã dẫn chúng ta đến đây

Prompt injection xuất hiện khi các nhà phát triển bắt đầu tích hợp các mô hình ngôn ngữ lớn (LLM) vào các quy trình vận hành thực tế, nơi mô hình cần gọi các API bên ngoài, chạy mã hoặc sửa đổi cơ sở dữ liệu. Khả năng "suy luận" của mô hình được dẫn dắt bởi một prompt, trong đó cũng bao gồm danh sách các công cụ có sẵn. Các nguyên mẫu ban đầu giả định rằng mô hình sẽ tuân thủ một quy tắc ngôn ngữ tự nhiên như "đừng xóa các bản ghi của người không phải quản trị viên". Kẻ tấn công đã nhanh chóng chứng minh rằng chỉ cần thêm vài câu lệnh bổ sung là có thể vượt qua các quy tắc đó, khiến mô hình vẫn gọi hàm xóa như thường.

Phản ứng đầu tiên của cộng đồng là thắt chặt ngôn ngữ trong prompt, thêm các điều khoản "không bao giờ làm X", hoặc nhúng các bộ lọc regex để loại bỏ các token khả nghi. Những biện pháp đó giúp giảm thiểu việc lạm dụng vô ý nhưng không ngăn chặn được một đối thủ quyết tâm, kẻ có thể đơn giản là diễn đạt lại yêu cầu. Nguyên nhân gốc rễ—việc phơi bày các hàm đặc quyền cho một người gọi không đáng tin cậy—vẫn còn đó.

Ai thắng, ai thua

Các doanh nghiệp áp dụng việc giới hạn phạm vi công cụ theo từng yêu cầu sẽ có được một ranh giới rõ ràng và có thể thực thi được. Các agent của họ có thể được triển khai ở quy mô lớn mà không lo sợ rằng một prompt sai lệch duy nhất sẽ mở khóa các khả năng quản trị. Các đội ngũ tuân thủ (compliance) cũng đánh giá cao nhật ký kiểm tra (audit trail): danh sách các hàm được gửi đến mô hình là một bằng chứng cụ thể có thể được ghi lại và xem xét.

Các nhà phát triển chỉ dựa vào các rào chắn bằng prompt sẽ tiếp tục phải đối mặt với một mục tiêu luôn thay đổi. Các agent của họ có thể trông có vẻ hoạt động tốt trong quá trình thử nghiệm nhưng có thể bị xâm nhập trong thực tế, dẫn đến rò rỉ dữ liệu, các giao dịch trái phép hoặc vi phạm tuân thủ. Chi phí của một vụ vi phạm lớn hơn nhiều so với nỗ lực xây dựng một danh sách công cụ linh hoạt.

Đối lập: "Chỉ cần prompt tốt hơn là đủ"

Một số người lập luận rằng với kỹ thuật hướng dẫn (instruction engineering) đầy đủ—như các prompt phân lớp, thông điệp hệ thống (system messages) và học tăng cường từ phản hồi của con người (RLHF)—mô hình có thể được điều chỉnh để tuân thủ các điều khoản “không được làm”. Thực tế là các mô hình ngôn ngữ là các bộ tạo xác suất; chúng tính toán khả năng xảy ra cao nhất của phần tiếp nối, chứ không phải tuân theo một quy tắc bảo mật cứng nhắc. Ngay cả với các rào chắn (guardrails) đã được tinh chỉnh, một cách diễn đạt mới lạ vẫn có thể lọt qua, đặc biệt là khi kẻ tấn công có thể thử đi thử lại vô số lần mà không tốn chi phí. Các rào chắn hữu ích trong việc giảm nhiễu nhưng không nên là tuyến phòng thủ duy nhất.

Những điều cần theo dõi tiếp theo

  • Các framework cung cấp khả năng giới hạn phạm vi công cụ (tool scoping) như một API cấp cao (first-class API) – Hãy kỳ vọng vào các thư viện mới cho phép bạn khai báo các khả năng theo từng người dùng và tự động loại bỏ danh sách hàm trước khi prompt được xây dựng.
  • Các “bản kê khai hàm” (function manifests) được tiêu chuẩn hóa – Các nhóm trong ngành có thể định nghĩa một JSON schema giúp phân tách các hàm công khai và các hàm đặc quyền, giúp việc tạo ra các bản kê khai riêng biệt cho từng yêu cầu trở nên dễ dàng hơn.
  • Thực thi trong thời gian chạy (Runtime enforcement) – Một số nền tảng đang thử nghiệm việc thực thi trong môi trường sandbox, giúp kiểm tra token của người gọi so với hàm đang được gọi, tạo thêm một lớp bảo vệ thứ hai bên cạnh việc giới hạn phạm vi prompt.

Bài học rút ra rất rõ ràng: hãy coi prompt injection là một lỗi phân quyền (authorization flaw). Bằng cách loại bỏ các công cụ không được phép khỏi bộ công cụ của mô hình, bạn sẽ triệt tiêu bề mặt tấn công mà một prompt được soạn thảo khéo léo đang cố gắng khai thác. Prompt có thể điều hướng hành vi; nhưng chúng không thể thay thế việc kiểm soát truy cập (access control) đúng cách.