docker/cli · warning
warning: potential malicious behavior - trust data has…
Error message
warning: potential malicious behavior - trust data has insufficient signatures for remote repository %s: %v
What it means
Returned by NotaryError for signed.ErrRoleThreshold (trust.go:251-252). TUF roles declare a threshold of signatures required to consider metadata valid; the downloaded role metadata did not meet its threshold count of valid signatures. Because insufficient signatures can indicate a compromised or tampered role, the client reports it as 'potential malicious behavior'.
Solutions
- Have the repository admin add the missing signature(s): each configured signer for the role must publish (AddTarget/Publish) so the role again carries threshold-valid signatures.
- If a signer key was legitimately removed, lower the role threshold to match the remaining keys via 'docker trust signer remove' followed by a publish, or add a replacement signer key.
- Confirm no unauthorized party modified the role metadata by reviewing the notary server's published targets.json and the list of valid signing key IDs.
- Re-pull after the admin re-publishes; if the warning persists, verify the local trust pinning config (trust-pinning.json) has not pinned an outdated root.
Defensive patterns
Strategy: validation
Validate before calling
// Verify the served role metadata meets its declared signature threshold before consuming.
func verifyRoleThreshold(repo client.Repository, roleName data.RoleName) error {
roles, err := repo.ListRoles()
if err != nil {
return err
}
for _, r := range roles {
if r.Name == roleName && len(r.Signatures) < r.Threshold {
return fmt.Errorf("role %s below threshold (%d/%d)", roleName, len(r.Signatures), r.Threshold)
}
}
return nil
} Type guard
func isErrRoleThreshold(err error) bool {
if err == nil {
return false
}
return errors.Is(err, signed.ErrRoleThreshold)
} Try / catch
if err := repo.Publish(); err != nil {
if errors.Is(err, signed.ErrRoleThreshold) {
return fmt.Errorf("insufficient signatures on published metadata: %w; have all required signers publish", err)
}
return trust.NotaryError(gun, err)
} Prevention
- When removing a signer, simultaneously lower the role threshold or add a replacement before publishing.
- Document each delegation role's key set and threshold so signers know who must publish.
- Audit notary role metadata periodically to confirm signature counts meet thresholds.
- Coordinate key rotations so metadata is re-signed by all required keys in the same publish cycle.
When it happens
Trigger: Listing/pulling/verifying a repository whose targets/releases/delegation role requires N signatures but the served metadata only carries fewer valid ones - e.g. a delegation role had 2 keys with threshold 2 but one key was removed or one signature is invalid. Also triggered when a signer's key was rotated but the old signatures were not re-signed, dropping below threshold.
Common situations: Repository admin removed a signer key without lowering the role threshold, so remaining signatures are below the required count; a delegation role threshold was raised but not enough signers published; a compromised notary server stripped a signature; key rotation left metadata signed only by the new key while threshold still expects the old one.
Related errors
- warning: potential malicious behavior - trust data version…
- private key file must not be readable or writable by others
- error: could not find signing keys for remote repository
- error: remote trust data does not exist for
- error: could not produce valid signature for
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/9d629c642ed53d49.
Report an issue: GitHub.
Appendix: source
Thrown at cmd/docker-trust/internal/trust/trust.go:252
case *json.SyntaxError:
logrus.Debugf("Notary syntax error: %s", err)
return fmt.Errorf("error: no trust data available for remote repository %s. Try running notary server and setting DOCKER_CONTENT_TRUST_SERVER to its HTTPS address", repoName)
case signed.ErrExpired:
return fmt.Errorf("error: remote repository %s out-of-date: %v", repoName, err)
case trustmanager.ErrKeyNotFound:
return fmt.Errorf("error: signing keys for remote repository %s not found: %v", repoName, err)
case storage.NetworkError:
return fmt.Errorf("error: error contacting notary server: %v", err)
case storage.ErrMetaNotFound:
return fmt.Errorf("error: trust data missing for remote repository %s or remote repository not found: %v", repoName, err)
case trustpinning.ErrRootRotationFail, trustpinning.ErrValidationFail, signed.ErrInvalidKeyType:
return fmt.Errorf("warning: potential malicious behavior - trust data mismatch for remote repository %s: %v", repoName, err)
case signed.ErrNoKeys:
return fmt.Errorf("error: could not find signing keys for remote repository %s, or could not decrypt signing key: %v", repoName, err)
case signed.ErrLowVersion:
return fmt.Errorf("warning: potential malicious behavior - trust data version is lower than expected for remote repository %s: %v", repoName, err)
case signed.ErrRoleThreshold:
return fmt.Errorf("warning: potential malicious behavior - trust data has insufficient signatures for remote repository %s: %v", repoName, err)
case client.ErrRepositoryNotExist:
return fmt.Errorf("error: remote trust data does not exist for %s: %v", repoName, err)
case signed.ErrInsufficientSignatures:
return fmt.Errorf("error: could not produce valid signature for %s. If Yubikey was used, was touch input provided?: %v", repoName, err)
default:
return err
}
}
// AddToAllSignableRoles attempts to add the image target to all the top level
// delegation roles we can (based on whether we have the signing key and whether
// the role's path allows us to).
//
// If there are no delegation roles, we add to the targets role.
func AddToAllSignableRoles(repo client.Repository, target *client.Target) error {
signableRoles, err := GetSignableRoles(repo, target)
if err != nil {
return errView on GitHub (pinned to 4f84911bfe)