Closed Bug 2051015 (CVE-2026-16368) Opened 4 months ago Closed 3 months ago

WebAssembly: integer overflow in `Instance::init` on 32bit SpiderMonkey leads to heap overflow

Categories

(Core :: JavaScript: WebAssembly, defect, P2)

defect

Tracking

()

RESOLVED FIXED
154 Branch
Tracking Status
firefox-esr115 --- unaffected
firefox-esr140 153+ fixed
firefox152 --- wontfix
firefox153 + fixed
firefox154 + fixed

People

(Reporter: nebusec.io, Assigned: jseward)

References

Details

(Keywords: csectype-bounds, reporter-external, sec-high, Whiteboard: [adv-main153+][adv-ESR140.13+])

Attachments

(1 file, 4 external files)

Attached file asan_crash.js —

WebAssembly: integer overflow in Instance::init on 32bit SpiderMonkey leads to heap overflow

Description

At instantiation, Instance::init in js/src/wasm/WasmInstance.cpp trusts this baseline metadata count and performs a raw sizeof(gc::AllocSite) * allocSitesCount multiplication before js_malloc. It then initializes the original count of entries:

uint32_t allocSitesCount = codeTailMeta().numAllocSites;
if (allocSitesCount > 0) {
  allocSites_ =
      (gc::AllocSite*)js_malloc(sizeof(gc::AllocSite) * allocSitesCount);
  if (!allocSites_) {
    ReportOutOfMemory(cx);
    return false;
  }
  for (uint32_t i = 0; i < allocSitesCount; ++i) {
    new (&allocSites_[i]) gc::AllocSite();
    allocSites_[i].initWasm(zone);
  }
}

That layout makes sizeof(gc::AllocSite) 24 bytes on 32-bit targets. A baseline module with 178,956,971 dead-code allocation sites stores allocSitesCount = 178956971. The instantiation allocation computes 24 * 178956971 = 4294967304, which wraps to 8 in 32-bit size_t. The initialization loop still runs 178,956,971 iterations and constructs gc::AllocSite objects through the wrapped allocation, producing heap out-of-bounds writes during WebAssembly.Instance creation before any wasm function is called.

Reproduce

The js shell was compiled with the following mozconfig:

ac_add_options --enable-project=js
ac_add_options --target=i686-pc-linux-gnu

ac_add_options --enable-address-sanitizer
ac_add_options --disable-jemalloc
ac_add_options --disable-optimize
ac_add_options --enable-debug
ac_add_options --disable-install-strip

export CFLAGS="-m32"
export CXXFLAGS="-m32"
export LDFLAGS="-m32"
export HOST_CFLAGS=""
export HOST_CXXFLAGS=""
export HOST_LDFLAGS=""

mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-js-asan-noopt-i686-pc-linux-gnu

Please run the proof-of-concept with:

obj-js-asan-noopt-i686-pc-linux-gnu/js ./asan_crash.js

The expected output:

