uBlock Origin recently added four new scriptlets that AdGuard has no equivalent for — (commit 99e6228):
edit-object-on-getter.js — prune properties from an object on read access
trusted-edit-object-on-getter.js — edit (set new values) properties of an object on read access
edit-object-on-setter.js — prune properties from an object on write access
trusted-edit-object-on-setter.js — edit (set new values) properties of an object on write access
How they work
Scriptlet intercepts property descriptor:
propChain (e.g. "window.__data")
↓
getter trap OR setter trap
↓
JSONPath query applied (prune / edit)
↓
Modified object returned to / stored for page scripts
The core mechanism uses trapProperty that walks the property chain, replaces the descriptor with { get, set } traps, and on access applies JSONPath edits.
Gap analysis
| AdGuard scriptlet |
What it does |
Why it's not equivalent |
set-constant / trusted-set-constant |
Replaces entire property value |
No selective editing — can't say "remove trackingId but keep userName" |
json-prune / json-prune-fetch-response / json-prune-xhr-response |
Intercepts JSON.parse / fetch / XHR |
Only works on network/parse boundaries, not arbitrary property access |
trusted-json-set |
Intercepts method calls via Proxy |
Intercepts function calls, not property descriptor access |
abort-on-property-read/write |
Throws ReferenceError on access |
Only aborts — doesn't modify values |
trusted-prune-inbound-object |
Proxy on native methods, prunes arguments |
Prunes function arguments, not property descriptor returns |
None of these can do: "When window.__CONFIG is read, return it with trackingPreferences removed."
Real-world use case
// Site sets:
window.__INITIAL_STATE__ = {
user: { name: "Alice", id: "123", trackingId: "abc-def", adPreferences: {...} },
config: { theme: "dark", analyticsEnabled: true }
};
// Desired: when any script reads window.__INITIAL_STATE__,
// `trackingId` and `adPreferences` are pruned, `analyticsEnabled` set to false
// example.com##+js(edit-object-on-getter, window.__INITIAL_STATE__, $.user.trackingId $.user.adPreferences $.config.analyticsEnabled)
// Not possible with any existing AdGuard scriptlet
Proposed implementation
1. New helper
A shared helper that defines getter/setter traps on a property chain and applies a configurable edit callback. Can reuse:
getPropertyInChain() — chain walking (get-property-in-chain.ts)
setPropertyAccess() — safe Object.defineProperty wrapper (object-utils.ts)
interceptChainProp() — intermediate chain trap (chain-prop-utils.ts)
getDescriptorAddon() — infinite-loop prevention (get-descriptor-addon.ts)
jsonPruner() / jsonPath() — JSON mutation (prune-utils.ts, json-path-utils.ts)
2. Four new scriptlet files
| File |
Uses |
src/scriptlets/edit-object-on-getter.js |
jsonPruner for prune-only |
src/scriptlets/edit-object-on-setter.js |
jsonPruner for prune-only |
src/scriptlets/trusted-edit-object-on-getter.js |
jsonPath for full edit |
src/scriptlets/trusted-edit-object-on-setter.js |
jsonPath for full edit |
Each accepts: propChain (dot-separated path) + variadic JSONPath expressions.
3. Test files (4), compatibility table updates, auto-generated wiki docs
Design decisions
- JSONPath syntax: Use AdGuard's existing JSONPath syntax from
json-path-utils.ts. uBO compatibility aliases may be needed for cross-blocker filter lists.
- Non-trusted scope: Follow uBO's security boundary — only pruning, no value injection.
- Chain trapping: Follow
set-constant pattern — trap intermediate null/undefined props so the trap activates when the chain materializes.
- Stack matching: Consider adding optional
stack parameter for targeting specific call sites (uBO doesn't include it, but AdGuard's set-constant does).
Related
uBlock Origin recently added four new scriptlets that AdGuard has no equivalent for — (commit 99e6228):
edit-object-on-getter.js— prune properties from an object on read accesstrusted-edit-object-on-getter.js— edit (set new values) properties of an object on read accessedit-object-on-setter.js— prune properties from an object on write accesstrusted-edit-object-on-setter.js— edit (set new values) properties of an object on write accessHow they work
The core mechanism uses
trapPropertythat walks the property chain, replaces the descriptor with{ get, set }traps, and on access applies JSONPath edits.Gap analysis
set-constant/trusted-set-constanttrackingIdbut keepuserName"json-prune/json-prune-fetch-response/json-prune-xhr-responseJSON.parse/fetch/XHRtrusted-json-setProxyabort-on-property-read/writeReferenceErroron accesstrusted-prune-inbound-objectProxyon native methods, prunes argumentsNone of these can do: "When
window.__CONFIGis read, return it withtrackingPreferencesremoved."Real-world use case
Proposed implementation
1. New helper
A shared helper that defines getter/setter traps on a property chain and applies a configurable edit callback. Can reuse:
getPropertyInChain()— chain walking (get-property-in-chain.ts)setPropertyAccess()— safeObject.definePropertywrapper (object-utils.ts)interceptChainProp()— intermediate chain trap (chain-prop-utils.ts)getDescriptorAddon()— infinite-loop prevention (get-descriptor-addon.ts)jsonPruner()/jsonPath()— JSON mutation (prune-utils.ts,json-path-utils.ts)2. Four new scriptlet files
src/scriptlets/edit-object-on-getter.jsjsonPrunerfor prune-onlysrc/scriptlets/edit-object-on-setter.jsjsonPrunerfor prune-onlysrc/scriptlets/trusted-edit-object-on-getter.jsjsonPathfor full editsrc/scriptlets/trusted-edit-object-on-setter.jsjsonPathfor full editEach accepts:
propChain(dot-separated path) + variadic JSONPath expressions.3. Test files (4), compatibility table updates, auto-generated wiki docs
Design decisions
json-path-utils.ts. uBO compatibility aliases may be needed for cross-blocker filter lists.set-constantpattern — trap intermediate null/undefined props so the trap activates when the chain materializes.stackparameter for targeting specific call sites (uBO doesn't include it, but AdGuard'sset-constantdoes).Related
thisobject in json/edit scriptlets, similar to AdGuardtrusted-json-setjsonSource=thisuBlockOrigin/uBlock-issues#4019