Lazio beat bitter rivals Roma to book Coppa Italia semi-final berth
Zaccagni broke the deadlock from the spot six minutes into the second half after Roma's new signing Dean Huijsen had fouled Taty Castellanos.
Roma came close to securing a late equaliser, but Lazio goalkeeper Christos Mandate made an impressive save from Andrea Belotti's half-volley.
To add to Roma manager Jose Mourinho's woes, his Argentine forward Paulo Dybala was substituted at half time due to injury.
"I felt that in the first half, we were the team with the most character, set out well, but when you lose Dybala, it all changes," Mourinho told Mediaset.
"Without Paulo, there is no connection between attack and defence, while the quality level drops.
"I am a little disappointed with a few individuals, as we ought to do more. We work so hard to get the ball to the flanks and then don’t put the crosses in."
Romelu Lukaku went close to an equaliser for Roma in the closing stages, but his overhead kick narrowly sailed over the bar.
Late in added time, tensions flared when Lazio's Pedro received a second yellow card following an altercation with Leandro Paredes and Roma's Sardar Azmoun was shown a red card for striking Nicolo Rovella.
Roma's Gianluca Mancini received a red card for dissent after the final whistle.
Lazio will meet Juventus or Frosinone, who meet on Thursday, in the semi-finals.