Skip to content

Conversation

@davidmurdoch
Copy link
Contributor

@davidmurdoch davidmurdoch commented Jan 6, 2026

CHANGELOG entry: null

Pre-merge author checklist

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

Note

Updates dependency targets and LavaMoat policy to align with newer Browserslist data.

  • Bumps browserslist to ^4.28.1 and refreshes lockfile, updating baseline-browser-mapping, caniuse-lite, electron-to-chromium, node-releases, and update-browserslist-db
  • Adjusts lavamoat/build-system/policy.json globals: replace process.exit with process, add console.info and console.trace

Written by Cursor Bugbot for commit 2781195. This will update automatically on new commits. Configure here.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 6, 2026

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@davidmurdoch
Copy link
Contributor Author

@metamaskbot update-policies

@metamaskbot metamaskbot added the team-extension-platform Extension Platform team label Jan 6, 2026
@socket-security
Copy link

socket-security bot commented Jan 6, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatedbrowserslist@​4.26.3 ⏵ 4.28.19810091 +189100

View full report

@metamaskbot
Copy link
Collaborator

Policies updated.
👀 Please review the diff for suspicious new powers.

🧠 Learn how: https://lavamoat.github.io/guides/policy-diff/#what-to-look-for-when-reviewing-a-policy-diff

@metamaskbotv2
Copy link
Contributor

metamaskbotv2 bot commented Jan 6, 2026

✨ Files requiring CODEOWNER review ✨

📜 @MetaMask/policy-reviewers (1 files, +3 -1)
  • 📁 lavamoat/
    • 📁 build-system/
      • 📄 policy.json +3 -1

Tip

Follow the policy review process outlined in the LavaMoat Policy Review Process doc before expecting an approval from Policy Reviewers.

@metamaskbotv2
Copy link
Contributor

metamaskbotv2 bot commented Jan 6, 2026

