Vulnerability: Merkle.checkMembership allows existence proofs for the same leaf in multiple locations in the tree
Severity: high

Description:
`checkMembership` is used by several contracts to prove that transactions exist in the child chain. The function uses a `leaf`, an `index`, and a `proof` to construct a hypothetical root hash. This constructed hash is compared to the passed in `rootHash` parameter. If the two are equivalent, the `proof` is considered valid.\\nThe proof is performed iteratively, and uses a pseudo-index (j) to determine whether the next proof element represents a “left branch” or “right branch”:\\n```\\nuint256 j = index;\\n// Note: We're skipping the first 32 bytes of `proof`, which holds the size of the dynamically sized `bytes`\\nfor (uint256 i = 32; i <= proof.length; i += 32) {\\n    // solhint-disable-next-line no-inline-assembly\\n    assembly {\\n        proofElement := mload(add(proof, i))\\n    }\\n    if (j % 2 == 0) {\\n        computedHash = keccak256(abi.encodePacked(NODE\\_SALT, computedHash, proofElement));\\n    } else {\\n        computedHash = keccak256(abi.encodePacked(NODE\\_SALT, proofElement, computedHash));\\n    }\\n    j = j / 2;\\n}\\n```\\n\\nIf `j` is even, the computed hash is placed before the next proof element. If `j` is odd, the computed hash is placed after the next proof element. After each iteration, `j` is decremented by `j` = `j` / 2.\\nBecause `checkMembership` makes no requirements on the height of the tree or the size of the proof relative to the provided `index`, it is possible to pass in invalid values for `index` that prove a leaf's existence in multiple locations in the tree.\\nBy modifying existing tests, we showed that for a tree with 3 leaves, leaf 2 can be proven to exist at indices 2, 6, and 10 using the same proof each time. The modified test can be found here: https://gist.github.com/wadeAlexC/01b60099282a026f8dc1ac85d83489fd#file-merkle-test-js-L40-L67\\n```\\nit('should accidentally allow different indices to use the same proof', async () => {\\n  const rootHash = this.merkleTree.root;\\n  const proof = this.merkleTree.getInclusionProof(leaves[2]);\\n\\n  const result = await this.merkleContract.checkMembership(\\n    leaves[2],\\n    2,\\n    rootHash,\\n    proof,\\n  );\\n  expect(result).to.be.true;\\n\\n  const nextResult = await this.merkleContract.checkMembership(\\n    leaves[2],\\n    6,\\n    rootHash,\\n    proof,\\n  );\\n  expect(nextResult).to.be.true;\\n\\n  const nextNextResult = await this.merkleContract.checkMembership(\\n    leaves[2],\\n    10,\\n    rootHash,\\n    proof,\\n  );\\n  expect(nextNextResult).to.be.true;\\n});\\n```\\n\\nConclusion\\nExit processing is meant to bypass exits processed more than once. This is implemented using an “output id” system, where each exited output should correspond to a unique id that gets flagged in the `ExitGameController` contract as it's exited. Before an exit is processed, its output id is calculated and checked against `ExitGameController`. If the output has already been exited, the exit being processed is deleted and skipped. Crucially, output id is calculated differently for standard transactions and deposit transactions: deposit output ids factor in the transaction index.\\nBy using the behavior described in this issue in conjunction with methods discussed in issue 5.8 and https://github.com/ConsenSys/omisego-morevp-audit-2019-10/issues/20, we showed that deposit transactions can be exited twice using indices `0` and `2**16`. Because of the distinct output id calculation, these exits have different output ids and can be processed twice, allowing users to exit double their deposited amount.\\nA modified `StandardExit.load.test.js` shows that exits are successfully enqueued with a transaction index of 65536: https://gist.github.com/wadeAlexC/4ad459b7510e512bc9556e7c919e0965#file-standardexit-load-test-js-L55

Impact:

Recommended mitigation:
Use the length of the proof to determine the maximum allowed index. The passed-in index should satisfy the following criterion: `index < 2**(proof.length/32)`. Additionally, ensure range checks on transaction position decoding are sufficiently restrictive (see https://github.com/ConsenSys/omisego-morevp-audit-2019-10/issues/20).\\nCorresponding issue in plasma-contracts repo: https://github.com/omisego/plasma-contracts/issues/546