totalSites=178956971
sitesPerFunc=1900000
funcCount=95
wasmBytes=715828669
wasmCompileMode=baseline
compiling
instantiating
=================================================================
==2221248==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xf580af18 at pc 0x5b37c3bd bp 0xffd928a8 sp 0xffd928a0
WRITE of size 4 at 0xf580af18 thread T0
/audit/ff/firefox/obj-js-asan-noopt-i686-pc-linux-gnu/dist/bin/llvm-symbolizer: error: '[anon:js-executable-memory]': No such file or directory
    #0 0x5b37c3bc in js::gc::AllocSite::AllocSite() /audit/ff/firefox/js/src/gc/Pretenuring.h:90:14
    #1 0x5db3863f in js::wasm::Instance::init(JSContext*, JS::GCVector<JSObject*, 0u, js::SystemAllocPolicy> const&, JS::GCVector<js::wasm::Val, 0u, js::SystemAllocPolicy> const&, JS::Handle<JS::GCVector<js::WasmMemoryObject*, 0u, js::SystemAllocPolicy>>, JS::GCVector<js::WasmGlobalObject*, 0u, js::SystemAllocPolicy> const&, JS::GCVector<js::WasmTagObject*, 0u, js::SystemAllocPolicy> const&, mozilla::Vector<RefPtr<js::wasm::DataSegment const>, 0u, js::SystemAllocPolicy> const&, mozilla::Vector<js::wasm::ModuleElemSegment, 0u, js::SystemAllocPolicy> const&) /audit/ff/firefox/obj-js-asan-noopt-i686-pc-linux-gnu/js/src/wasm/./../../../../js/src/wasm/WasmInstance.cpp:2647:29
    #2 0x5dcdfe45 in js::WasmInstanceObject::create(JSContext*, RefPtr<js::wasm::Code const> const&, mozilla::Vector<RefPtr<js::wasm::DataSegment const>, 0u, js::SystemAllocPolicy> const&, mozilla::Vector<js::wasm::ModuleElemSegment, 0u, js::SystemAllocPolicy> const&, unsigned int, JS::Handle<JS::GCVector<js::WasmMemoryObject*, 0u, js::SystemAllocPolicy>>, mozilla::Vector<RefPtr<js::wasm::Table>, 0u, js::SystemAllocPolicy>&&, JS::GCVector<JSObject*, 0u, js::SystemAllocPolicy> const&, mozilla::Vector<js::wasm::GlobalDesc, 0u, js::SystemAllocPolicy> const&, JS::GCVector<js::wasm::Val, 0u, js::SystemAllocPolicy> const&, JS::GCVector<js::WasmGlobalObject*, 0u, js::SystemAllocPolicy> const&, JS::GCVector<js::WasmTagObject*, 0u, js::SystemAllocPolicy> const&, JS::Handle<JSObject*>, std::unique_ptr<js::wasm::DebugState, JS::DeletePolicy<js::wasm::DebugState>>) /audit/ff/firefox/obj-js-asan-noopt-i686-pc-linux-gnu/js/src/wasm/./../../../../js/src/wasm/WasmJS.cpp:2410:18
    #3 0x5dccd459 in js::wasm::Module::instantiate(JSContext*, js::wasm::ImportValues&, JS::Handle<JSObject*>, JS::MutableHandle<js::WasmInstanceObject*>) const /audit/ff/firefox/obj-js-asan-noopt-i686-pc-linux-gnu/js/src/wasm/./../../../../js/src/wasm/WasmModule.cpp:969:16
    #4 0x5dce0abe in js::WasmInstanceObject::construct(JSContext*, unsigned int, JS::Value*) /audit/ff/firefox/obj-js-asan-noopt-i686-pc-linux-gnu/js/src/wasm/./../../../../js/src/wasm/WasmJS.cpp:2480:28
    #5 0x5cb578ab in CallJSNative(JSContext*, bool (*)(JSContext*, unsigned int, JS::Value*), js::CallReason, JS::CallArgs const&) /audit/ff/firefox/js/src/vm/Interpreter.cpp:498:13
    #6 0x5cb6242a in CallJSNativeConstructor(JSContext*, bool (*)(JSContext*, unsigned int, JS::Value*), JS::CallArgs const&) /audit/ff/firefox/js/src/vm/Interpreter.cpp:516:8
    #7 0x5caecba0 in InternalConstruct(JSContext*, js::AnyConstructArgs const&, js::CallReason) /audit/ff/firefox/js/src/vm/Interpreter.cpp:722:14
    #8 0x5caec0f4 in js::ConstructFromStack(JSContext*, JS::CallArgs const&, js::CallReason) /audit/ff/firefox/js/src/vm/Interpreter.cpp:769:10
    #9 0x5b796f0c in js::jit::DoCallFallback(JSContext*, js::jit::BaselineFrame*, js::jit::ICFallbackStub*, unsigned int, JS::Value*, JS::MutableHandle<JS::Value>) /audit/ff/firefox/obj-js-asan-noopt-i686-pc-linux-gnu/js/src/jit/./../../../../js/src/jit/BaselineIC.cpp:1692:10
    #10 0xe81f0b37  ([anon:js-executable-memory]+0x6b37)

