Intro to Browser Security Research
Intro to Browser Security Research
Source: https://securitylab.amnesty.org/latest/2025/03/journalists-targeted-with-pegasus-spyware/
Chrome Vulnerability Reward Program
High-quality report High-quality report High-quality report Baseline
with demonstrating of demonstrated
demonstration of controlled write memory corruption
RCE
Renderer Process
DOM engine
JavaScript engine
etc.
<html>, <body>,
let o = {‘foo’: bar}
<div>, etc.
foo->DoSomething();
Free memory
delete foo;
C++ object lifecycle
Foo *foo = new Foo();
Used memory
foo->DoSomething();
foo
delete foo;
Free memory
C++ object lifecycle
Foo *foo = new Foo();
Used memory
foo->DoSomething();
foo
delete foo;
Free memory
C++ object lifecycle
Foo *foo = new Foo();
Used memory
vtable ptr
foo->DoSomething();
foo
delete foo;
Free memory
C++ object lifecycle
Foo *foo = new Foo();
Used memory
DoSomething ptr
vtable ptr
foo->DoSomething();
foo
delete foo;
Free memory
C++ object lifecycle
Foo *foo = new Foo();
Used memory
foo->DoSomething();
Free memory
delete foo;
Free memory
Use after free
Foo *foo = new Foo();
Used memory
foo->DoSomething();
Free memory
delete foo;
Use after free
Foo *foo = new Foo();
Used memory
delete foo;
Free memory
foo->DoSomething();
Use after free
Foo *foo = new Foo();
Used memory
delete foo;
foo
foo->DoSomething();
Free memory
Use after free
Foo *foo = new Foo();
Used memory
delete foo;
Free memory
foo->DoSomething();
Free memory
Use after free
Foo *foo = new Foo();
Used memory
???
delete foo;
Free memory
foo->DoSomething();
Free memory
Use after free
Foo *foo = new Foo();
Used memory
delete foo;
Attacker-controlled
// attacker-controlled
// allocation
Free memory
foo->DoSomething();
Use after free
Foo *foo = new Foo();
Used memory
Free memory
foo->DoSomething();
Use after free
Foo *foo = new Foo();
Used memory
Attacker-controlled
fake vtable ptr
delete foo;
Attacker-controlled
// attacker-controlled
// allocation
Free memory
foo->DoSomething();
JavaScript security
o = {toString:function() { alert(1); }}
What is a callback
o = {toString:function() { alert(1); }}
JavaScript object
What is a callback
o = {toString:function() { alert(1); }}
Attacker-controlled function
gets called whenever the
object is converted to string
DOM callbacks
<form onsubmit="myfunc()">
<input type="submit">
</form>
DOM callbacks
<form onsubmit="myfunc()">
<input type="submit">
</form>
Attacker-controlled function
gets called whenever certain
DOM events occur
General idea
<script>
let array = [1,2,3,4,5,6,7,8,9,10]
array.sort( function() { array.length = 2; } )
</script>
JavaScript vulnerability (made up example)
<script>
let array = [1,2,3,4,5,6,7,8,9,10]
array.sort( function() { array.length = 2; } )
</script>
<script>
let array = [1,2,3,4,5,6,7,8,9,10]
array.sort( function() { array.length = 2; } )
</script>
var o = {toString:function() {
for(var i=600;i<1000;i++) { arr[i] = 1337; }
}};
arr[0] = o;
arr.sort();
DOM vulnerability (made up example)
<script>
function func() {
document.getElementById("f1").remove();
}
</script>
<form id="f1" onsubmit="func()">
<input type="submit">
</form>
DOM vulnerability (made up example)
<script>
function func() {
document.getElementById("f1").remove();
}
</script>
<form id="f1" onsubmit="func()">
<input type="submit">
</form>
Callback triggers when
form is being submitted
DOM vulnerability (made up example)
<script>
function func() {
document.getElementById("f1").remove();
}
</script>
<form id="f1" onsubmit="func()">
<input type="submit">
</form>
We delete a form while it’s
being submitted. What
happens?
But wait, what about garbage collector?
Languages can be
● Interpreted
● Compiled
Why can’t we have both?
Optimizing compiler
function f(x) {
let arr = [1,2,3,4]
let m = x % 4;
return arr[m];
}
JIT compiler bug (made up example)
function f(x) {
let arr = [1,2,3,4]
let m = x % 4;
If the compiler (incorrectly)
return arr[m];
assumes m must be
} between 0 and 3…
JIT compiler bug (made up example)
function f(x) {
let arr = [1,2,3,4]
let m = x % 4;
…then it might remove
return arr[m];
(optimize away) the array
} index check
JIT compiler bug (made up example)
function f(x) {
let arr = [1,2,3,4]
let m = x % 4;
return arr[m];
}
Source: https://en.wikipedia.org/wiki/Fuzzing
Domato (2017), https://github.com/googleprojectzero/domato
● Generational
● Grammar-based
● Context-free grammars for HTML, CSS and JavaScript
<html> = <lt>html<gt><head><body><lt>/html<gt>
<head> = <lt>head<gt><elements><lt>/head<gt>
<body> = <lt>body<gt><elements><lt>/body<gt>
<elements> = <element><elements>
<elements> = <element>
<element> = <a>
<element> = <audio>
Domato (2017), https://github.com/googleprojectzero/domato
Domato (2017), https://github.com/googleprojectzero/domato
Apple Safari WebKit 17 999, 1038, 1044, 1080, 1082, 1087, 1090,
1097, 1105, 1114, 1241, 1242, 1243, 1244,
1246, 1249, 1250
Total 31*
Then vs. Now
Then:
● Generational Fuzzing
● “Let’s find bugs in the entire browser”
Now:
● Mutational, coverage-guided fuzzing
○ Jackalope, LibAFL, libFuzzer
● Focus on a single component (or interaction between several components)
Future?
● AI (agents)
Let’s analyze a recent Firefox bug
Let’s analyze a recent Firefox bug
What is this?
<items> <xsl:stylesheet version="1.0"
<item>Item 1</item> xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<item>Item 2</item> <xsl:template match="/">
</items> <ul>
<xsl:for-each select="items/item">
<li><xsl:value-of select="."/></li>
</xsl:for-each>
</ul>
</xsl:template>
</xsl:stylesheet>
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
A hidden callback
setTimeout(callback, 0);
A hidden callback
setTimeout(callback, 0);
function callback() {
xmlDoc.removeChild(xmlDoc.childNodes[0]);
FuzzingFunctions.garbageCollect();
FuzzingFunctions.cycleCollect();
}
Inside the callback…
function callback() {
xmlDoc.removeChild(xmlDoc.childNodes[0]);
FuzzingFunctions.garbageCollect();
FuzzingFunctions.cycleCollect();
}
Remove an element from
an XML document, while
that XML document is being
transformed
DEMO
Where to go from now?
● Read more:
○ bug writeups
○ conference talks
○ blog posts
● Take a previous bug
○ Try to reproduce it
○ Analyze how it works
● Find people who report cool bugs and follow them on social media
○ Find people they follow
● Try to do something on your own!