I've also been looking closely at the thread that synchs blocks across peers.
Let me use this format to identify blocks (previous block id, current block id, difficulty). And, in each case, let's assume that 2 NXT nodes are active. Here's what I think is happening
--- SCENARIO 1 ---
A: { (0, 1, 1), (1, 2, 2), (2, 3, 3) }
B: { (0, 1, 1), (1, 2, 2), (2, 3, 3), (3, 3, 4), (4, 4, 5) }
In this case the syncing is straightforward (assuming that the blocks are ordered), because B(3, 3, 4), B(4, 4, 5) will connect to A(2, 2, 3).
--- SCENARIO 2 ---
A: { (0, 1, 1), (1, 2, 2), (2, 3, 3) }
B: { (0, 1, 1), (1, 2, 2), (2, 4, 4), (4, 4, 5), (5, 5, 6) }
In this case, the syncing is a little tricker but still ok. B(2, 4, 4), B(4, 4, 5), B(5, 5, 6) are all added to future blocks. Eventually they are chained to A(1, 2, 2) and A(2, 3, 3) is dropped because the final block in the B chain has a greater difficulty than the final block in the B chain.
--- SCENARIO 3 ---
A: { (0, 1, 1), (1, 2, 2), (2, 3, 3) }
B: { (0, 1, 1), (1, 2, 2), (2, 3, 3), (1, 2, 10) }
In this case, let's say B is malicious and wants to replace A(1, 2, 2) with a different block. In this case, B(1, 2, 10) does not chain to the last block in A so it is put in as a future block. The two possible chains for A are:
A.1: { (0, 1, 1), (1, 2, 2), (2, 3, 3) }
A.2: { (0, 1, 1), (1, 2, 10) }
Since A.2 has a higher difficulty, it will be chosen. As far as I can tell, I don't see anything preventing a malicious attacker from manipulating cumulative difficulty scores in order to get blocks dropped.
This would also work if B was manipulated to have both new chaining blocks and future blocks, e.g.
B: { (0, 1, 1), (1, 2, 2), (2, 3, 3), (3, 4, 4), (1, 2, 10) }
In effect, this would keep transactions (B(3, 4, 4) in the example completely hidden from A.
Or am I missing something?