0xf580af18 is located 0 bytes after 8-byte region [0xf580af10,0xf580af18)
allocated by thread T0 here:
    #0 0x59ae0a7d in malloc /builds/worker/fetches/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:67:3
    #1 0x59d13e9e in SystemMalloc::malloc(unsigned int) /audit/ff/firefox/obj-js-asan-noopt-i686-pc-linux-gnu/memory/build/./../../../memory/build/malloc_decls.h:58:1
    #2 0x59d13d81 in DummyArenaAllocator<SystemMalloc>::moz_arena_malloc(unsigned int, unsigned int) /audit/ff/firefox/obj-js-asan-noopt-i686-pc-linux-gnu/memory/build/./../../../memory/build/malloc_decls.h:58:1
    #3 0x59d13c2a in moz_arena_malloc /audit/ff/firefox/obj-js-asan-noopt-i686-pc-linux-gnu/memory/build/./../../../memory/build/malloc_decls.h:209:1
    #4 0x5db4b1ad in js_arena_malloc(unsigned int, unsigned int) /audit/ff/firefox/obj-js-asan-noopt-i686-pc-linux-gnu/dist/include/js/Utility.h:384:10
    #5 0x5dafe970 in js_malloc(unsigned int) /audit/ff/firefox/obj-js-asan-noopt-i686-pc-linux-gnu/dist/include/js/Utility.h:388:10
    #6 0x5db384b0 in js::wasm::Instance::init(JSContext*, JS::GCVector<JSObject*, 0u, js::SystemAllocPolicy> const&, JS::GCVector<js::wasm::Val, 0u, js::SystemAllocPolicy> const&, JS::Handle<JS::GCVector<js::WasmMemoryObject*, 0u, js::SystemAllocPolicy>>, JS::GCVector<js::WasmGlobalObject*, 0u, js::SystemAllocPolicy> const&, JS::GCVector<js::WasmTagObject*, 0u, js::SystemAllocPolicy> const&, mozilla::Vector<RefPtr<js::wasm::DataSegment const>, 0u, js::SystemAllocPolicy> const&, mozilla::Vector<js::wasm::ModuleElemSegment, 0u, js::SystemAllocPolicy> const&) /audit/ff/firefox/obj-js-asan-noopt-i686-pc-linux-gnu/js/src/wasm/./../../../../js/src/wasm/WasmInstance.cpp:2641:25
    #7 0x5dcdfe45 in js::WasmInstanceObject::create(JSContext*, RefPtr<js::wasm::Code const> const&, mozilla::Vector<RefPtr<js::wasm::DataSegment const>, 0u, js::SystemAllocPolicy> const&, mozilla::Vector<js::wasm::ModuleElemSegment, 0u, js::SystemAllocPolicy> const&, unsigned int, JS::Handle<JS::GCVector<js::WasmMemoryObject*, 0u, js::SystemAllocPolicy>>, mozilla::Vector<RefPtr<js::wasm::Table>, 0u, js::SystemAllocPolicy>&&, JS::GCVector<JSObject*, 0u, js::SystemAllocPolicy> const&, mozilla::Vector<js::wasm::GlobalDesc, 0u, js::SystemAllocPolicy> const&, JS::GCVector<js::wasm::Val, 0u, js::SystemAllocPolicy> const&, JS::GCVector<js::WasmGlobalObject*, 0u, js::SystemAllocPolicy> const&, JS::GCVector<js::WasmTagObject*, 0u, js::SystemAllocPolicy> const&, JS::Handle<JSObject*>, std::unique_ptr<js::wasm::DebugState, JS::DeletePolicy<js::wasm::DebugState>>) /audit/ff/firefox/obj-js-asan-noopt-i686-pc-linux-gnu/js/src/wasm/./../../../../js/src/wasm/WasmJS.cpp:2410:18
    #8 0x5dccd459 in js::wasm::Module::instantiate(JSContext*, js::wasm::ImportValues&, JS::Handle<JSObject*>, JS::MutableHandle<js::WasmInstanceObject*>) const /audit/ff/firefox/obj-js-asan-noopt-i686-pc-linux-gnu/js/src/wasm/./../../../../js/src/wasm/WasmModule.cpp:969:16
    #9 0x5dce0abe in js::WasmInstanceObject::construct(JSContext*, unsigned int, JS::Value*) /audit/ff/firefox/obj-js-asan-noopt-i686-pc-linux-gnu/js/src/wasm/./../../../../js/src/wasm/WasmJS.cpp:2480:28
    #10 0x5cb578ab in CallJSNative(JSContext*, bool (*)(JSContext*, unsigned int, JS::Value*), js::CallReason, JS::CallArgs const&) /audit/ff/firefox/js/src/vm/Interpreter.cpp:498:13
    #11 0x5cb6242a in CallJSNativeConstructor(JSContext*, bool (*)(JSContext*, unsigned int, JS::Value*), JS::CallArgs const&) /audit/ff/firefox/js/src/vm/Interpreter.cpp:516:8
    #12 0x5caecba0 in InternalConstruct(JSContext*, js::AnyConstructArgs const&, js::CallReason) /audit/ff/firefox/js/src/vm/Interpreter.cpp:722:14
    #13 0x5caec0f4 in js::ConstructFromStack(JSContext*, JS::CallArgs const&, js::CallReason) /audit/ff/firefox/js/src/vm/Interpreter.cpp:769:10
    #14 0x5b796f0c in js::jit::DoCallFallback(JSContext*, js::jit::BaselineFrame*, js::jit::ICFallbackStub*, unsigned int, JS::Value*, JS::MutableHandle<JS::Value>) /audit/ff/firefox/obj-js-asan-noopt-i686-pc-linux-gnu/js/src/jit/./../../../../js/src/jit/BaselineIC.cpp:1692:10
    #15 0xe81f0b37  ([anon:js-executable-memory]+0x6b37)
    #16 0xe821a537  ([anon:js-executable-memory]+0x537)
    #17 0xe821e8ab  ([anon:js-executable-memory]+0x48ab)
    #18 0xe81ea524  ([anon:js-executable-memory]+0x524)
    #19 0x5c189b81 in EnterBaseline(JSContext*, EnterJitData&) /audit/ff/firefox/obj-js-asan-noopt-i686-pc-linux-gnu/js/src/jit/./../../../../js/src/jit/BaselineJIT.cpp:146:5
    #20 0x5c188f39 in js::jit::EnterBaselineInterpreterAtBranch(JSContext*, js::InterpreterFrame*, unsigned char*) /audit/ff/firefox/obj-js-asan-noopt-i686-pc-linux-gnu/js/src/jit/./../../../../js/src/jit/BaselineJIT.cpp:201:26
    #21 0x5caf8a2b in js::Interpret(JSContext*, js::RunState&) /audit/ff/firefox/js/src/vm/Interpreter.cpp:2040:17
    #22 0x5cae9d92 in MaybeEnterInterpreterTrampoline(JSContext*, js::RunState&) /audit/ff/firefox/js/src/vm/Interpreter.cpp:392:10
    #23 0x5cae9619 in js::RunScript(JSContext*, js::RunState&) /audit/ff/firefox/js/src/vm/Interpreter.cpp:468:13
    #24 0x5caee77c in js::ExecuteKernel(JSContext*, JS::Handle<JSScript*>, JS::Handle<JSObject*>, js::AbstractFramePtr, JS::MutableHandle<JS::Value>) /audit/ff/firefox/js/src/vm/Interpreter.cpp:858:10
    #25 0x5caef00d in js::Execute(JSContext*, JS::Handle<JSScript*>, JS::Handle<JSObject*>, JS::MutableHandle<JS::Value>) /audit/ff/firefox/js/src/vm/Interpreter.cpp:888:10
    #26 0x5d2a5e81 in ExecuteScript(JSContext*, JS::Handle<JSObject*>, JS::Handle<JSScript*>, JS::MutableHandle<JS::Value>) /audit/ff/firefox/obj-js-asan-noopt-i686-pc-linux-gnu/js/src/vm/./../../../../js/src/vm/CompilationAndEvaluation.cpp:552:10
    #27 0x5d2a6163 in JS_ExecuteScript(JSContext*, JS::Handle<JSScript*>) /audit/ff/firefox/obj-js-asan-noopt-i686-pc-linux-gnu/js/src/vm/./../../../../js/src/vm/CompilationAndEvaluation.cpp:576:10
    #28 0x59bddd93 in RunFile(JSContext*, char const*, _IO_FILE*, CompileUtf8, bool, bool) /audit/ff/firefox/obj-js-asan-noopt-i686-pc-linux-gnu/js/src/shell/./../../../../js/src/shell/js.cpp:1413:10
    #29 0x59bdd13d in Process(JSContext*, char const*, bool, FileKind) /audit/ff/firefox/obj-js-asan-noopt-i686-pc-linux-gnu/js/src/shell/./../../../../js/src/shell/js.cpp:2205:14

