Skip to content

OpenSSH private-key test vectors trigger secret-scanning alerts in downstream consumers #2376

Description

@p-dot-max

Summary

The OpenSSH test suites embed 36 well-formed private keys as inline PEM literals. Because they are syntactically valid keys shipped inside the published -sources.jar artifacts, automated secret scanners (GitGuardian, gitleaks, GitHub secret scanning, Trufflehog) flag them as leaked credentials in any organisation that ingests or vendors BouncyCastle sources.

These keys secure nothing — they are known-answer fixtures for encoder/decoder round-trips, intentionally public, and the passphrase for the encrypted variants (JcaTest!9) is a literal in the same file. The ask is narrow: make that intent machine-evident, so downstream teams can dismiss the finding in seconds instead of opening an incident.

Affected files

File Private-key PEM blocks
core/src/test/java/org/bouncycastle/crypto/test/OpenSSHKeyParsingTests.java 28
prov/src/test/java/org/bouncycastle/jce/provider/test/OpenSSHSpecTests.java 8

Covers ssh-rsa (PKCS#1 and openssh-key-v1), ssh-dss, ecdsa-sha2-nistp256 and ssh-ed25519, plus aes256-ctr/bcrypt encrypted variants.

Observed on 1.86-SNAPSHOT. The vectors are long-standing: the 1024-bit RSA key is present in tags r1rv61 and r1rv73, so it has shipped in published source artifacts since 1.61.

Impact

  • False-positive incident load. Each vendored copy or fork re-triggers the alert. Triage currently requires reading the test to infer that the key is a fixture.
  • No suppression path for consumers. Scanner allowlists are keyed on path or fingerprint; a consumer vendoring bcprov sources into a monorepo has neither a stable path nor upstream-provided fingerprints.
  • Personal identifiers in key comments. Two openssh-key-v1 vectors carry the originating workstation comment — mark@barnacles and meganwoods@tyche-3265.local (OpenSSHSpecTests.java). These are incidental to the test and needlessly associate named individuals with material that reads as a credential leak.

Non-goals

Spelled out because each is a plausible reflexive response that would cost real effort for no benefit:

  • Not a vulnerability report. No key here protects any system, so there is no exposure to assess and no advisory to publish. Please do not route this through the security process.
  • Not a request to rotate anything. Rotation presupposes a system the key guards. There is none.
  • Not a request to rewrite git history. The material is immutable in already-published Maven Central artifacts, so a filter-repo would break every clone and fork while retracting nothing.
  • Not a request to remove the vectors. They are load-bearing known-answer fixtures; deleting them would reduce coverage. Any change should preserve the assertions.

Proposed remediation

Ordered by cost. Any one materially reduces downstream triage; (1) and (2) are complementary.

  1. Declare intent in-file. Add a class-level Javadoc block to both test classes stating that the embedded keys are deliberately published, disposable test vectors that protect no system, with a stable marker string (e.g. NOT-A-SECRET: openssh test vector) that consumers can allowlist by content rather than path.

  2. Ship a scanner allowlist. Commit a .gitleaks.toml (and/or .github/secret_scanning.yml) covering the two paths, so contributors and forks inherit the suppression rather than each re-deriving it.

  3. Regenerate the two vectors carrying personal identifiers, substituting a neutral comment such as bc-test-vector. This is a mechanical, behaviour-preserving change: it requires recomputing the pinned expectations in OpenSSHSpecTests — the ED25519 base/tail hex either side of the random check-int, and the PKCS#8 encodings asserted for the encrypted keys.

Happy to raise a PR for any combination of the above if the maintainers indicate a preferred direction.

Reproduction

The underlying material is visible without any tooling:

$ git grep -c -E -- '-----BEGIN (RSA|DSA|EC|OPENSSH) PRIVATE KEY-----' -- \
    'core/src/test/java/org/bouncycastle/crypto/test/OpenSSHKeyParsingTests.java' \
    'prov/src/test/java/org/bouncycastle/jce/provider/test/OpenSSHSpecTests.java'
core/src/test/java/org/bouncycastle/crypto/test/OpenSSHKeyParsingTests.java:28
prov/src/test/java/org/bouncycastle/jce/provider/test/OpenSSHSpecTests.java:8

Each of these is a complete, parseable private key in PEM armour. Scanners that ship a generic private-key rule keyed on the -----BEGIN … PRIVATE KEY----- header — which is the default in gitleaks, Trufflehog and GitHub secret scanning — will match on them; the exact finding count and grouping varies by tool and by whether history is scanned.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions