The Blue Devils (4-2, 1-2 ACC) managed just 255 yards of offense as quarterback Daniel Jones completed 14 of 42 passes and was picked off twice.
The Cavaliers' defense held late, sacking Jones for a 10-yard loss after Duke reached the Virginia 30. Jones threw incomplete on fourth-and-16 with 1:08 left, and Virginia ran out the clock as the Blue Devils were out of timeouts.
Virginia (4-1, 1-0) went ahead 28-14 midway through the fourth quarter as quarterback Kurt Benkert connected with wide receiver Doni Dowling on a 17-yard touchdown. Dowling recorded two touchdowns as Benkert overcame a slow start to finish 24 of 43 for 182 yards and three touchdowns.
Duke pulled within 28-21 with on a 4-yard run by Quentin Harris with 6:14 to go.
Virginia tallied 310 yards of offense and held the ball for more than 35 minutes. Running back Jordan Ellis ran for a career-high 96 yards on 25 carries.
After the teams combined for 83 yards and four interceptions in the first quarter -- with each team scoring off an interception return -- they settled in and found a groove on offense in the second quarter.
Jones, who started the game by completing only one of his first 13 attempts, found Davis Koppenhaver on a 7-yard touchdown pass to give the Blue Devils a 14-7 lead midway through the second quarter.
Virginia managed only 86 yards in the first half but answered Duke's touchdown with a score of its own as Benkert connected with Olamide Zaccheaus for an 11-yard touchdown to tie the game 14 heading into halftime.