# Gem signature forgery

Duplicate tar entries in a .gem file let signature verification read the last data.tar.gz while installation extracts the first, allowing forged contents under a valid signature.

- Payout: $1,000
- Severity: medium
- Program: RubyGems
- Credited: b9629eebd06fb8f0680ecbdef829e
- Disclosed: 2018-08-03
- Write-up quality: 9/10
- Original: https://hackerone.com/reports/275269
- Library page: https://bugbountylibrary.com/r/h1%3A275269
- Tags: domain:oss impact:integrity kind:bounty platform:hackerone sev:medium tech:ruby technique:parser-differential technique:source-review vuln:crypto vuln:misconfiguration vuln:signature-replay

**Target:** gem package tar container / signature verification
**Root cause:** gem's verify_files iterates all tar entries and last-wins for @signatures/@digests, while extract_files and read_checksums take the first matching entry, so verification and extraction operate on different data.tar.gz/checksums.yaml.gz entries.
**Steps:**
1. `gem fetch multi_json` and move original gem to another dir
2. `echo hacked > HACKED; tar czf data.tar.gz HACKED`
3. `./forge-gem.sh orig/multi_json-1.12.2.gem data.tar.gz forged.gem` prepends a new data.tar.gz before the genuine one
4. `gem cert --add rwz.pem` to trust the original signer
5. `gem install --install-dir install -P HighSecurity forged.gem`
6. Observe install/gems/multi_json-1.12.2/ contains only HACKED
**How found:** Noticed gem's tar handling had multiple code paths (extract_files, read_checksums, verify_files) and hypothesized they might disagree on duplicate entry names; confirmed by reading source that extract uses first while verify last-wins, then built a PoC gem.
**Exploitation:** Attacker takes any legitimately signed gem, prepends a malicious data.tar.gz (and optionally checksums.yaml.gz) entry, and distributes it. Verification validates the trailing genuine entry's signature; extraction installs the leading malicious entry. Works under MediumSecurity/HighSecurity profiles.
**Escalation:** Weaker variant: mix data.tar.gz from an old vulnerable signed gem with metadata.gz from a newer signed release, since the two are signed independently and not bound together.
**Insight:** When a format allows duplicate keys/entries, audit every consumer of that format for first-vs-last-wins disagreement between the security check and the actual data consumer; tar, zip, and archive parsers are prime targets.