SUMMARY: AddressSanitizer: heap-buffer-overflow /audit/ff/firefox/js/src/gc/Pretenuring.h:90:14 in js::gc::AllocSite::AllocSite()
Shadow bytes around the buggy address:
  0xf580ac80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0xf580ad00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0xf580ad80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0xf580ae00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0xf580ae80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fd fd
=>0xf580af00: fa fa 00[fa]fa fa fa fa fa fa fa fa fa fa fa fa
  0xf580af80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0xf580b000: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0xf580b080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0xf580b100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0xf580b180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==2221248==ABORTING

Not confirmed, but likely sec-high if it affects Firefox and not just the shell. Eyeballing the POC nothing shell-only jumped out at me, but in future js shell testing please use the --fuzzing-safe option. That disables many shell-only developer functions that lead fuzzers down bind alleys creating invalid states that aren't possible in a Firefox release.

https://searchfox.org/firefox-main/source/js/src/shell/fuzz-flags.txt#:~:text=Note,%2D%2Dfuzzing%2Dsafe

Group: core-security → javascript-core-security

I can confirmed that works with --fuzzing-safe as well. To be clear the current poc only works on 32bit build. The commit hash is 6a252a86c5bb0fdd7a197d1c244f8a28e0827b3a the mirror https://github.com/mozilla-firefox/firefox

