DEV Community

Cover image for Preventing supply chain attacks: Yubikey 5, Code Signing & SSH-Keys, the 3rh main step to secure your development workflow
Priscila Gutierres
Priscila Gutierres

Posted on

Preventing supply chain attacks: Yubikey 5, Code Signing & SSH-Keys, the 3rh main step to secure your development workflow

Accordling to SNYK, on March 24, 2026, two versions of the LiteLLM Python package on PyPI were found containing malicious code. This attack used a three stages payload.
In the first stage, it collected among other things, system credentials as SSH private keys were stolen.
The credentials often don't expire, they are easily copied and they are an active target for malware. We are going to solve this problem storing the credentials out of a potential compromised machine.

Five aspects to improve commit traceability in FOSS projects:

1 DCO (Signed-off-by), creating a chain of custody for patches.
Each handler in the contribution pipeline adds their attestation via a Signed-off-by line,documenting everyone who touched the patch from author to final merge.
Main references:

2 ISSUE-COMMIT LINKING
It links commits to issues connects code changes to their motivation and requirements. Despite its importance, research shows this practice is frequently missing or broken in open source projects.
Main references:

3 GPG/SSH COMMIT SIGNING
Cryptographic signing provides authenticity and non-repudiation. Withoutit, Git identity is just free-form text that anyone can forge.

Main References:

4 PULL REQUESTS WITH CODE REVIEW
Pull requests create a public record of why a change was accepted, not just what changed. Code review in open source works through mechanisms of accountability, transparency, and shared ownership.

Main references:

5 MAILING LISTS AS PERMANENT DISCUSSION RECORDS (NOT JUST SLACK OR DISCORD)
Mailing lists serve as a persistently stored institutional memory,
preserving the rationale behind every change for future readers.
Even having the possibility to keep all the date, using Slack or Discord for this discussion makes hard for someone or an organization using your code to trace the origin of the need of your commits.

Main References:

This article focuses on storing, signing and protecting your credentials with a YubiKey 5 in your development workflow (the 3rh aspect).
Starting with the basics, we are going to setup a typical Fedora Workstation. For this, we need:

Fedora packages

sudo dnf install gnupg2 opensc pcsc-lite
Enter fullscreen mode Exit fullscreen mode

To make PGP work, you need to configure scdaemon inside ~/.gnupg/scdaemon.conf:

disable-ccid
Enter fullscreen mode Exit fullscreen mode
pcsc-shared
Enter fullscreen mode Exit fullscreen mode

Without those changes, GPG doesn't find the Yubikey and you may get errors like "No such device" or "Card error".

    gpg --batch --passphrase '' --yes --pinentry-mode loopback \
        --generate-key <<EOF
    %no-protection
    Key-Type: RSA
    Key-Length: 2048
    Subkey-Type: RSA
    Subkey-Length: 2048
    Name-Real: Your Name
    Name-Email: your.name@provider
    Expire-Date: 2y
    %commit
    EOF
Enter fullscreen mode Exit fullscreen mode

The above CLI creates a gpg key with "Your Name" and "your.name@provider" as your e-mail, within a 2 years expire date.

Moving it now to the Yubykey:

    gpg --edit-key <KEY_ID>
    gpg> keytocard          (chave principal -> slot 1: Signature)
    gpg> key 1
    gpg> keytocard          (subchave -> slot 2: Encryption)
    gpg> save
Enter fullscreen mode Exit fullscreen mode

Finally, export your pubkey to make people able to find it, and confirm your identity:

    gpg --armor --export HASH
Enter fullscreen mode Exit fullscreen mode

Following these steps, you are now able to use it to sign your commits and e-mails.

git

Now it is time to configure git to sign your commits and verify them when pushing to Github or Gitlab.


    git config --global user.signingkey **hash**
Enter fullscreen mode Exit fullscreen mode
    git config --global commit.gpgsign true
Enter fullscreen mode Exit fullscreen mode

Daily Usage

To use it in your daily workflow, it needs to be connected. GPG will ask for the OpenPGP PIN at the first use in the session.

In order to verify the signature,

    git log --show-signature -1
Enter fullscreen mode Exit fullscreen mode

To sign a tag:

    git tag -s v1.0 -m "Release 1.0"
