强大的扩展无需复杂的代码。
Powerful extensions do not need powerful code

原始链接: https://adayinthelifeof.nl/2026/08/23/powerful-extensions-do-not-need-powerful-code/

Gosub 浏览器项目旨在解决浏览器安全性与强大扩展功能之间的矛盾,Chrome 的 Manifest V3 升级凸显了这一问题。Gosub 提出的系统并非限制扩展程序的功能,而是侧重于提供“更安全的构建模块”,并使扩展权限的实际影响透明化。 Gosub 不再授予广泛且抽象的权限,而是将清单文件转换为具体的“能力”。它会对这些权限进行综合评估,以揭示其实际后果——例如,如果某个扩展程序同时具备页面读取权限和网络输出权限,系统会向用户发出可能“窃取数据”的警告。该系统为开发者创造了强大的激励机制:使用安全、浏览器原生功能的扩展程序将获得“安静”的安装体验,而使用广泛、特权代码的扩展程序则会触发清晰、明确的警告。 对于广告拦截器而言,这意味着用高性能的原生过滤引擎取代风险高、不受限制的扩展代码,在无需高级访问权限的情况下支持标准语法。通过优先考虑精细、透明的能力授权而非模糊的权限列表,Gosub 旨在实现强大且注重隐私的扩展功能,同时不损害浏览器的安全模型。该项目目前处于设计和原型开发阶段。

```Hacker News 最新 | 过往 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 强大的扩展程序不需要复杂的代码 (adayinthelifeof.nl) 4 分,作者:jaytaph,2 小时前 | 隐藏 | 过往 | 收藏 | 讨论 | 帮助 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系 搜索: ```
相关文章

原文

When Chrome introduced Manifest V3, ad blockers took the biggest hit. The idea behind MV3 itself was not necessarily a bad one: extension code that sits in the request path of every page load is bad for security and bad for performance, so it had to go. The replacement however was a capped and much less expressive rule format, and the most popular type of extension suddenly got a lot worse. Since then, the general feeling seems to be that you can have security, or you can have proper ad blocking, but not both.

We don’t believe that is true. For Gosub, we are designing our extension system around a simple idea: powerful extensions do not need powerful extension code. If the browser itself provides good enough building blocks, an extension can do a lot of things while its own code is allowed to do almost nothing. The install dialog is what nudges extension authors in that direction.

Capabilities, not permissions

In Chrome, the manifest basically is the grant: you list permission names, and those names map more or less directly onto API surface. In Gosub, we treat the manifest as just input. During installation we translate it into an explicit list of capabilities with scopes, things like filtering.block(all sites), content_script(youtube.com) or network.egress_public(api.example.com). That list is what the enforcement layer, the dialogs and revocation all work with, not the manifest itself. This gives us a few things Chrome cannot do:

  • A host permission on its own means nothing. It only means something in combination with the API that uses it: host_permissions plus scripting becomes content_script(hosts), the same hosts plus cookies becomes cookies.read/write(hosts), and so on. There is no general “access to example.com”.
  • Nothing ever translates into a wildcard. The grant is always a concrete list, so a capability we add next year can never silently end up in the grant of an extension that was installed today.
  • An extension can narrow its grant, but never widen it. With an optional gosub key in the manifest, an author can say “of everything my Chrome permissions imply, I only need these”. If that key contains a name the translation did not derive, it is rejected, not granted. And unknown or garbage permission strings (the ecosystem is full of them) are simply ignored.

When permissions combine

Chrome’s install prompt lists permissions one by one, and each line on its own sounds harmless enough. The problem is that permissions combine. An extension that can read pages and can talk to the network, can read your pages and send them somewhere. Neither line tells you this.

So during translation we don’t stop at the individual capabilities. We also calculate what the combinations add up to, and the dialog leads with that instead of with the ingredient list. Let’s look at a real one. This is the manifest of Grammarly, straight from the Chrome Web Store, run through our translator:

Install dialog for Grammarly: derived warnings such as reading passwords or cookies and sending them out, the granted list in plain sentences, the proven "it cannot" claims, and the optional permissions it can ask for later

(All dialog images in this post are styled renderings of the actual output of our translator. None of the text inside them was written by hand.)

To be clear: this does not mean that Grammarly is doing any of these things. It is a perfectly legitimate tool, and to check your writing it simply needs to read what you type, on every site. But that is exactly the point: the current permission model cannot tell the difference between a grammar checker and a keylogger, since both need to read what you type. So the dialog shows what the granted authority makes possible, instead of guessing what the extension intends to do with it. We only inform the user, we never forbid anything; it is still the user who decides.

Further down, the dialog lists what the extension cannot do. We can prove those claims from the grant, and they give the user some contrast to judge the warnings against. And at the very bottom you can see the optional permissions: things Grammarly may ask for later, together with what agreeing to them would unlock.

