This is a rusty badge on the front door, not a burglar already in the lobby
Tenable plugin 35291 fires when a remote TLS service presents any certificate in its chain signed with a weak hash algorithm such as MD2, MD4, MD5, or SHA-1; per Tenable, it also flags SHA-1 chains that expire after 2017-01-01. This is not a software-version bug with a neat affected range; the "affected versions" are effectively *any host or appliance still using an old certificate chain*, including self-signed internal certs, stale private-PKI leaf certs, and legacy appliance cert bundles.
The vendor's MEDIUM is technically defensible in a vacuum because weak-hash certificate signatures have real cryptographic history behind them. In enterprise reality, though, this finding is usually *over-prioritized*: exploitation generally needs an on-path position or some other traffic-redirection foothold, modern public-web clients have spent years distrusting SHA-1, and the blast radius is bounded to the specific trust path using the bad cert. For most fleets, this belongs in cleanup/backlog hygiene, not emergency patching.
4 steps from start to impact.
Get on-path or control name resolution
- Attacker can observe or reroute victim traffic
- Victim actually connects to the affected TLS service
- Requires a prior foothold or network-adjacent position
- Modern enterprise segmentation, DNS controls, NAC, and VPN design reduce reachable opportunities
- Many affected services are internal-only and not broadly reachable by arbitrary attackers
Forge or substitute a believable certificate
- Weak-hash certificate chain is still trusted by the client population
- Attacker can craft or obtain a substitute cert that passes validation in that environment
- Public CAs and major browsers have deprecated/rejected SHA-1 for years
- Collision attacks are specialized, not commodity initial-access tooling
- Known public roots are often excluded by related scanner logic and many modern clients reject them anyway
Exploit client acceptance of the weak chain
- Target client stack still accepts the chain
- No pinning, mutual TLS, or strict trust policy blocks the substitute cert
- Modern browsers and many OS trust stores reject or warn on SHA-1
- Pinned certs, mTLS, and managed trust stores kill the path
- User-facing warnings or app failures often surface the attempt
Intercept or alter protected traffic
- Successful TLS impersonation against a real client population
- Valuable data or privileged actions traverse that connection
- Impact is limited to the trust path behind the certificate
- No code execution or direct host compromise is created by this finding alone
- Many internal services carry low-value or machine-to-machine traffic only
MD2/MD4/MD5/SHA-1, then separate public-facing endpoints from internal-only and admin-plane services. For a LOW verdict there is no mitigation SLA; treat this as backlog hygiene, but complete the inventory during the next certificate hygiene cycle so you know which few hits actually matter.LOW has no formal mitigation deadline, these are the exceptions worth fixing early because the trust blast radius is higher.LOW, do this as routine PKI maintenance rather than emergency work, but close the template gap before your next renewal wave or you'll keep regenerating the problem.EDR alonedoesn't solve it, because the core issue is trust in a weak certificate chain during TLS establishment, not malware execution on the endpoint.Patching TLS protocol versions onlydoesn't solve it, because you can run modern TLS and still present a weakly signed certificate.Closing the scanner finding by exceptionwithout fixing PKI issuance doesn't help, because the same weak-signature templates will keep reproducing the exposure on renewal or rebuild.
The supporting signals.
| In-the-wild status | No evidence that *this scanner condition* is being broadly exploited as a current enterprise campaign. The underlying cryptographic weaknesses are real, but the operational exploit path is usually on-path MITM plus legacy client trust. |
|---|---|
| KEV status | Not CISA KEV-listed as a finding class; the loose CVE mappings Tenable shows (CVE-2004-2761, CVE-2005-4900) are not meaningful KEV drivers for patch priority here. |
| Proof-of-concept availability | Yes, in research form: MD5 chosen-prefix collision work and the rogue CA demonstration; SHA-1 collision research was made practical by Google/CWI (SHAttered). This is not the same as commodity exploit tooling for arbitrary enterprise services. |
| EPSS | Not a useful signal here. Plugin 35291 is a generic configuration finding spanning weak certificate signatures, not a single product CVE with stable exploit-likelihood modeling. |
| Vendor severity / score | Tenable marks it MEDIUM, with CVSS v3 5.3 and vector CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N, inherited from legacy weak-hash CVE mappings rather than a host-takeover scenario. |
| Affected range | Any service presenting a certificate chain signed with MD2, MD4, MD5, or SHA-1; Tenable explicitly flags SHA-1 chains that expire after 2017-01-01. |
| Fixed version | There is no patched software build to cite. The effective fix is to reissue and deploy certificates and intermediates using SHA-256 or stronger, and retire any legacy private-PKI or appliance cert templates still producing weak signatures. |
| Scanning / exposure reality | Internet-facing prevalence has been pushed down for years by browser and CA deprecation of SHA-1, so most current hits are more likely to be internal services, appliances, or private PKI debris than mass-exploitable public web assets. |
| Disclosure / lineage | Tenable published plugin 35291 on 2009-01-05 and last updated it on 2025-04-10. The underlying cryptographic issues trace back to MD5 collision concerns and later practical SHA-1 collision research. |
| Research lineage | MD5 certificate collision work was demonstrated by researchers including Marc Stevens and collaborators; practical SHA-1 collision work was published by Google/CWI in 2017. |
Sources.
- Tenable Nessus Plugin 35291
- Tenable Plugin 35291 Changelog
- Mozilla Security Blog: Phasing Out Certificates with SHA-1 based Signature Algorithms
- Chromium Blog: Gradually Sunsetting SHA-1
- Google Security Blog: Announcing the first SHA1 collision
- Microsoft Security Advisory 961509
- NIST SP 800-107 Rev. 1
- MITRE CWE-328: Use of Weak Hash
Why this verdict
- Requires on-path control: the attacker normally needs DNS/network interception or some equivalent foothold before the weak cert helps them at all, which is a major downward adjustment from the vendor baseline.
- Client trust population is narrow: modern browsers and mainstream public-web clients have distrusted or degraded
SHA-1for years, so the reachable victim set is much smaller than the raw plugin count suggests. - No host compromise primitive: this finding does not give RCE, privilege escalation, or direct service takeover by itself; impact is confined to impersonation of the specific TLS endpoint if multiple prerequisites are already met.
Why not higher?
A higher rating would fit an unauthenticated remote bug that yields code execution or trivial credential theft across a broad exposed population. This one needs a multi-step chain: on-path position, acceptable forged/substitute certificate, and clients that still trust the weak signature path. That is too much real-world friction for MEDIUM or HIGH in most fleets.
Why not lower?
It is not pure noise. Weakly signed certs still matter on internal admin planes, legacy middleware, appliances, and private PKI where browser-era protections do not save you. If the affected cert protects privileged traffic or high-value service identities, the local business impact of a successful MITM is real even if the exploit path is narrow.
Crowdsourced verification payload.
Run this from an auditor workstation or jump host that can reach the target TLS service; it does not need to run on the target itself. Invoke it as ./check_weak_cert_sig.sh host:port for example ./check_weak_cert_sig.sh mail.example.com:443. No special privileges are required beyond network reachability and openssl installed locally.
#!/usr/bin/env bash
# check_weak_cert_sig.sh
# Exit codes:
# 0 = PATCHED
# 1 = VULNERABLE
# 2 = UNKNOWN / usage / connection error
set -u
TARGET="${1:-}"
if [[ -z "$TARGET" ]]; then
echo "UNKNOWN - usage: $0 host:port"
exit 2
fi
if ! command -v openssl >/dev/null 2>&1; then
echo "UNKNOWN - openssl not found"
exit 2
fi
HOST="${TARGET%:*}"
PORT="${TARGET##*:}"
if [[ -z "$HOST" || -z "$PORT" || "$HOST" == "$PORT" ]]; then
echo "UNKNOWN - target must be in host:port format"
exit 2
fi
TMPDIR="$(mktemp -d 2>/dev/null || mktemp -d -t weakcert)"
trap 'rm -rf "$TMPDIR"' EXIT
CHAIN_FILE="$TMPDIR/chain.pem"
CERT_FILE="$TMPDIR/cert.pem"
# Pull the presented certificate chain.
if ! timeout 15 openssl s_client -connect "$HOST:$PORT" -servername "$HOST" -showcerts < /dev/null > "$CHAIN_FILE" 2>/dev/null; then
echo "UNKNOWN - failed to connect or TLS handshake failed"
exit 2
fi
awk 'BEGIN{c=0} /BEGIN CERTIFICATE/{c++; fn=sprintf("%s/cert-%02d.pem", ENVIRON["TMPDIR_OUT"], c)} c>0{print > fn} /END CERTIFICATE/{close(fn)}' TMPDIR_OUT="$TMPDIR" "$CHAIN_FILE"
shopt -s nullglob
CERTS=("$TMPDIR"/cert-*.pem)
if [[ ${#CERTS[@]} -eq 0 ]]; then
echo "UNKNOWN - no certificates parsed from server response"
exit 2
fi
WEAK_FOUND=0
DETAILS=()
INDEX=0
for CERT in "${CERTS[@]}"; do
INDEX=$((INDEX+1))
SIGALG="$(openssl x509 -in "$CERT" -noout -text 2>/dev/null | awk -F': ' '/Signature Algorithm/ {print $2; exit}')"
SUBJECT="$(openssl x509 -in "$CERT" -noout -subject 2>/dev/null | sed 's/^subject=//')"
if [[ -z "$SIGALG" ]]; then
DETAILS+=("cert${INDEX}:unknown-signature:${SUBJECT:-unknown-subject}")
continue
fi
SIGLOW="$(echo "$SIGALG" | tr '[:upper:]' '[:lower:]')"
if [[ "$SIGLOW" =~ md2|md4|md5|sha1 ]]; then
WEAK_FOUND=1
DETAILS+=("cert${INDEX}:$SIGALG:${SUBJECT:-unknown-subject}")
else
DETAILS+=("cert${INDEX}:$SIGALG:${SUBJECT:-unknown-subject}")
fi
done
if [[ $WEAK_FOUND -eq 1 ]]; then
echo "VULNERABLE - weak certificate signature algorithm detected"
printf '%s
' "${DETAILS[@]}"
exit 1
fi
echo "PATCHED - no weak certificate signature algorithms detected in presented chain"
printf '%s
' "${DETAILS[@]}"
exit 0