/audit/ff/firefox/obj-js-asan-noopt-i686-pc-linux-gnu/dist/bin/js --fuzzing-safe ./asan_crash.js
totalSites=178956971
sitesPerFunc=1900000
funcCount=95
wasmBytes=715828669
wasmCompileMode=baseline+ion
compiling
instantiating
=================================================================
==1247078==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xf5806e58 at pc 0x5b44ce8d bp 0xffc3bf28 sp 0xffc3bf20
WRITE of size 4 at 0xf5806e58 thread T0
/audit/ff/firefox/obj-js-asan-noopt-i686-pc-linux-gnu/dist/bin/llvm-symbolizer: error: '[anon:js-executable-memory]': No such file or directory
...
SUMMARY: AddressSanitizer: heap-buffer-overflow /audit/ff/firefox/js/src/gc/Pretenuring.h:90:14 in js::gc::AllocSite::AllocSite()
Shadow bytes around the buggy address:
  0xf5806b80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0xf5806c00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0xf5806c80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0xf5806d00: fa fa fd fd fa fa 04 fa fa fa fd fd fa fa fd fa
  0xf5806d80: fa fa fd fd fa fa 00 00 fa fa fd fa fa fa fd fd
=>0xf5806e00: fa fa fd fd fa fa 00 00 fa fa 00[fa]fa fa fa fa
  0xf5806e80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0xf5806f00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0xf5806f80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0xf5807000: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0xf5807080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==1247078==ABORTING

This looks real, and I don't think requires anything fuzzing-unsafe. I'm impressed the code doesn't OOM on 32-bit with that many allocation instructions.

Severity: -- → S2
Priority: -- → P2
Assignee: nobody → jseward
Attached file (secure) —
Attached file (secure) —
Group: javascript-core-security → core-security-release
Status: UNCONFIRMED → RESOLVED
Closed: 3 months ago
Resolution: --- → FIXED
Target Milestone: --- → 154 Branch

Please add uplift requests for beta and ESR140

Attached file (secure) —
Attachment #9608825 - Flags: approval-mozilla-beta?

firefox-beta Uplift Approval Request

  • User impact if declined/Reason for urgency: On 32-bit targets only: heap OOB write caused by vanilla wasm input. Whether the written data is controllable by the attacker is unclear; I suspect not.
  • Code covered by automated testing?: yes
  • Fix verified in Nightly?: yes
  • Needs manual QE testing?: no
  • Steps to reproduce for manual QE testing:
  • Risk associated with taking this patch: low
  • Explanation of risk level: Very simple patch, that merely adds overflow checking for a previously unchecked u32 x u32 multiply.
  • String changes made/needed?: none
  • Is Android affected?: yes

firefox-esr140 Uplift Approval Request

  • User impact if declined/Reason for urgency: On 32-bit targets only: heap OOB write caused by vanilla wasm input. Whether the written data is controllable by the attacker is unclear; I suspect not.
  • Code covered by automated testing?: yes
  • Fix verified in Nightly?: yes
  • Needs manual QE testing?: no
  • Steps to reproduce for manual QE testing:
  • Risk associated with taking this patch: low
  • Explanation of risk level: Very simple patch, that merely adds overflow checking for a previously unchecked u32 x u32 multiply.
  • String changes made/needed?: none
  • Is Android affected?: yes
Attachment #9608826 - Flags: approval-mozilla-esr140?
Attached file (secure) —
Attachment #9608825 - Flags: approval-mozilla-beta? → approval-mozilla-beta+
Attachment #9608826 - Flags: approval-mozilla-esr140? → approval-mozilla-esr140+
Duplicate of this bug: 2051872
QA Whiteboard: [sec] [uplift] [qa-triage-done-c154/b153]
Flags: needinfo?(jseward)
Whiteboard: [adv-main153+][adv-ESR140.13+]
Alias: CVE-2026-16368
Group: core-security-release
Flags: sec-bounty?

Unfortunately your bug report fell within the excluded collision window of our automated scans and is not eligible for a bounty
https://github.com/mozilla/bedrock/blob/eaec5cd9e1a0be974702e3d4f153ea9c23c673b8/bedrock/security/templates/security/bug-bounty.html#L27

Flags: sec-bounty? → sec-bounty-
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: