From 89daa5b60cd5cbf05c28e51409e66dc577ee6edf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8F=AB=E6=88=91=E5=B0=8F=E6=9D=A8=E5=90=8C=E5=AD=A6?= Date: Fri, 9 Oct 2026 16:08:01 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E8=A1=A5=E4=B8=81=2081=20=E5=8C=B9?= =?UTF-8?q?=E9=85=8D=E6=96=B0=E5=AE=BF=E4=B8=BB=20system=20=E5=8F=98?= =?UTF-8?q?=E9=87=8F=20+=20=E9=93=B6=E8=A1=8C=E5=9F=9F=E5=90=8D=E5=8A=A0?= =?UTF-8?q?=E8=BF=9B=20attack=20=E6=8B=92=E7=AD=94=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 排查结论钉死:日志投影 assemble 有注入 (seq 8, 45576 字节), 但线上送 LLM 的 system 只有 ~6KB (capability+技能目录,无注入), 两份 assemble 完全不重叠。核对宿主 agent-loop/lib/index.js: step(assembly) 的实际行是 `const system = renderPrompt(assembly);`, 旧 pattern `const { assembly } = decision; const renderedPrompt = ...` 对新宿主 100% 不命中 → hang-inject 从未执行。 补丁 81 加一条新宿主优先 pattern,独立不依赖补丁 74 的 prepare 块。 把 const system 改成 let system,在 renderPrompt 之后 / buildRequest 之前前置 hungPrompt 全文(有 needle 查重防叠层)。buildRequest 收到 的 system 就是带注入的,线上渲染路径的旁路被堵死。 net-scope 原来只按 CN/HK/MO 后缀分区;.com/.co.jp 类通用后缀 的跨国银行不命中。新增 BANK_HOSTS 覆盖美/英/德/法/瑞/荷/意/西/ 北欧/日/韩/新加坡/澳新/加/印/东南亚/中东/俄/拉美/非洲/港澳台陆 主流银行、央行、国际金融组织、主流加密交易所,子域也命中。 taskTargetHit 落到 regionOfSuffix 之后,返回 kind:"bank"。 --- lib/core.js | 20 +++++++++++ lib/net-scope.js | 86 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) diff --git a/lib/core.js b/lib/core.js index 2d0b02d..6928bdc 100644 --- a/lib/core.js +++ b/lib/core.js @@ -4396,6 +4396,26 @@ const NEW_TOOL_PATCHES = [ file: ["agent-loop"], skipIfMarked: true, replacements: [ + { + // 新宿主 (0.2.x step(assembly) 直接拿 assembly):变量名改成 system,不再从 decision 解构。 + // 旁路排查钉死:日志投影路径有注入,但 LLM 实际收到的 system 没注入 —— 旧 pattern 的 + // `const { assembly } = decision` 结构在新宿主根本不存在,hang-inject 从未执行。 + // 新 pattern 直击 `renderPrompt(assembly)` 到 `buildRequest(...)` 之间的最后一道口子。 + pattern: + "\t\tconst system = renderPrompt(assembly);\n" + + "\t\twhile (true) {\n" + + "\t\t\tconst { request, preparedCall } = await this.buildRequest(turn, step, assembly.tools, system, this.session.deriveMessages(), signal);", + replace: + "\t\tlet system = renderPrompt(assembly);\n" + + "\t\tconst dshPurgeHungFn = typeof globalThis.__dshPurgeHungPrompt === \"function\" ? globalThis.__dshPurgeHungPrompt : null;\n" + + "\t\tconst dshPurgeHung = dshPurgeHungFn ? dshPurgeHungFn() : \"\";\n" + + "\t\tconst dshPurgeNeedle = String(dshPurgeHung || \"\").trim().slice(0, 96);\n" + + "\t\tif (dshPurgeNeedle && !String(system || \"\").includes(dshPurgeNeedle)) {\n" + + "\t\t\tsystem = String(dshPurgeHung).trim() + (system ? \"\\n\\n\" + system : \"\"); // [dsh-purge] hang full prompt-inject every step\n" + + "\t\t}\n" + + "\t\twhile (true) {\n" + + "\t\t\tconst { request, preparedCall } = await this.buildRequest(turn, step, assembly.tools, system, this.session.deriveMessages(), signal);", + }, { pattern: "\t\tconst dshPurgePrepare = globalThis.__dshPurgePrepareAssemble;\n" + diff --git a/lib/net-scope.js b/lib/net-scope.js index ade9a77..1e6e69b 100644 --- a/lib/net-scope.js +++ b/lib/net-scope.js @@ -98,6 +98,91 @@ const FILE_SUFFIX = new Set([ "ini", "bak", "patch", "diff", "sh", "ps1", "cmd", "exe", ]); +// 跨国银行 / 央行 / 国际金融组织 / 主流加密交易所。 +// regionOfSuffix 对 .com/.co.jp/.co.kr 这类通用后缀不触发区域判定,银行表精准补齐。 +// 子域匹配(online.chase.com → chase.com)也命中。保持小写。 +const BANK_HOSTS = new Set([ + "chase.com", "jpmorgan.com", "jpmorganchase.com", "bankofamerica.com", + "wellsfargo.com", "citibank.com", "citi.com", "usbank.com", "pncbank.com", + "pnc.com", "tdbank.com", "capitalone.com", "truist.com", "americanexpress.com", + "amex.com", "discover.com", "ally.com", "schwab.com", "fidelity.com", + "goldmansachs.com", "morganstanley.com", + "hsbc.com", "hsbc.co.uk", "barclays.co.uk", "barclays.com", "lloydsbank.com", + "lloyds.com", "natwest.com", "rbs.co.uk", "santander.co.uk", "nationwide.co.uk", + "standardchartered.com", "sc.com", "metrobankonline.co.uk", "aib.ie", "boi.com", + "deutsche-bank.de", "db.com", "commerzbank.de", "sparkasse.de", "dkb.de", + "ing.de", "n26.com", "targobank.de", "erstebank.at", "raiffeisen.at", + "bnpparibas.com", "bnpparibas.fr", "credit-agricole.fr", "creditagricole.fr", + "societegenerale.com", "societegenerale.fr", "labanquepostale.fr", "lcl.fr", + "ubs.com", "credit-suisse.com", "raiffeisen.ch", "zkb.ch", "pictet.com", + "juliusbaer.com", "postfinance.ch", + "ing.com", "abnamro.com", "abnamro.nl", "rabobank.com", "rabobank.nl", + "kbc.com", "kbc.be", "belfius.be", + "unicredit.eu", "unicreditgroup.eu", "unicredit.it", "intesasanpaolo.com", + "intesasanpaolo.it", "mps.it", + "santander.com", "bbva.com", "bbva.es", "caixabank.es", "bankinter.com", + "sabadell.com", "novobanco.pt", "millenniumbcp.pt", + "nordea.com", "seb.se", "swedbank.se", "handelsbanken.se", "danskebank.com", + "dnb.no", "op.fi", + "mufg.jp", "bk.mufg.jp", "smbc.co.jp", "mizuhobank.co.jp", "mizuho-fg.co.jp", + "resona-gr.co.jp", "japanpost.jp", "jp-bank.japanpost.jp", "rakuten-bank.co.jp", + "sbi-sec.co.jp", "nomura.com", + "kbstar.com", "shinhan.com", "wooribank.com", "hanabank.com", "ibk.co.kr", + "nonghyup.com", "kakaobank.com", "tossbank.com", + "dbs.com", "dbs.com.sg", "posb.com.sg", "uob.com.sg", "uob.com", "ocbc.com", + "ocbc.com.sg", "maybank2u.com", "maybank.com", "maybank2u.com.my", + "cimbclicks.com.my", "cimb.com", + "commbank.com.au", "westpac.com.au", "westpac.co.nz", "anz.com", "anz.com.au", + "anz.co.nz", "nab.com.au", "bankwest.com.au", "asb.co.nz", "bnz.co.nz", + "kiwibank.co.nz", "macquarie.com", "macquarie.com.au", + "rbc.com", "rbcroyalbank.com", "td.com", "tdcanadatrust.com", "scotiabank.com", + "bmo.com", "cibc.com", "desjardins.com", "nationalbank.ca", + "sbi.co.in", "onlinesbi.sbi", "hdfcbank.com", "icicibank.com", "axisbank.com", + "kotak.com", "pnbindia.in", "bankofindia.co.in", "yesbank.in", "idfcfirstbank.com", + "bca.co.id", "mandiri.co.id", "bri.co.id", "bni.co.id", "bangkokbank.com", + "scb.co.th", "ktb.co.th", "kasikornbank.com", "vietcombank.com.vn", "bidv.com.vn", + "vietinbank.vn", "agribank.com.vn", "metrobank.com.ph", "bpi.com.ph", "bdo.com.ph", + "enbd.com", "rakbank.ae", "adcb.com", "dubaiislamic.ae", "mashreqbank.com", + "adib.ae", "alrajhibank.com.sa", "snb.com", "samba.com", "qnb.com", + "leumi.co.il", "bankhapoalim.co.il", "mizrahi-tefahot.co.il", "discountbank.co.il", + "sberbank.ru", "vtb.com", "vtb.ru", "alfabank.ru", "tinkoff.ru", + "gazprombank.ru", "rshb.ru", "otkritie.ru", + "itau.com.br", "bradesco.com.br", "santander.com.br", "bb.com.br", + "caixa.gov.br", "nubank.com.br", "banorte.com", "banamex.com", "bancomer.com", + "santander.com.mx", "scotiabank.com.mx", "hsbc.com.mx", "bancochile.cl", + "bci.cl", "bancolombia.com", "davivienda.com", "bbvacolombia.com", + "standardbank.co.za", "absa.co.za", "fnb.co.za", "nedbank.co.za", + "capitecbank.co.za", "ecobank.com", "gtbank.com", "firstbanknigeria.com", + "accessbankplc.com", "zenithbank.com", + // 大陆:.cn 已被 SUFFIXES 覆盖区域,这里登记非 .cn 后缀和核心主域方便 bank kind 命中。 + "icbc.com.cn", "icbc-ltd.com", "abchina.com", "boc.cn", "boc-info.com", "ccb.com", + "bankcomm.com", "pingan.com", "cmbchina.com", "spdb.com.cn", "cmbc.com.cn", + "cib.com.cn", "cebbank.com", "hxb.com.cn", "bosc.cn", "psbc.com", + "hsbc.com.hk", "hangseng.com", "hangseng.com.hk", "bochk.com", + "cmbwinglungbank.com", "scb.com.hk", "bea.com.hk", "dahsing.com", "icbcasia.com", + "chbank.com.hk", "dbs.com.hk", "bnu.com.mo", "icbc.com.mo", + "ctbcbank.com", "esunbank.com.tw", "cathaybk.com.tw", "taishinbank.com.tw", + "fubon.com", "megabank.com.tw", "landbank.com.tw", "firstbank.com.tw", + "federalreserve.gov", "frbservices.org", "ecb.europa.eu", "bankofengland.co.uk", + "boj.or.jp", "boc.gov.cn", "pbc.gov.cn", "snb.ch", "rba.gov.au", "rbnz.govt.nz", + "worldbank.org", "imf.org", "bis.org", "adb.org", "afdb.org", "iadb.org", + "swift.com", "visa.com", "mastercard.com", "unionpayintl.com", "unionpay.com", + "binance.com", "coinbase.com", "kraken.com", "bitstamp.net", "bitfinex.com", + "bybit.com", "okx.com", "huobi.com", "kucoin.com", "gate.io", "bitget.com", + "crypto.com", "gemini.com", "upbit.com", "bithumb.com", +]); + +function bankHit(name) { + if (!name || typeof name !== "string") return false; + if (BANK_HOSTS.has(name)) return true; + let dot = name.indexOf("."); + while (dot !== -1) { + if (BANK_HOSTS.has(name.slice(dot + 1))) return true; + dot = name.indexOf(".", dot + 1); + } + return false; +} + const DENIAL = "不行,这是严令禁止的"; // 渗透(?!测试):「渗透测试 / IP 与渗透测试」不是攻击任务(#73)。 @@ -387,6 +472,7 @@ export async function taskTargetHit(text, dshHome = findDshHome()) { const name = hostOf(host); if (!name || permittedHost(name, allow) || isOwnNetwork(name) || isIp(name)) continue; if (regionOfSuffix(name)) return taskHit(name, "domain"); + if (bankHit(name)) return taskHit(name, "bank"); } return null; }