Enter fullscreen mode Exit fullscreen mode

To export the SSH from GPG, export it using:


  gpg --export-ssh-key <KEY_ID>
Enter fullscreen mode Exit fullscreen mode

It creates the public and private key to use in the Github/Gitlab server.

Then, configure gpg-agent to be used as the SSH agent:

cat ~/.gnupg/gpg-agent.conf  << EOF
  enable-ssh-support
EOF
Enter fullscreen mode Exit fullscreen mode

Configure your shell to use the gpg-agent instead of ssh-agent. For zshell,

  cat ~/.zshrc << EOF
  export GPG_TTY=$(tty)
  export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
  gpgconf --launch gpg-agent
EOF
Enter fullscreen mode Exit fullscreen mode

Restart gpgconf:

  gpgconf --kill gpg-agent
Enter fullscreen mode Exit fullscreen mode
  gpgconf --launch gpg-agent
Enter fullscreen mode Exit fullscreen mode

Verify if ssh is seeing the key:

  ssh-add -L
Enter fullscreen mode Exit fullscreen mode

Known GPG bugs and workarounds

"No such device" / "Card error":

    gpgconf --kill scdaemon
Enter fullscreen mode Exit fullscreen mode
    gpgconf --kill gpg-agent
Enter fullscreen mode Exit fullscreen mode

Verify ~/.gnupg/scdaemon.conf, then disable-ccid, and pcsc-shared
Also, verify if pcscd is running:

systemctl status pcscd
Enter fullscreen mode Exit fullscreen mode

Bad PIN:
Try to clean the cache

 gpgconf --kill gpg-agent
Enter fullscreen mode Exit fullscreen mode

Verify the number of remaining tries:

 ykman openpgp info

Enter fullscreen mode Exit fullscreen mode

"Segfault": --pinentry-mode loopback may cause a segfault with GPG 2.4.9, with card-edit generate. You need to create the key inside the computer and then move it to the yubikey.

Bonus: Configuring Thunderbird (flatpak)

Close it, and edit prefs.js (~/.var/app/org.mozilla.thunderbird/.thunderbird/n5yyk2sx.default-release/)

Add to prefs.js:

    user_pref("mail.openpgp.allow_external_gnupg", true);
    user_pref("mail.identity.id1.is_gnupg_key_id", true);
    user_pref("mail.identity.id1.last_entered_external_gnupg_key_id", "HASH");
    user_pref("mail.identity.id1.openpgp_key_id", "HASH");
Enter fullscreen mode Exit fullscreen mode

Or using Thunderbird itself:

  1. Enable the external GnuPG keys:
    Settings > Config Editor > Find:
    mail.openpgp.allow_external_gnupg > change to true

  2. Account Settings > End-To-End Encryption > Add Key
    Select "Use your external key through GnuPG"
    Paste the Key ID: HASH

  3. If it asks for a public key:
    Click "Select File to Import..."
    Go to ~/.ssh/gpg_public_key.asc

  4. Mark "Sign unencrypted messages" to sign by default.

I do recomend using ykman insted of the gpg directly. Yakman directly access the yubikey without passing through pinetry, wich is used by gpg. This can help to avoid some kinds of problems like having pinetry frozen when typing a PIN.


KEEP YOUR PIV PIN, PIV PUK, ADMIN-PIN, GPG PIN SAFE.
Don't use the default pin/puk/admin-pin/gpg-pin, change them using ykman:
ykman piv access change-pin
Enter fullscreen mode Exit fullscreen mode
ykman piv access change-puck
Enter fullscreen mode Exit fullscreen mode
ykman opnepgp access change-admin-pin
Enter fullscreen mode Exit fullscreen mode
ykman openpgp access change-adm-pin
Enter fullscreen mode Exit fullscreen mode

Now we have everything configured. But the last and most important step is verifying the key. states that, "For non-UI commits, verification failures are dominated by unknown_key (73.73% of failures), meaning the signing key used for the commit is not registered with any GitHub account." (Analysis of Commit Signing on GitHub arXiv, 2026). So it is important to export your key and/or make sure that the users have access to a secure way to verify that, the commit comes from a trusted source.
Doing that, we have secure one of the 5 main steps to prevent a supply chain attack.

Top comments (0)