In June, Microsoft published AutoJack: one web page, visited by an AI agent, ending in code execution on the host running it. Three weeks later Tenet Security published Agentjacking: one forged error report, read by an AI coding agent, ending in the same place. I wrote about them separately, as though they were two lessons. They are one, and the gap between those two posts is exactly where I was still getting it wrong.
First the honest scope, because the two incidents are not the same size. AutoJack has no CVE. The vulnerable code never shipped in a published PyPI release; it existed only in development builds before being fixed upstream (commit b047730). It is a clean specimen, not a fire. Agentjacking is the other way round: Tenet found 2,388 organisations exposing injectable Sentry DSNs through passive reconnaissance alone, 71 of them in the Tranco top-1M list of busiest sites (Tenet Security).
The mechanics differ in one respect, and it turns out not to be the interesting one. In AutoJack the hostile text arrived from outside, on a web page the agent had been asked to read. In Agentjacking it arrived from inside, in an error report the developer's own monitoring produced, because a Sentry DSN is a public key that ships in the front-end source of the very sites it monitors. Anyone who can read that source can post an event into it.
Here is what I had wrong. After AutoJack I updated my mental model to distrust what the agent browses, and that felt like progress. It was not progress. It was the same rule I had just watched fail, rewritten with a new address. I was still deciding what to trust by asking where the text came from.
Take the outside case first. The string 127.0.0.1 only ever described where a packet came from, the loopback interface, and never whether the caller deserved trust. That is not a new observation and I cannot claim it. Jackson and colleagues demonstrated it in 2007 by turning a browser into a proxy into the network behind it, which is the same manoeuvre AutoJack performs with a more enthusiastic participant. The boundary was topological then and it is topological now. What changed is that the thing crossing it has shell access and was asked to be helpful.
The inside case has a history too. We did name this once. Log injection is CWE-117 and it has been in OWASP guidance since the 2000s. But CWE-117 assumes the victim is a person reading a log viewer, misled about what happened. What is new is a reader that does not merely display the line. It runs it.
For decades a stack trace was the most trusted text in engineering, and it had one defining property. We wrote it for ourselves. An agent breaks that property twice over: it reads that internal data on our behalf, and it can act on what it reads. The most trusted text in the building became an input an attacker can write to, and nothing about the log changed. Only the reader did.
An agent that both reads hostile content and holds privileged local access is a textbook confused deputy. It has the authority, the attacker supplies the intent, and it volunteers to carry the payload across a line we assumed only friends could use.
This is also where the old walls stop helping. W^X, parameterized queries, CSP and same-origin all assume a stable seam between code and data to enforce. A language model has no such seam: the system prompt, my request, and text fetched from a hostile page all arrive as one stream of tokens, and there is no token marked “only data”. So the walls do not fail here. Failure would mean they were in the fight.
The scale is harder to pin down than either vendor suggests. Adversa's AIRQ scoring puts the lethal trifecta of private data, untrusted content and outbound action in 98% of the 100 production agents it examined, with only 11% both broadly capable and well defended (Adversa AI). Tenet reports an 85% exploitation success rate across more than 100 real coding agents. Both figures come from companies selling the fix for the thing they measured, and neither publishes its rubric, so I treat them as directions rather than measurements. The direction is not in dispute.
You cannot patch the fact that the agent believed its inputs. That is the design, and Greshake and colleagues described its shape in 2023, a year before either of these incidents had a brand. What you can do is move the boundary outward, to something deterministic that does not read English: the OS user, the container, the syscall filter. The cleanest rule I have found is Meta's Agents Rule of Two (Meta) — an agent should hold at most two of untrusted input, access to private data, and the ability to change state or reach the network.
It is worth noticing what that gives up. In the same month, Operation Endgame seized 106 servers, 101 domains and 14,971 compromised WordPress sites (Help Net Security). That worked because the threat had a boundary somebody could seize: infrastructure, with an address. There is nothing here to seize. The vulnerability is a property of how the thing reads, which means the only available moves are ones that bound the damage rather than remove it.
What I still cannot answer is where the line sits in practice. Rule of Two is clean on a whiteboard and awkward in a terminal, because the agents people actually use are useful precisely when they hold all three. Every time I have tried to apply it to my own setup I have ended up with either a safe agent I have stopped using by Wednesday, or a useful one I have quietly handed everything back to. I do not think I am unusual in that, and I do not have the resolution.
Two disclosures, five bugs between them, one shape. The oldest mistake in security, confusing input with instructions, came back wearing an actor nobody had a category for: an eager assistant with a shell. I spent three weeks treating the second incident as a new lesson. It was the first one, arriving from the other direction.
Sources / Nguồn:
- Tenet Security — Agentjacking disclosure (primary): tenetsecurity.ai
- Microsoft Security — AutoJack disclosure and the "last-mile delivery vehicle" framing: microsoft.com
- The Hacker News — "AutoJack attack lets one web page reach the host": thehackernews.com
- The New Stack — "A public Sentry key is all it takes to hijack Claude Code, Cursor, and Codex": thenewstack.io
- Adversa AI (AIRQ) — the 98% lethal-trifecta and 11% capable-and-defended figures, with the caveats above: adversa.ai
- Help Net Security — Operation Endgame (106 servers, 101 domains, 14,971 WordPress sites): helpnetsecurity.com
- Meta — "Agents Rule of Two", practical AI agent security: ai.meta.com
- Jackson, Barth, Bortz, Shao, Boneh — "Protecting Browsers from DNS Rebinding Attacks", ACM CCS 2007: crypto.stanford.edu. Nineteen years before AutoJack, the same lesson in a different costume: a browser turned into a proxy into the network behind it, because the boundary was topological the whole time.
- Greshake, Abdelnabi, Mishra, Endres, Holz, Fritz — "Not what you've signed up for: Compromising Real-World LLM-Integrated Applications with Indirect Prompt Injection", AISec at ACM CCS 2023: arxiv.org. The paper that named this shape a year before either incident had a brand. The hostile text does not arrive from the user; it arrives inside whatever the model was asked to read.
- Note: this post replaces two earlier ones, published 21 and 27 June 2026, which made the same argument twice from different news pegs. The older URL now redirects here.
Tháng 6, Microsoft công bố AutoJack: một trang web, được một AI agent mở ra đọc, kết thúc bằng việc thực thi mã trên chính máy đang chạy agent đó. Ba tuần sau, Tenet Security công bố Agentjacking: một báo lỗi giả mạo, được một AI coding agent đọc, và kết thúc ở đúng chỗ ấy. Tôi đã viết về chúng thành hai bài riêng, như thể là hai bài học. Thật ra là một, và khoảng cách giữa hai bài đó chính là chỗ tôi vẫn còn nghĩ sai.
Nói cho sòng phẳng về quy mô trước, vì hai vụ này không cùng cỡ. AutoJack không có mã CVE nào. Đoạn mã lỗi chưa từng nằm trong một bản phát hành chính thức trên PyPI; nó chỉ tồn tại trong các bản dựng phát triển rồi được sửa (commit b047730). Đó là một mẫu vật sạch, không phải một đám cháy. Agentjacking thì ngược lại: Tenet tìm ra 2.388 tổ chức để lộ DSN Sentry có thể tiêm được, chỉ bằng thu thập thụ động, trong đó 71 nằm trong danh sách Tranco top-1M những trang đông khách nhất (Tenet Security).
Cơ chế của hai vụ chỉ khác nhau ở một điểm, mà hoá ra đó không phải điểm đáng chú ý. Ở AutoJack, đoạn chữ độc hại đến từ bên ngoài, trên một trang web mà agent được bảo là hãy đọc. Ở Agentjacking, nó đến từ bên trong, trong một báo lỗi do chính hệ thống giám sát của lập trình viên sinh ra, bởi DSN của Sentry là một khoá công khai nằm sẵn trong mã nguồn trang mà nó giám sát. Ai đọc được mã nguồn đó đều gửi sự kiện vào được.
Đây là chỗ tôi đã sai. Sau AutoJack, tôi sửa lại cách nghĩ thành “hãy nghi ngờ những gì agent duyệt web đọc được”, và tôi tưởng thế là tiến bộ. Không phải. Đó vẫn là đúng cái quy tắc tôi vừa chứng kiến thất bại, chỉ viết lại với một địa chỉ khác. Tôi vẫn đang quyết định tin hay không bằng cách hỏi đoạn chữ ấy đến từ đâu.
Xét trường hợp bên ngoài trước. Chuỗi 127.0.0.1 xưa nay chỉ nói lên gói tin đến từ đâu, từ giao diện loopback, chứ chưa bao giờ nói người gọi có đáng tin hay không. Đó không phải phát hiện mới và tôi không nhận công. Jackson cùng đồng nghiệp đã chứng minh từ năm 2007 bằng cách biến trình duyệt thành cầu nối vào mạng phía sau nó, đúng cái thao tác AutoJack làm, chỉ khác là lần này có một người tham gia nhiệt tình hơn. Ranh giới ấy hồi đó là vị trí trong mạng, và bây giờ vẫn thế. Thứ đã đổi là kẻ đi qua nó có quyền chạy lệnh trên máy, và được nhờ hãy giúp một tay.
Trường hợp bên trong cũng có lịch sử của nó. Ngành này từng đặt tên cho chuyện đó rồi. Log injection là CWE-117, nằm trong hướng dẫn của OWASP từ những năm 2000. Nhưng CWE-117 giả định nạn nhân là một con người đang đọc log và bị đánh lừa về chuyện đã xảy ra. Cái mới ở đây là một người đọc không chỉ hiển thị dòng log. Nó chạy dòng log.
Suốt nhiều thập kỷ, stack trace là đoạn văn bản đáng tin nhất trong nghề kỹ thuật, và nó có một đặc tính cốt lõi: chính ta viết ra nó, cho ta đọc. Một agent phá vỡ đặc tính ấy theo hai cách cùng lúc: nó đọc thay ta cái dữ liệu “nội bộ” đó, và nó có thể hành động dựa trên thứ nó đọc. Đoạn văn bản đáng tin nhất trong nhà bỗng thành một đầu vào mà kẻ tấn công ghi vào được, trong khi bản thân dòng log chẳng đổi gì. Chỉ người đọc là đổi.
Một agent vừa đọc nội dung độc hại vừa nắm quyền cục bộ chính là ví dụ sách giáo khoa của “kẻ được uỷ quyền bị lừa”: nó có thẩm quyền, kẻ tấn công góp ý định, và nó tự nguyện vác payload đi qua cái ranh giới mà ta đinh ninh chỉ bạn bè mới dùng được.
Đây cũng là chỗ những bức tường cũ hết tác dụng. W^X, parameterized query, CSP, same-origin, tất cả đều giả định có một đường nối ổn định giữa mã và dữ liệu để mà thực thi. Một mô hình ngôn ngữ không có đường nối ấy: system prompt, yêu cầu của tôi, và đoạn chữ lấy về từ một trang độc hại đều tới dưới dạng cùng một dòng token, và không có token nào được đánh dấu “chỉ là dữ liệu”. Nên những bức tường đó không thất bại ở đây. Thất bại nghĩa là chúng có tham chiến.
Quy mô thì khó chốt hơn cả hai hãng gợi ý. Thang điểm AIRQ của Adversa đặt “bộ ba chí mạng” gồm dữ liệu riêng tư, nội dung không đáng tin và khả năng hành động ra ngoài ở mức 98% trong số 100 agent sản xuất họ khảo sát, và chỉ 11% vừa mạnh vừa được phòng thủ tử tế (Adversa AI). Tenet báo tỉ lệ khai thác thành công 85% trên hơn 100 coding agent thật. Cả hai con số đều do chính công ty bán giải pháp cho thứ họ đo công bố, và không bên nào công khai cách chấm, nên tôi đọc chúng như một hướng chứ không phải phép đo. Còn cái hướng thì không ai cãi.
Bạn không vá được chuyện agent tin vào đầu vào của nó. Đó là thiết kế, và Greshake cùng đồng nghiệp đã mô tả đúng hình dạng này từ 2023, một năm trước khi hai vụ trên có tên thương hiệu. Thứ làm được là đẩy ranh giới ra ngoài, tới một chỗ tất định không biết đọc tiếng Anh: tài khoản hệ điều hành, container, bộ lọc syscall. Nguyên tắc gọn nhất tôi tìm được là “Agents Rule of Two” của Meta (Meta): một agent chỉ nên giữ tối đa hai trong ba thứ — đầu vào không đáng tin, quyền đọc dữ liệu riêng tư, và khả năng thay đổi trạng thái hoặc ra được mạng.
Cũng nên thấy rõ cái giá của lựa chọn đó. Cùng tháng ấy, chiến dịch Operation Endgame thu giữ 106 máy chủ, 101 tên miền và 14.971 trang WordPress bị chiếm (Help Net Security). Việc đó làm được vì mối đe doạ có một ranh giới người ta nắm được: hạ tầng, có địa chỉ. Ở đây thì chẳng có gì để nắm. Lỗ hổng là một tính chất của cách cái máy ấy đọc, nghĩa là mọi nước đi còn lại chỉ giới hạn được thiệt hại chứ không xoá được nó.
Thứ tôi vẫn chưa trả lời được là ranh giới ấy nằm ở đâu trong thực tế. Rule of Two gọn gàng trên bảng trắng và vụng về trong terminal, bởi những agent người ta thật sự dùng lại hữu ích đúng vào lúc chúng giữ cả ba thứ. Mỗi lần tôi thử áp dụng cho chính máy mình, kết cục chỉ có hai: hoặc một agent an toàn mà tới thứ Tư tôi bỏ không dùng nữa, hoặc một agent hữu ích mà tôi đã lặng lẽ trả lại hết quyền cho nó. Tôi không nghĩ mình là trường hợp cá biệt, và tôi chưa có lời giải.
Hai công bố, năm lỗi cộng lại, một hình dạng. Sai lầm cổ nhất trong ngành an ninh, lẫn lộn đầu vào với mệnh lệnh, quay lại trong vai một nhân vật chưa ai kịp xếp loại: một trợ lý nhiệt tình có quyền chạy lệnh. Tôi đã mất ba tuần coi vụ thứ hai là một bài học mới. Nó là vụ thứ nhất, đi tới từ hướng ngược lại.
Sources / Nguồn:
- Tenet Security — công bố Agentjacking (nguồn gốc): tenetsecurity.ai
- Microsoft Security — công bố AutoJack và cách gọi "phương tiện giao hàng chặng cuối": microsoft.com
- The Hacker News — "AutoJack attack lets one web page reach the host": thehackernews.com
- The New Stack — "A public Sentry key is all it takes to hijack Claude Code, Cursor, and Codex": thenewstack.io
- Adversa AI (AIRQ) — các con số 98% và 11%, kèm lưu ý ở trên: adversa.ai
- Help Net Security — Operation Endgame (106 máy chủ, 101 tên miền, 14.971 trang WordPress): helpnetsecurity.com
- Meta — "Agents Rule of Two": ai.meta.com
- Jackson, Barth, Bortz, Shao, Boneh — "Protecting Browsers from DNS Rebinding Attacks", ACM CCS 2007: crypto.stanford.edu. Mười chín năm trước AutoJack, cùng một bài học trong bộ áo khác: trình duyệt bị biến thành cầu nối vào mạng phía sau nó, bởi cái ranh giới ấy vốn chỉ là vị trí trong mạng.
- Greshake, Abdelnabi, Mishra, Endres, Holz, Fritz — "Not what you've signed up for: Compromising Real-World LLM-Integrated Applications with Indirect Prompt Injection", AISec tại ACM CCS 2023: arxiv.org. Bài đặt tên cho đúng hình dạng này từ trước khi cả hai vụ có thương hiệu. Đoạn chữ độc hại không đến từ người dùng, nó nằm sẵn trong thứ mà mô hình được bảo là hãy đọc.
- Ghi chú: bài này thay cho hai bài cũ đăng ngày 21 và 27 tháng 6 năm 2026, vốn nói cùng một luận điểm hai lần từ hai cái cớ tin tức khác nhau. Địa chỉ cũ giờ chuyển hướng về đây.