Loudness as an incentive

Every capability has a tier: silent, standard, loud or gated. Loud grants, and anything that produces a derived warning, get the ! treatment you saw above. So yes, an extension can still do everything with its own privileged code. But if it does, the dialog will spell out exactly what that code is able to do. Do you want a content script on every site? You can have one, but your users will be told in plain words what that means.

The other half of the story is that the browser offers safer building blocks for the things extensions usually do: filtering, cosmetic hiding, a vetted scriptlet library, mediated form filling, declarative DOM actions. If you use such a primitive instead of your own code, your dialog becomes quieter. So the dialog really has two audiences: it tells the user what an extension can do, and it gives the author immediate feedback on how much authority they are asking for. That is basically the whole incentive: a quiet install dialog is the reward for staying on the safe path.

But what about ad blockers?

We keep the core decision of MV3: no extension code in the request path. What we don’t keep is the idea that this has to result in a small, capped rule format.

Instead, Gosub ships a native filter engine (we called it baleen, after the way a whale filters krill) that understands the ABP/uBO list syntax the filter community has been maintaining for years. Blocking rules, exceptions, $important, cosmetic hiding, the common procedural selectors, scriptlets from an audited library, rules the user adds themselves: all of this runs inside the browser, not inside extension code. And it turns out this is fast enough that we don’t need any caps: a stack of 27 lists with 719,000 rules matches in about 7 µs per request, and EasyList + EasyPrivacy in about 1.6 µs. That is roughly twice as fast as Brave’s engine on the same request corpus.

So on Gosub, an ad blocker ships lists, not code. And when it narrows its manifest with the gosub key, it ends up with filtering capabilities that are all silent or standard tier. Here is what a uBO-Lite-style blocker looks like at install time. The dialog comes in two flavors: on the left the regular view that most users will see, plain sentences and nothing else. On the right the power-user view, which adds the capability names and scopes for people who want to verify the claims instead of just believing them. The lines under each warning show how it was derived: which two capabilities combined into it. Most people should never have to see a string like page.exfiltration, but it is there for those who do:

The same install dialog for a uBO Lite clone with the Gosub narrowing key, rendered twice: the regular view with plain sentences on the left, and the power-user view with capability names, scopes and derivation trails on the right

Both views come from the same grant. The only warnings left come from the click-to-zap gesture and from the per-rule match counters, and the dialog says exactly that. It even promises that the extension cannot read pages unless you click it.

To see why this matters, let’s run the raw Chrome manifest of the same extension through the same translator. Chrome’s permission language can only say “scripting, on all sites”, so this is what that honestly amounts to (power-user view again):

Install dialog for uBlock Origin Lite's raw Chrome manifest, power-user view: three large derived warning blocks including page.exfiltration, page.filter_control and remote.page_control

Same extension, same behaviour. The only difference is a grant that is able to express “I only filter”. And that distinction matters: an extension can have a powerful effect without holding an equally powerful general-purpose primitive.

By the way, filter lists get the same treatment as the manifest. A list is exactly the place where you could hide a $redirect rule that runs code inside pages, behind a manifest that looks completely innocent. So anything a bundled list adds to the extension’s authority shows up in the dialog as well, in its own section. Moving authority from the manifest into a rule file should not make it disappear from the security model.

You might wonder how much of the real-world lists we can actually handle natively. We measured it against uBO’s own filter list: 55% of the cosmetic-family rules are scriptlets, 33% are plain cosmetic rules and 11% are procedural. All of these are supported natively. Only 0.8% of the rules would still need the loud content-script route.

Where we are now

All of this exists today as a design prototype: a versioned spec (the capability registry, the composition rules, the dialog rules) and a Rust harness that translates real manifests from start to finish: manifest in, enforced grant out. We run it against 10,165 real manifests from the Chrome Web Store, and 47% of them currently produce at least one combined warning. That probably says more about the permission model these extensions grew up with than about their intentions.

What does not exist yet is the browser side. We are nowhere near implementing all of this in Gosub, and we don’t even know whether the final extension system will look exactly like this. The design still needs a lot of work, and implementing it will undoubtedly expose assumptions that look good on paper but don’t survive contact with a real browser. The dialogs need work as well: we don’t want to scare users with a wall of warning signs until they learn to ignore all of them, but we also don’t want extensions to receive authority the user could not reasonably have expected. Finding that balance is part of the experiment.

If MV3 showed us anything, it is that browsers ask users to approve API names, while extensions deal in effects. By translating manifests into capabilities, spelling out what the combinations mean, and making the dangerous route loud, we think we can keep MV3’s architectural advantage without giving up powerful extensions like ad blockers. And every other kind of extension gets a quiet path to aim for.

联系我们 contact @ memedata.com