Anthony Boone was 22 of 37 for 176 yards with a 1-yard touchdown pass to Eric Schneider.
The Blue Devils (6-1, 2-1 Atlantic Coast Conference) reached bowl eligibility for the third straight year and took the early edge in the Coastal Division race.
Shaquille Powell carried four times for 32 yards on the decisive drive and Boone took a zone-read keeper 23 yards to the Virginia 7.
Sirk — who regularly replaces Boone in short-yardage situations — then faked a quarterback draw and hit a wide-open Reeves with a jump pass in the end zone.
Johns and the Cavaliers had two chances after that to tie it up. On Virginia's next drive, Johns hit Gooch for 19 yards on a second-and-14, bringing the ball to the Duke 38. But he wasn't close with his deep throw to Canaan Severin on a fourth-and-12 pass three plays later with 2:14 left.
Virginia forced a punt and took over at its own 15 with 23 seconds left. Johns hit Jennings in stride for a 26-yard gain and Johns spiked the ball with 8 seconds left. Johns then hit Doni Dowling across the middle but Jeremy Cash brought him down after the clock expired.
That gave the Blue Devils their sixth win in seven meetings with Virginia since David Cutcliffe took over in 2008.
Duke twice drove inside the Virginia 10 but had to settle for short field goals from Ross Martin, who converted from 19 and 25 yards.
Virginia's Ian Frye tied it twice with field goals, from 21 and 30 yards. The second of those made it 13-all with 7:11 left in the third.
Boone — who threw four touchdowns against Virginia two years ago, then added two more in a come-from-way-behind win in 2013 — helped Duke take a 10-0 lead, capping the opening drive with his short touchdown pass to Schneider. Martin added a 19-yard field goal early in the second quarter.
Johns and the Cavaliers responded by going 75 yards in nine plays, capped with his short scoring pass to Shepherd with 9:11 before halftime. They made it 10-all at the half on Frye's 21-yard kick on the final play.