Why do we need revocation in both the offered/received HTLC outputs and HTLC timeout/success outputs? The witness script for the output in the HTLC success/timeout transaction is:

OP_IF
    # Penalty transaction
    &lt;revocationpubkey&gt;
OP_ELSE
    `to_self_delay`
    OP_CHECKSEQUENCEVERIFY
    OP_DROP
    &lt;local_delayedpubkey&gt;
OP_ENDIF
OP_CHECKSIG


Which already exists a penalty transaction. While in the offered HTLC and received HTLC outputs in the commitment transaction, we have,

# To remote node with revocation key
OP_DUP OP_HASH160 &lt;RIPEMD160(SHA256(revocationpubkey))&gt; OP_EQUAL
...


Why don't we put the revocation in the HTLC-Timeout/Success outputs only?
HTLCs have a different timeout (cltv_expiry) than the regular timeout that we use for penalty transactions (to_self_delay). That is the reason why we use a separate transaction stage (HTLC success/HTLC timeout) to allow our counterparty sufficient time to exercise their right to get the entire balance of the channel in case we broadcast the previous state of the channel.

To elaborate further, when your counterparty tells you to add a HTLC, your version of the commitment transaction will have 3 outputs:


Paying to your counterparty immediately
Paying to self, guarded by the revocation key for to_self_delay time
Received HTLC output like below

# To remote node with revocation key
OP_DUP OP_HASH160 &lt;RIPEMD160(SHA256(revocationpubkey))&gt; OP_EQUAL
OP_IF
    OP_CHECKSIG
OP_ELSE
    &lt;remote_htlcpubkey&gt; OP_SWAP OP_SIZE 32 OP_EQUAL
    OP_IF
        # To local node via HTLC-success transaction.
        OP_HASH160 &lt;RIPEMD160(payment_hash)&gt; OP_EQUALVERIFY
        2 OP_SWAP &lt;local_htlcpubkey&gt; 2 OP_CHECKMULTISIG
    OP_ELSE
        # To remote node after timeout.
        OP_DROP &lt;cltv_expiry&gt; OP_CHECKLOCKTIMEVERIFY OP_DROP
        OP_CHECKSIG
    OP_ENDIF
OP_ENDIF



When you supply the HTLC pre-image to your counterparty the transaction gets resolved. However, even after successful resolution of the HTLC with your counterparty, let us say you decide to cheat them by force closing the earlier state of the commitment transaction containing the HTLC. As soon as you publish this commitment transaction, you publish the HTLC success transaction that consumes the OP_IF part inside the OP_ELSE. Since the HTLC success transaction is consuming an output that is not timelocked, you are not providing enough time for your counterparty to use their right of the revocation key which is in the received HTLC output. That is the reason there is a second stage, where your spending from the offered HTLC output to yourself is locked until to_self_delay which allows your counterparty to use the revocation secret.

Now you might wonder, why the revocation exists in the commitment transaction received HTLC output if it is provided in the HTLC success/timeout transactions. Let us take the above case to explain it. You added the HTLC and signed the commitment transaction. That HTLC was settled by you providing the pre-image to your counterparty and the commitment transaction containing that HTLC was revoked. Despite that, assume you try to broadcast the previous commitment transaction containing the HTLC and refrains from publishing the HTLC success transaction. If revocation did not exist in the commitment transaction, the counterparty might not be able to get their funds back until the cltv_expiry which might extend to hundreds of blocks (couple of days) if there are a number of hops. This is cumbersome since that HTLC was already settled (especially if there are number of previously satisfied HTLCs), and the provision of revocation in the commitment transaction allows the counterparty to settle them immediately. 

The revocation part is designed so that your counterparty never suffers because of the actions you decide to take to cheat them. The presence of revocation in commitment transaction and the HTLC success/HTLC timeout transaction help protect the Lightning Network participants from frauds committed their peers.