Builds ready [4286dd8]
UI Startup Metrics (1291 ± 117 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup12911011164111713611501
load1078857139911211411281
domContentLoaded1072852139511111361273
domInteractive271599192381
firstPaint146631204123183253
backgroundConnect21420025310220237
firstReactRender1483141623
getState3814112154266
initialActions104112
loadScripts86565211851119331062
setupStore1252741322
numNetworkReqs171172161165
BrowserifyPower User HomeuiStartup------
load------
domContentLoaded------
domInteractive------
firstPaint------
backgroundConnect------
firstReactRender------
getState------
initialActions------
loadScripts------
setupStore------
numNetworkReqs------
WebpackStandard HomeuiStartup825682111577866951
load65858484563672822
domContentLoaded65257783762664815
domInteractive2716111212390
firstPaint1096336360130254
backgroundConnect2461282930105
firstReactRender16103241825
getState3716158244671
initialActions104112
loadScripts64957582860661806
setupStore1363971527
numNetworkReqs171173171167
WebpackPower User HomeuiStartup------
load------
domContentLoaded------
domInteractive------
firstPaint------
backgroundConnect------
firstReactRender------
getState------
initialActions------
loadScripts------
setupStore------
numNetworkReqs------
FirefoxBrowserifyStandard HomeuiStartup13891088244320014681670
load1111921168412011811324
domContentLoaded1111920167912011801323
domInteractive66312253987136
firstPaint------
backgroundConnect54201854265164
firstReactRender1394541222
getState156111181339
initialActions102012
loadScripts1077908165910711411242
setupStore164149211549
numNetworkReqs19983191376
BrowserifyPower User HomeuiStartup25361534363854430063201
load1736986278453322042447
domContentLoaded1735986278453321992446
domInteractive10734971141101315
firstPaint------
backgroundConnect4002511393999401106
firstReactRender20126982529
getState1195191487130185
initialActions208123
loadScripts1441969258545319722247
setupStore665107017949239
numNetworkReqs69191783478160
WebpackStandard HomeuiStartup15911274211118816971950
load13401109194815114441575
domContentLoaded13391109194715114441574
domInteractive802720543108161
firstPaint------
backgroundConnect56171553867146
firstReactRender15115261623
getState2072773516105
initialActions103122
loadScripts13061094193113913931529
setupStore195227291475
numNetworkReqs19986191376
WebpackPower User HomeuiStartup26531560364052731103313
load19411146272448323692559
domContentLoaded19401146272448323692558
domInteractive80313958087278
firstPaint------
backgroundConnect3542311583544161072
firstReactRender221385112646
getState123571101140123214
initialActions219123
loadScripts16791131251942220922386
setupStore36410481053691
numNetworkReqs67211823772170
📊 Page Load Benchmark Results

Current Commit: 4286dd8 | Date: 1/6/2026

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.05s (±53ms) 🟡 | historical mean value: 1.05s ⬇️ (historical data)
  • domContentLoaded-> current mean value: 728ms (±50ms) 🟢 | historical mean value: 729ms ⬇️ (historical data)
  • firstContentfulPaint-> current mean value: 77ms (±11ms) 🟢 | historical mean value: 77ms ⬇️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.05s 53ms 1.01s 1.32s 1.10s 1.32s
domContentLoaded 728ms 50ms 696ms 997ms 762ms 997ms
firstPaint 77ms 11ms 60ms 168ms 88ms 168ms
firstContentfulPaint 77ms 11ms 60ms 168ms 88ms 168ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 58 Bytes (0%)
  • ui: 0 Bytes (0%)
  • common: 20 Bytes (0%)

@davidmurdoch davidmurdoch marked this pull request as ready for review January 6, 2026 23:24
@davidmurdoch davidmurdoch requested a review from a team as a code owner January 6, 2026 23:24
"console.log": true,
"console.warn": true,
"process.exit": true
"process": true
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Broadened process permissions may expose environment variables

Medium Severity

The policy change for browserslist>baseline-browser-mapping from process.exit to process significantly broadens permissions. The full process object includes process.env (environment variables often containing CI secrets, API keys), process.argv, and other sensitive capabilities. Other packages in this policy file use granular permissions like process.exit, process.cwd, or process.stderr.write. If baseline-browser-mapping only needs to exit the process, the broader process permission grants unnecessary access that could be exploited if the package is compromised.

Fix in Cursor Fix in Web

Copy link
Contributor

@MajorLift MajorLift Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Granting unnecessary process.env access to a build process dependency isn't ideal, and the fix looks simple:

The process entry can be removed by adding process.argv as an override (the following passes yarn lavamoat:auto locally):

diff --git a/lavamoat/build-system/policy-override.json b/lavamoat/build-system/policy-override.json
index 512734d809..1f81ec6b2d 100644
--- a/lavamoat/build-system/policy-override.json
+++ b/lavamoat/build-system/policy-override.json
@@ -593,6 +593,12 @@
       "packages": {
         "@babel/core>@babel/types": true
       }
+    },
+    "browserslist>baseline-browser-mapping": {
+      "globals": {
+        "process.exit": true,
+        "process.argv": true
+      }
     }
   }
 }
diff --git a/lavamoat/build-system/policy.json b/lavamoat/build-system/policy.json
index 36f6a625de..79b637c254 100644
--- a/lavamoat/build-system/policy.json
+++ b/lavamoat/build-system/policy.json
@@ -1620,6 +1620,7 @@
       "globals": {
         "console.log": true,
         "console.warn": true,
+        "process.argv": true,
         "process.exit": true
       }
     },

That said, the packages don't seem to be used in any way that could directly expose vulnerabilities, and they're both well maintained by reputable orgs. @davidmurdoch What do you think -- worth the trouble?

@naugtur It looks like policy generation came up with wider permissions than necessary here (top-level global object instead of nested capabilities). Is this expected behavior?

Copy link
Contributor

@naugtur naugtur Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re "worth the trouble" - sha1-hulud has caught very reputable organizations off-guard. It's not whether we trust the org, it's whether we trust the contents of a package on npm ;)
Narrowing down these policies is a very responsible thing to do.

Policy generation is the best-effort estimation of what seems necessary for the package to work. Depending on how it accesses the globals we sometimes can figure out a subset of fields from the AST, but some AST shapes will cause us to defer to the whole global field. We can't generate a policy that's too narrow because it'd force devs to have to add overrides for many common and harmless globals.

The globals that should be preferred for narrowing down are things like process, document, or chrome - the ones that are bags of mixed capabilities. Once we get past the basics of providing a modern version of lavamoat for node, we are planning to focus on the capabilities that need special treatment (at runtime and in policy review)

Please continue to be vigilant about narrowing down policies for the most powerful capabilities. This is great work! 👏 👏 👏

