Skip to content

fix(fxconfig)!: enable TLS by default to prevent plaintext fallback vulnerability - #138

Closed
MayankSharmaCSE wants to merge 1 commit into
hyperledger:mainfrom
MayankSharmaCSE:fix/tls-secure-by-default
Closed

fix(fxconfig)!: enable TLS by default to prevent plaintext fallback vulnerability#138
MayankSharmaCSE wants to merge 1 commit into
hyperledger:mainfrom
MayankSharmaCSE:fix/tls-secure-by-default

Conversation

@MayankSharmaCSE

@MayankSharmaCSE MayankSharmaCSE commented Apr 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Enable TLS by default across all service configurations (orderer, queries, notifications). Previously TLS was disabled by default.

Breaking Change

TLS is now enabled by default.

If you upgrade to this version and don't have TLS configured, you may see:
rootCertPaths must not be empty

New users must either:

  • Configure TLS with rootCerts, or
  • Explicitly set tls.enabled: false

Existing users can add tls.enabled: false to restore previous behavior.

Changes

  • TLS now defaults to enabled: true instead of false
  • Normalize() sets Enabled=true when nil
  • TLS warning moved to config load time (single centralized warning instead of per-client)
  • Integration tests updated with explicit tls.enabled: false (testcontainers use --insecure flag)
  • Added assert.False message for Queries TLS assertion for consistency

Migration

Enable TLS (recommended for production):

tls:
  enabled: true
  rootCerts:
    - /path/to/ca.crt

Disable TLS (not recommended for production):
tls:
  enabled: false

Fixes #108
Test Plan

  • Unit tests pass
  • Integration tests pass

Copilot AI review requested due to automatic review settings April 16, 2026 16:50

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses a security issue in fxconfig where gRPC clients could silently downgrade to plaintext when TLS was disabled or not explicitly configured, enabling a man-in-the-middle risk.

Changes:

  • Flip TLSConfig.Enabled default from false to true so TLS is enabled unless explicitly disabled.
  • Emit a warning log when TLS is disabled to improve visibility of insecure configurations.
  • Update load tests to reflect the new secure default behavior.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
tools/fxconfig/internal/config/config.go Changes TLS enabled default to true via struct tag.
tools/fxconfig/internal/client/client.go Adds a warning log when TLS is disabled in createSecOpts.
tools/fxconfig/internal/config/load_test.go Updates test expectation so Notifications TLS is enabled by default.
Comments suppressed due to low confidence (1)

tools/fxconfig/internal/config/config.go:67

  • The new default default:"true" suggests TLS should be enabled when Enabled is unset, but TLSConfig.Normalize() still sets Enabled to false when nil and IsEnabled() still returns false when Enabled is nil. That means TLS can still silently fall back to plaintext if a TLSConfig is constructed without viper defaults (or if YAML explicitly sets enabled: null), which undermines the secure-by-default intent. Consider changing Normalize()/IsEnabled() to default to true when Enabled is nil (and update the related comments) so the behavior is consistent across all code paths.
	Enabled            *bool    `mapstructure:"enabled" yaml:"enabled,omitempty" desc:"Enable/disable TLS" default:"true"`
	ClientKeyPath      string   `mapstructure:"clientKey" yaml:"clientKey,omitempty" desc:"Path to TLS client private key"`
	ClientCertPath     string   `mapstructure:"clientCert" yaml:"clientCert,omitempty" desc:"Path to TLS client certificate"`
	RootCertPaths      []string `mapstructure:"rootCerts" yaml:"rootCerts,omitempty" desc:"Paths to TLS root certificates"`
	ServerNameOverride string   `mapstructure:"serverNameOverride" yaml:"serverNameOverride,omitempty" desc:"Override TLS server name"`

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


// let's see if we use TLS
if !tlsConfig.IsEnabled() {
logger.Warn("TLS is disabled — connections will be unencrypted and unauthenticated. This is insecure and not recommended for production environments.")

Copilot AI Apr 16, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This warning string appears to exceed the repository’s lll max line length (120) enforced by golangci-lint, which will likely fail CI. Consider splitting the message across concatenated string literals (or otherwise shortening it) so the line length stays within the configured limit.

Suggested change
logger.Warn("TLS is disabled — connections will be unencrypted and unauthenticated. This is insecure and not recommended for production environments.")
logger.Warn(
"TLS is disabled — connections will be unencrypted and unauthenticated. " +
"This is insecure and not recommended for production environments.",
)

Copilot uses AI. Check for mistakes.
Comment on lines +435 to +438
assert.True(t, cfg.Orderer.TLS.IsEnabled())
assert.Equal(t, []string{"/path/to/ca.pem"}, cfg.Orderer.TLS.RootCertPaths)
assert.False(t, cfg.Queries.TLS.IsEnabled())
assert.False(t, cfg.Notifications.TLS.IsEnabled())
assert.True(t, cfg.Notifications.TLS.IsEnabled())

Copilot AI Apr 16, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the new secure default, this test now expects Notifications TLS to be enabled even though the YAML in this test does not provide any root certs for Notifications (and no global tls.rootCerts). That configuration would fail TLSConfig.Validate() (rootCertPaths must not be empty when TLS is enabled), so the test is no longer representative of a valid config. Consider adding a top-level tls.rootCerts (or notifications-specific rootCerts) to keep the test focused on the enabled flag while still producing a valid configuration.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to update the tests now to disable TLS explicitly. Also update the documentation accordingly.

Comment on lines +435 to +438
assert.True(t, cfg.Orderer.TLS.IsEnabled())
assert.Equal(t, []string{"/path/to/ca.pem"}, cfg.Orderer.TLS.RootCertPaths)
assert.False(t, cfg.Queries.TLS.IsEnabled())
assert.False(t, cfg.Notifications.TLS.IsEnabled())
assert.True(t, cfg.Notifications.TLS.IsEnabled())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to update the tests now to disable TLS explicitly. Also update the documentation accordingly.

@mbrandenburger

Copy link
Copy Markdown
Contributor

hi @MayankSharmaCSE it seems that the unit tests are still failing.

@MayankSharmaCSE

Copy link
Copy Markdown
Contributor Author

@mbrandenburger, fixed the issue .

@mbrandenburger mbrandenburger left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @MayankSharmaCSE for working on this PR. We are making good progress here. I have a few more comments below.

Moreover, we should better indicate that this is a breaking change. Please make sure that the PR description highlights this. New users need to configure TLS correctly or disable it explicitly.

The commit message should therefore also contain fix(fxconfig)! per conventional commits.

Comment on lines +439 to +440
assert.False(t, cfg.Queries.TLS.IsEnabled())
assert.False(t, cfg.Notifications.TLS.IsEnabled())
assert.False(t, cfg.Notifications.TLS.IsEnabled(), "Notifications explicitly has enabled: false in config")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add a similar comment to assert.False(t, cfg.Queries.TLS.IsEnabled()) as well?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeh , I missed that during the refactor. i will add the assertion for cfg.Queries.TLS.IsEnabled() to ensure consistency across all three service configs in the test.

Comment on lines +43 to +44
logger.Warn("TLS is disabled — connections will be unencrypted and " +
"unauthenticated. This is insecure and not recommended for production.")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am wondering if this is the right place to throw the logging as this would lead to multiple warning for each client (orderer, queries, notifications). Without additional information which service has TLS disabled.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should handle the warning somewhere else ... during config loading?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point. Logging in each client would produce redundant warnings without context. I agree a single warning during config load would be cleaner. However, to keep this PR focused, I did prefer to address this as a follow-up item rather than scope creep this fix.

Comment on lines 144 to 150
### TLS Configuration

- **No TLS**: `enabled: false` or all TLS fields empty
- **No TLS**: `enabled: false`
- **Server TLS**: `enabled: true` with only `rootCerts` set (server authentication only)
- **Mutual TLS**: `enabled: true` with `clientKey`, `clientCert`, and `rootCerts` all set (mutual authentication)
- **Service-specific TLS**: Each service (orderer, queries, notifications) can override the parent `tls` section
- **SNI Override**: Use `serverNameOverride` for IP-based connections or custom hostname verification

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to document this better and explain that by default TLS is enabled and requires at least a rootCert otherwise the user will get an error. Or the user explicitly turns off TLS.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will add clear documentation explaining:

  • TLS is now enabled by default and requires TLS certificates.
  • Users can set tls.enabled: false to disable (not recommended for production).
  • The "rootCertPaths must not be empty" error indicates misconfiguration. This will be added to the README and/or inline comments in the config example file.

@MayankSharmaCSE

Copy link
Copy Markdown
Contributor Author

@mbrandenburger Thanks for the review you had! I have addressed all your comments:

  1. Breaking change — Updated commit prefix to fix(fxconfig)!: and added a prominent Breaking Change section in the PR description warning users that TLS is now enabled by default.
  2. Queries assertion — Added the missing assert.False message for cfg.Queries.TLS.IsEnabled() for consistency with Orderer and Notifications.
  3. Warning logging location — Moved the TLS warning to ResolveTLS() in config.go so it logs once at config load time instead of multiple times per client. Happy to address this as a follow-up if you'd prefer a different approach.
  4. Documentation — Added a Breaking Change notice in the README explaining the new default, the error users may see (rootCertPaths must not be empty), and how to migrate.

@mbrandenburger mbrandenburger left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @MayankSharmaCSE Great work! See my comments below.

Comment on lines 28 to 32
require.NoError(t, err)
require.NotNil(t, cfg)
assert.Equal(t, 30*time.Second, cfg.Orderer.ConnectionTimeout)
assert.Equal(t, 30*time.Second, cfg.Queries.ConnectionTimeout)
assert.Equal(t, 30*time.Second, cfg.Notifications.ConnectionTimeout)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add TLS enabled as assertions as it's our new default.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For instance:

assert.True(t, cfg.Orderer.TLS.IsEnabled())
// ... (and Queries/Notifications)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. I will add assert.True for when TLS is enabled by default (not explicitly disabled).

Comment on lines +48 to +53

// Warn once if any service has TLS disabled
if !c.Orderer.TLS.IsEnabled() || !c.Queries.TLS.IsEnabled() || !c.Notifications.TLS.IsEnabled() {
configLogger.Warn("TLS is disabled for one or more services — " +
"connections will be unencrypted. This is insecure and not recommended for production.")
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have the feeling we should not do the logging here as the "application" should decide if this particular configuration should log a warning or not. Thus, checking the config and print a log could happen in

cliCtx.Printer = cliio.NewCLIPrinter(cmd.OutOrStdout(), cmd.ErrOrStderr(), cliio.FormatTable)
WDYT?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, the config package shouldn't dictate logging. I will move the TLS warning from config.goto root.go so the application controls when/how to log. Does that sound right to you?

@mbrandenburger mbrandenburger changed the title fix(fxconfig): enable TLS by default to prevent plaintext fallback vulnerability fix(fxconfig)!: enable TLS by default to prevent plaintext fallback vulnerability Apr 29, 2026
@mbrandenburger

Copy link
Copy Markdown
Contributor

@pasquale95 Can you please have a look at this PR, which changes the "default TLS behavior" for fxconfig to always enabled - if not explicitly disabled.

@MayankSharmaCSE
MayankSharmaCSE force-pushed the fix/tls-secure-by-default branch 3 times, most recently from 82ad38c to f01ca25 Compare April 29, 2026 18:49
- Change tls.enabled default from false to true
- Normalize() sets Enabled=true when nil
- Add TestLoad_TLSEnabledByDefault to assert default behavior
- Move TLS warning to root.go (CLI layer)
- Update integration tests with explicit tls.enabled: false
- Improve assert messages for Queries TLS consistency
- Document breaking change in README

Signed-off-by: mayanksharmaCSE <mayanksharmacse1@gmail.com>
@mbrandenburger

Copy link
Copy Markdown
Contributor

This PR was re-opened in #214

@MayankSharmaCSE

Copy link
Copy Markdown
Contributor Author

@mbrandenburger,yes,I have followed up on the changes in #214 because i messed up my git history with some wrong commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

gRPC clients fall back to plaintext when TLS is disabled - no certificate validation

3 participants