Code signing is one of the oldest trust mechanisms in software distribution, and it remains one of the most misunderstood. At its core, code signing provides two guarantees: the identity of the publisher (authentication) and the integrity of the code since it was signed (tamper detection). Both are essential for supply chain security, and both are regularly undermined by poor implementation.
How Code Signing Works
The mechanics are straightforward public-key cryptography. A software publisher obtains a code signing certificate from a Certificate Authority (CA). The certificate binds the publisher's identity to a public key. The publisher uses the corresponding private key to create a digital signature over the software artifact. Consumers verify the signature using the public key in the certificate.
The verification chain works like this:
- The operating system or runtime environment has a set of trusted root CAs built in
- The code signing certificate chains up to one of these trusted roots
- The signature on the software artifact is verified against the certificate's public key
- If the chain is valid and the signature matches, the software is considered trusted
This model works well when every participant follows best practices. In reality, the failure modes are numerous and interesting.
Where Code Signing Fails
Certificate Theft
The most direct attack is stealing the signing key. If an attacker obtains the private key associated with a code signing certificate, they can sign malicious software that appears legitimate.
This has happened repeatedly in practice. The Stuxnet malware used stolen code signing certificates from Realtek and JMicron. The ShadowPad backdoor in the NetSarang suite was signed with the vendor's legitimate certificate because the build process was compromised. The ASUS Live Update compromise in 2019 used ASUS's own signing infrastructure.
The root cause is almost always poor key management. Keys stored on developer workstations, in CI/CD environments without hardware security modules (HSMs), or in cloud storage without adequate access controls.
Compromised Build Pipelines
Even if the signing key is well-protected, compromising the build pipeline achieves the same result. If an attacker can inject malicious code before the signing step, the malicious artifact gets signed with the legitimate key. SolarWinds SUNBURST is the canonical example -- the malicious code was injected during the build process and then signed with SolarWinds' legitimate certificate.
This is why signing alone is insufficient. You also need build process integrity controls, reproducible builds, and provenance attestation.
Certificate Authority Compromise
If a CA is compromised, the attacker can issue fraudulent certificates for any identity. The DigiNotar breach in 2011 resulted in fraudulent certificates for Google, Mozilla, and other major domains. While this primarily affected TLS certificates, the same risk applies to code signing CAs.
Timestamp Server Issues
Code signatures include timestamps that establish when the signature was created. This matters because certificates expire. A timestamped signature remains valid after the certificate expires, as long as the certificate was valid at the time of signing.
If a timestamp server is compromised or produces inaccurate timestamps, the temporal validity of signatures is undermined. Additionally, if a signing key is compromised and the attacker has access to a timestamp server, they can create signatures that appear to have been created before the compromise was discovered.
Best Practices for Code Signing
Key Management
Use hardware security modules (HSMs). The signing key should never exist on a general-purpose computer. HSMs (hardware or cloud-based like AWS CloudHSM or Azure Managed HSM) ensure the key cannot be exported and that all signing operations are performed in a secure enclave.
Implement access controls. Signing should require multiple approvals (quorum-based signing) and should be restricted to specific CI/CD pipelines, not individual developers.
Rotate certificates regularly. Do not wait for expiration. Rotate annually at minimum and immediately if there is any suspicion of compromise.
Separate signing environments. The signing infrastructure should be isolated from development and build environments. If the build environment is compromised, the attacker should not automatically have access to the signing capability.
Build Pipeline Integration
Sign in a dedicated step. Do not sign as part of the build process. Build the artifact, verify it, and then sign it in a separate, controlled environment.
Record provenance. Use frameworks like SLSA to create provenance attestations that document how the artifact was built, what inputs were used, and what environment it was built in. The signature on the artifact confirms integrity; the provenance attestation confirms origin.
Implement reproducible builds. If your build is reproducible, anyone can rebuild from source and verify that the result matches the signed artifact. This provides a verification mechanism independent of the signing key.
Certificate Lifecycle
Monitor certificate transparency logs. Certificate Transparency (CT) logs record all issued certificates. Monitor these logs for certificates issued to your organization that you did not request -- this can indicate CA compromise or unauthorized issuance.
Maintain a certificate inventory. Know every code signing certificate your organization has, who has access to the corresponding key, and when it expires. Organizations frequently discover forgotten certificates during incident response.
Plan for revocation. Have a process documented and tested for revoking a compromised certificate. Know how to contact your CA, how to publish revocation information, and how to communicate the revocation to your users.
Sigstore: The New Approach
Sigstore is an open-source project that rethinks code signing for the modern software supply chain. Instead of long-lived certificates from traditional CAs, Sigstore uses short-lived certificates tied to identity providers (GitHub, Google, Microsoft).
The workflow:
- Developer authenticates with an identity provider (e.g., GitHub OAuth)
- Sigstore's Fulcio CA issues a short-lived certificate (valid for minutes) bound to the authenticated identity
- The artifact is signed with the ephemeral key
- The signature is recorded in Sigstore's Rekor transparency log
- The key pair is discarded
This model eliminates the key management problem entirely. There is no long-lived key to steal, no HSM to maintain, and no certificate to rotate. The trust is anchored in the identity provider and the transparency log.
npm, PyPI, and several Linux distributions have adopted Sigstore for package signing. It is rapidly becoming the standard approach for open-source software signing.
Code Signing in the Enterprise
Enterprise code signing typically involves a mix of approaches:
- Operating system level: Windows Authenticode, macOS code signing, Android APK signing. Required for software distribution through OS-managed channels.
- Container signing: cosign (part of Sigstore) for container image signing, Notary for Docker Content Trust.
- Package signing: npm provenance, PyPI Trusted Publishers, Maven PGP signatures.
- Internal signing: Signing internal builds and artifacts to prevent unauthorized code from running in production.
The challenge is managing all of these consistently. Many organizations have different teams handling different signing mechanisms with no unified policy or key management.
How Safeguard.sh Helps
Safeguard.sh verifies code signing and provenance information as part of its SBOM analysis. When you upload an SBOM or scan an artifact, Safeguard.sh checks for valid signatures, verifies provenance attestations against Sigstore transparency logs, and flags components that lack signing or have signature anomalies.
This gives your security team visibility into the signing posture of your entire software supply chain from a single dashboard. Policy gates can enforce signing requirements -- for example, blocking builds that include unsigned dependencies or dependencies with expired certificates -- ensuring that code signing is not just a best practice but an enforced standard.