最新资讯
dev.to 我们在 DolphinBench 上测试记忆检索:纯关键词搜索暴露了自身回归 dev.to 别再把 Agent 写成 while 循环,把它建模为状态机 bloomberg.com Rightmove 与 Scout24 借 AI 产品应对低迷房市并上调展望 stackoverflow.blog 欢迎来到芯片时代:半导体制造、AI 数据中心与芯片设计的未来 www.youtube.com AI Agent 总犯同样的错:CentralAgent AI 将记忆重构为经验系统 pub.towardsai.net Netflix 科学家建议重采样 LLM 评判:5 次仅将误差棒缩小 13% pub.towardsai.net Jev 作为 LLM 前的静默层:构建提示感知的模型路由器 reddit.com OpenAI 称 Astra 仅满足 10% 安全任务标准 dev.to FreeToken:在自有 GPU 上运行前沿 MoE 模型及其内存需求 dev.to 当 AI Agent 说“完成”时,究竟完成了什么? dev.to 部署 Underdog Bark 3.0 Pro:逐字转写、自定义后端与分块设置 dev.to 为艰难对话构建 AI:五个 Agent、一条安全正则与一位盲评监督者
多元动态
登录 注册
智能体 dev.to · @luc richelet

我们攻击自家 AI Agent 治理 69 次,其中 5 次被攻破

原文 我的收藏

作者在 PostgreSQL 平台上以受限分支角色对 15 个声明为 BRANCH_SCOPED 的 SECURITY DEFINER 函数发起 69 次攻击,记录到 5 次权限边界失守,强调结论来自真实执行日志而非代码阅读。

AI推荐理由 以真实 PostgreSQL 角色和干净数据库对 15 个 SECURITY DEFINER 函数发起 69 次攻击并记录 5 次失守,属可复现的 Agent 权限治理实证,对 Agent 安全设计有直接参考;但为单方自述,未提供完整日志或第三方复核。

74

正文

9 September 2026 · Luc Richelet. Every number below comes from a real execution log, under real PostgreSQL login roles, on two clean databases. Nothing is inferred from reading code. Most AI-agent security content tells you what to do. This post tells you what we did to ourselves, and what broke. We run a small platform kernel on PostgreSQL. AI agents work inside it: they claim jobs, write artifacts, record health checks, emit signals. Every one of those actions goes through a SECURITY DEFINER function that is supposed to check who is calling and what they're allowed to touch. We had fifteen of those functions. The registry said they were declared but unproven. So instead of reading them, we attacked them — as a real database role with a real, narrow mandate, never as the superuser. Here's what happened. The setup One branch-scoped worker role, v14_ms, whose only mandate is the MOVESCAN branch. Fifteen SECURITY DEFINER functions, each declared BRANCH_SCOPED. Attacks: impersonate another actor, write into a foreign branch, distinguish "foreign" from "absent", inject a branch name, claim a job you don't own. Rule: a green obtained as postgres counts for nothing. Our identity helper returned true for any superuser. We only trust greens from login roles. Red #1 — luc_artifact_put: impersonation just worked B2 own actor, foreign branch -> created=false err=LK037 (correct) B3 p_actor='v14-ei' -> created=TRUE (wrote into EL_INKA) B4 p_actor='v14-global' -> created=TRUE (wrote into OPPORTUNITYFIT) Enter fullscreen mode Exit fullscreen mode The function checked the claimed actor's write scope. It never checked that the caller was that actor. Worse: the audit log recorded actor_id = v14-ei. The forgery was attributed to the victim. Red #2 — luc_artifact_superseder: impersonation, plus an existence leak SUP2 foreign artifact, own actor -> LK037 · no write mandate on this branch SUP4 absent artifact -> artefact inconnu : ccc… Enter fullscreen mode Exit fullscreen mode Two different answers. LK037 means it exists somewhere else. inconnu means it doesn't exist. A MOVESCAN-only role could enumerate whether any SHA existed in any other branch. We had closed exactly this leak on another function one release earlier. We hadn't closed it here. Red #3 — luc_job_fail: cross-branch denial of service FAIL2 foreign leased job, p_worker='v14-ei' -> DEAD Enter fullscreen mode Exit fullscreen mode A MOVESCAN worker killed an EL_INKA job by claiming to be its owner. The sibling function luc_job_complete refused the identical attack. Same module, two identity contracts. Red #4 and #5 — declared BRANCH_SCOPED, actually global luc_stale_actors returned actors from every branch to a scheduler scoped to one. luc_job_reclaim_expired reclaimed an expired lease belonging to another branch. The registry declared both branch-scoped. A false declaration in a safety registry is worse than no declaration — it looks like proof. The one that hurt the most: the audit log never named the attacker called as postgres : session_user=postgres current_user=postgres called as v14_ms : session_user=v14_ms current_user=postgres Enter fullscreen mode Exit fullscreen mode Inside a SECURITY DEFINER function, current_user is the owner. Two of our functions logged current_user on refusal. So: when an attack succeeded, the log named the victim (the impersonated actor); when an attack failed, the log named postgres. In neither case did the real caller appear. A post-incident investigation on that log would have blamed the wrong party every single time. What we changed One primitive, on the existing binding registry, no second identity system: create function luc_actor_is_exact_caller(p_actor text) returns boolean ... -- the actor's current binding names session_user, textually -- the login role carries exactly one actor -- no pg_has_role (transitive), no superuser exception Enter fullscreen mode Exit fullscreen mode Tested against direct, transitive, collective, stale, current, nonexistent and superuser identities. Then rewired the write gates to it, made "foreign" and "absent" return byte-identical responses, moved the branch check into the function with a returned-and-logged refusal instead of a raw constraint error, and logged session_user everywhere — with the claimed actor kept as a claim, not as an author. Result, on two clean rebuilds: 69 OK · 0 KO, deterministic. Historical suites: zero regression from the fix itself. What it cost us Honesty section. Along the way we introduced four defects of our own — a NOT NULL column that rolled back the very refusal trace we were trying to write, a two-transaction migration the real installer rightly refused, an event block rewritten with a value a foreign key rejected, and a variable/column name collision. All four were found by execution, none by rereading. The full before/after logs ship with the package. The thing we'd tell any small team on Postgres or Supabase Row Level Security decides which rows. It does not decide which actions, under whose authority, with what proof, and who answers for it. If your agent can call a SECURITY DEFINER function with an actor name as a parameter, ask one question: does the function check the parameter, or the caller? Then don't trust your reading. Log in as the narrowest role you have and try to lie. If you'd rather we did that to yours We run the same adversarial battery against your agent's Postgres surface — identity, scope, existence leaks, branch injection, audit attribution — as real login roles, and hand you the matrix: what your agent managed to do that it shouldn't have, with the log. Two days, fixed price, and you keep the harness. Luc Richelet — Calle Asturias 15A, 38660 Adeje, Tenerife, Canary Islands (ES) Email: luc.richelet@hotmail.com

来源报道 · 1 篇 · 以下链接均前往原始媒体

← 返回精选动态 原文

更多内容