This post by Mike Hearn relates an interesting bit of history:

When Bitcoin was first released, it contained two completely fatal bugs that made the entire system worthless. Fortunately, they were found and fixed before Bitcoin actually had any serious value.

The first bug was that scripts were concatenated before being run instead of just using a shared stack. This meant that anyone could write a scriptSig that always evaluated to true and claim anyone elses coins. Fixed here in v0.3.2:


However, the link appears to point to the 0.3.7 update.

Looking at the diff, this update does appear to change the script interpreter in the way Mike outlined.

A search turned up very little on the 0.3.7 update. One hit was this question, which generated no responses:

I noticed that 0.3.7 is released on the website, but after searching the forums I can't find any information on what the changes are. Never mind that the changes from version to version should be packaged with the download....

anyone care to clue me in on this one?

The CVE page, however, makes this claim:

On July 28 2010, two bugs were discovered and demonstrated on the test network. One exploited a bug in the transaction handling code and allowed an attacker to spend coins that they did not own. This was never exploited on the main network, and was fixed by Bitcoin version 0.3.5.

So, depending on the source you use, the release that fixed the bug was 0.3.2, 0.3.5, or 0.3.7.

Given that this was one of the worst bugs in Bitcoin's history, it seems like the documentation should be more consistent. Can someone point me to other sources that might help clear things up?

1 Answer 1


The 0.3.7 update does indeed fix the script execution bug that is being described, the vulnerable code below is removed and replaced with functions that execute the scriptSig and then the scriptPubKey on the same stack.

if (!EvalScript(txin.scriptSig + CScript(OP_CODESEPARATOR) + txout.scriptPubKey, txTo, nIn))

Previously what would happen is that the two script tapes were literally concatenated, then executed as one. The problem here is simply that we can use a trailing OP_PUSHDATA in the scriptSig push the entire scriptPubKey to the stack as a single data element rather than discrete opcodes. Our scriptSig would simply be a push opcode for the length of the scriptPubKey plus an OP_CODESEPERATOR. At the end of execution the only element remaining on the stack is not zero, so the evaluation returns true and we can spend any coins we like.

  • So the change allow only some standard scripts is not related to the issue? Sep 18, 2020 at 9:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.