Also, I'm impressed that AI can now understand implications of policy diffs.
Any ideas how to make it better?

Copy link
Contributor

@MajorLift MajorLift Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this can't be narrowed after all due to a typeof process !== undefined in the dependency. :(

Any ideas how to make it better?

We could add relevant information or instructions to AGENTS.md, but it seems like cursorbot and other models already have a pretty good understanding of what lavamoat does just from having docs/lavamoat-policy-review-process.md in context.

I asked which AST shapes would cause deferral to wider permissions here and got this response:

AST Shapes That Cause LavaMoat to Defer to Wider Permissions

LavaMoat's policy generator (lavamoat-tofu) tries to determine the most specific global access path by walking the AST's member expression chain. When it can't follow the chain, it defers to the parent/wider permission.

How the Analysis Works

For an identifier like process, lavamoat-tofu:

  1. Finds all references to global process
  2. For each reference, walks up the parent chain looking for an unbroken sequence of non-computed MemberExpression nodes
  3. Builds a path like ['process', 'env', 'NODE_ENV'] from that chain
  4. If the chain is empty or broken, returns just ['process']

The key function is isNonComputedMemberLikeExpression:

function isNonComputedMemberLikeExpression(node) {
  return !node.computed && isMemberLikeExpression(node);
}

AST Shapes That Cause Deferral

1. typeof Check on Bare Identifier

typeof process !== 'undefined';

AST:

UnaryExpression
├── operator: "typeof"
└── argument: Identifier("process")  ← parent is UnaryExpression, NOT MemberExpression

Why it defers: The process identifier's parent is UnaryExpression, which fails isNonComputedMemberLikeExpression. Result: memberExpressions = [], so path = ['process'].


2. Bare Identifier in Logical/Binary Expressions

process && process.env;

AST:

LogicalExpression
├── operator: "&&"
├── left: Identifier("process")  ← parent is LogicalExpression, NOT MemberExpression
└── right: MemberExpression(process.env)

Why it defers: The left process has LogicalExpression as parent. The right process.env would produce ['process', 'env'], but the left one produces ['process']. LavaMoat then reduces to the topmost (widest) path, keeping just process.


3. Computed Property Access

process['env'];
// or
process[someVariable];

AST:

MemberExpression
├── object: Identifier("process")
├── property: StringLiteral("env") or Identifier(someVariable)
└── computed: true  ← fails isNonComputedMemberLikeExpression!

Why it defers: computed: true fails the check. The chain breaks, so path = ['process'].


4. Identifier Passed as Argument

someFunction(process);

AST:

CallExpression
├── callee: Identifier("someFunction")
└── arguments: [Identifier("process")]  ← parent is CallExpression, NOT MemberExpression

Why it defers: Parent is CallExpression, not MemberExpression. Path = ['process'].


5. Assignment to Variable (Aliasing)

const p = process;
p.env.NODE_ENV; // later usage

AST for const p = process:

VariableDeclarator
├── id: Identifier("p")
└── init: Identifier("process")  ← parent is VariableDeclarator, NOT MemberExpression

Why it defers: The process reference is assigned to p. LavaMoat sees process with parent VariableDeclarator. Path = ['process'].


6. Destructuring

const { env } = process;

AST:

VariableDeclarator
├── id: ObjectPattern({ env })
└── init: Identifier("process")  ← bare reference to get the object to destructure

Why it defers: Same as aliasing - process is referenced without property access. The destructuring analysis in lavamoat-tofu tries to expand this, but a RestElement or computed property in the pattern causes fallback to ['process'].


The Reduction Rule

After analyzing all references, lavamoat-tofu calls reduceToTopmostApiCalls:

// If array contains 'process' and 'process.env' just keep 'process'

So even if some references produce process.env and others produce process, the final policy contains just process since it's the topmost (widest, most permissive) path that covers all accesses.


Real-World Example: baseline-browser-mapping v2.9.11

The code contains:

"undefined"!=typeof process && process.env && ...

This creates:

  • typeof process → path ['process'] (Pattern 1)
  • process && ... → left side produces ['process'] (Pattern 2)
  • process.env → path ['process', 'env']

After reduction: ['process'] wins because it's the topmost path.


Summary Table

Pattern Parent Node Type Can Follow Chain? Result
process.env MemberExpression ✅ Yes process.env
typeof process UnaryExpression ❌ No process
process && x LogicalExpression ❌ No process
process["env"] MemberExpression (computed) ❌ No process
fn(process) CallExpression ❌ No process
const p = process VariableDeclarator ❌ No process
const {env} = process VariableDeclarator ❌ No process

@metamaskbotv2
Copy link
Contributor

metamaskbotv2 bot commented Jan 6, 2026

Builds ready [99f6224]
UI Startup Metrics (1232 ± 89 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup1232102215338912801366
load103185512878210831147
domContentLoaded102585012788110751135
domInteractive2515105182177
firstPaint161651064140183277
backgroundConnect21519626313222243
firstReactRender1492941525
getState341994113859
initialActions103111
loadScripts818651106582871937
setupStore1051821116
numNetworkReqs171176161166
BrowserifyPower User HomeuiStartup------
load------
domContentLoaded------
domInteractive------
firstPaint------
backgroundConnect------
firstReactRender------
getState------
initialActions------
loadScripts------
setupStore------
numNetworkReqs------
WebpackStandard HomeuiStartup7996511051908521013
load65057394780697811
domContentLoaded64556894380692802
domInteractive241584172180
firstPaint955921139105189
backgroundConnect285126284299
firstReactRender15108291527
getState311578143959
initialActions104112
loadScripts64256694079690800
setupStore1153861125
numNetworkReqs181180171169
WebpackPower User HomeuiStartup------
load------
domContentLoaded------
domInteractive------
firstPaint------
backgroundConnect------
firstReactRender------
getState------
initialActions------
loadScripts------
setupStore------
numNetworkReqs------
FirefoxBrowserifyStandard HomeuiStartup14041086180416015121666
load1125922159112111921352
domContentLoaded1125917159112111921352
domInteractive69311763389129
firstPaint------
backgroundConnect59181874582171
firstReactRender1394651325
getState1267491126
initialActions102012
loadScripts1087908156110411551235
setupStore134130151043
numNetworkReqs19990191475
BrowserifyPower User HomeuiStartup24011404392551827703074
load1665991253248120902290
domContentLoaded1664991252648120902290
domInteractive78353316577255
firstPaint------
backgroundConnect3262114133503411156
firstReactRender20125082438
getState1105496396115212
initialActions2025223
loadScripts1423976250441918882083
setupStore55696413547156
numNetworkReqs69181783476161
WebpackStandard HomeuiStartup16061331307222417171899
load13411112281319114111581
domContentLoaded13411112281319114111581
domInteractive792922742110154
firstPaint------
backgroundConnect56192004071150
firstReactRender15113141525
getState2272413916102
initialActions103122
loadScripts13081099271818013741519
setupStore215219321696
numNetworkReqs19983191377
WebpackPower User HomeuiStartup28701670449756932633611
load21011256371156125522777
domContentLoaded21001256371156125522776
domInteractive84314638873337
firstPaint------
backgroundConnect3992612484034331212
firstReactRender21134982744
getState119611399160106182
initialActions213123
loadScripts18031235350550722692628
setupStore615125119634196
numNetworkReqs66231853582155
📊 Page Load Benchmark Results

Current Commit: 99f6224 | Date: 1/6/2026

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.03s (±37ms) 🟡 | historical mean value: 1.05s ⬇️ (historical data)
  • domContentLoaded-> current mean value: 720ms (±35ms) 🟢 | historical mean value: 729ms ⬇️ (historical data)
  • firstContentfulPaint-> current mean value: 76ms (±10ms) 🟢 | historical mean value: 77ms ⬇️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.03s 37ms 1.01s 1.31s 1.06s 1.31s
domContentLoaded 720ms 35ms 701ms 991ms 744ms 991ms
firstPaint 76ms 10ms 60ms 164ms 84ms 164ms
firstContentfulPaint 76ms 10ms 60ms 164ms 84ms 164ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 58 Bytes (0%)
  • ui: 0 Bytes (0%)
  • common: 20 Bytes (0%)

@metamaskbotv2
Copy link
Contributor

metamaskbotv2 bot commented Jan 7, 2026

Builds ready [2781195]
UI Startup Metrics (1271 ± 120 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup12711017158912013491462
load1067856138010911321254
domContentLoaded1060851136910711281245
domInteractive251595182179
firstPaint147641211124185282
backgroundConnect21319726611220234
firstReactRender1493951627
getState371986124360
initialActions105113
loadScripts85565111731079251034
setupStore1273441221
numNetworkReqs171179171169
BrowserifyPower User HomeuiStartup17471409231217818222086
load1070898157912411591285
domContentLoaded1058891157212311471275
domInteractive3116187252893
firstPaint164681288130212269
backgroundConnect24219952851246310
firstReactRender14101921517
getState17712567860192238
initialActions102112
loadScripts84068813541209241066
setupStore1564271433
numNetworkReqs67522072663125
WebpackStandard HomeuiStartup786644103373820947
load64257282565684774
domContentLoaded63756881564680767
domInteractive2415116192079
firstPaint985933651109206
backgroundConnect275133293696
firstReactRender14103941524
getState3215137194059
initialActions104112
loadScripts63456680663678759
setupStore1164061325
numNetworkReqs181181171169
WebpackPower User HomeuiStartup1144917186017112021487
load707592114586731864
domContentLoaded701586114085724857
domInteractive30161922725100
firstPaint1246370480163226
backgroundConnect5174968955275
firstReactRender16122821720
getState13712020214144161
initialActions103111
loadScripts698584113284721854
setupStore1484071336
numNetworkReqs67522192761129
FirefoxBrowserifyStandard HomeuiStartup14471103265723415381825
load1165925227220012241404
domContentLoaded1164925227220012241404
domInteractive9232112515191150
firstPaint------
backgroundConnect57201914576163
firstReactRender14104751421
getState14791101527
initialActions103122
loadScripts1128907216618311861329
setupStore164166211448
numNetworkReqs19983191475
BrowserifyPower User HomeuiStartup25411562399155429293263
load16731023266653921782504
domContentLoaded16731023266653821742504
domInteractive813397810684231
firstPaint------
backgroundConnect3642611984074351135
firstReactRender19126072427
getState117571126135115164
initialActions208123
loadScripts13811008243943114742317
setupStore35594910021116
numNetworkReqs74501572980148
WebpackStandard HomeuiStartup16281339212717017131995
load13511123180512214051551
domContentLoaded13501123180512214051551
domInteractive883233551115202
firstPaint------
backgroundConnect63182414289145
firstReactRender15102731624
getState135132141331
initialActions103122
loadScripts13111103171411013731503
setupStore214175291797
numNetworkReqs20983201579
WebpackPower User HomeuiStartup27441613363753531273449
load20421148278252225042671
domContentLoaded20421147278152225042671
domInteractive9330107313675379
firstPaint------
backgroundConnect3212212383613561144
firstReactRender19125472331
getState111601131111102222
initialActions213123
loadScripts17961132257947022792485
setupStore594109718523211
numNetworkReqs72471562978146
📊 Page Load Benchmark Results

Current Commit: 2781195 | Date: 1/7/2026

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.04s (±68ms) 🟡 | historical mean value: 1.04s ⬆️ (historical data)
  • domContentLoaded-> current mean value: 733ms (±66ms) 🟢 | historical mean value: 725ms ⬆️ (historical data)
  • firstContentfulPaint-> current mean value: 76ms (±13ms) 🟢 | historical mean value: 77ms ⬇️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.04s 68ms 1.01s 1.33s 1.27s 1.33s
domContentLoaded 733ms 66ms 699ms 999ms 941ms 999ms
firstPaint 76ms 13ms 60ms 188ms 88ms 188ms
firstContentfulPaint 76ms 13ms 60ms 188ms 88ms 188ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 58 Bytes (0%)
  • ui: 0 Bytes (0%)
  • common: 20 Bytes (0%)

@davidmurdoch davidmurdoch enabled auto-merge January 7, 2026 17:24
@davidmurdoch davidmurdoch added this pull request to the merge queue Jan 8, 2026
Merged via the queue into main with commit 88565f1 Jan 8, 2026
190 checks passed
@davidmurdoch davidmurdoch deleted the chore-udpate-browserslist branch January 8, 2026 14:41
@github-actions github-actions bot locked and limited conversation to collaborators Jan 8, 2026
@metamaskbot metamaskbot added the release-13.14.0 Issue or pull request that will be included in release 13.14.0 label Jan 8, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

release-13.14.0 Issue or pull request that will be included in release 13.14.0 size-XS team-extension-platform Extension Platform team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants