May 28, 2019·6 min read·engineeringistiosecurityauthorizationtcp

Istio's TCP policy flaw skipped the configured authorization check

CVE-2019-12243 affects Mixer-based authorization for TCP services in Istio 1.1 through 1.1.6. A direction error in generated proxy configuration prevented checks even when the operator had enabled policy enforcement.

A deny policy is ineffective if the request never reaches the component that evaluates it. The May 28 Istio security advisory describes precisely that failure for some TCP traffic. Istio 1.1 through 1.1.6 could omit Mixer policy checks even when the operator enabled them. Deny Checker and List Checker were stable capabilities affected by the bug, which the project now tracks as CVE-2019-12243.

The problem is not that an authorization rule contains the wrong condition. The original report in issue 13868 says inbound TCP connections do not generate Check requests to istio-policy when disablePolicyChecks is false. External authorization is consequently not applied. A configured Denier can cover the service while a connection from another pod is still accepted.

I regard workload identity as a useful foundation for mesh security, but enforcement requires a complete path from the connection to its policy decision. This bug interrupts that path after the administrator has explicitly chosen to enable it. The relevant evidence is whether the generated proxy behavior invokes the intended check, rather than whether the deny rule exists in the configuration store.

A direction argument changed the generated behavior

The report identifies a change introduced in Istio 1.1 in Pilot's Mixer networking plugin. Its buildInboundTCPFilter function used the outbound direction when computing whether check calls should be disabled. The reporter says the argument should be inbound. That is a small implementation difference with a large effect on the policy applied to incoming connections.

The problematic expression described by the issue is short enough to show directly. This is the reported pre-fix expression in the filter construction, not a configuration recommendation.

DisableCheckCalls: disablePolicyChecks(outbound, mesh, node)

The field records whether the generated filter should make policy check calls. Passing the wrong traffic direction causes the filter's behavior to diverge from the intended inbound enforcement configuration. The function name surrounding the expression and the argument disagree about which traffic is being configured. Pilot can therefore generate a filter that omits checks despite the mesh setting used by the administrator.

This is a useful example of control-plane configuration having data-plane security consequences. The reported defect is in Pilot, while the observable failure is the absence of Check requests for incoming TCP connections. An operator looking only at the policy adapter's rules would be examining a component that the connection never consulted.

The issue's reproduction explicitly enables checks, creates a TCP service and configures a Denier covering it. Its accepted connection establishes the discrepancy between declared enforcement and observed behavior. The report also says the bug is not tied to a particular installation environment. Its identified cause is the direction used while constructing proxy configuration.

The advisory defines a specific affected configuration

The security advisory lists four conditions that must all hold for this vulnerability to apply. The installation must use an affected 1.1 release, policy checks must be enabled, the workload must use a protocol outside HTTP, HTTP/2 and gRPC, and a Mixer adapter must supply authorization for the TCP backend. Deny Checker and List Checker are examples of those adapters.

These conditions prevent a broad claim that every Istio authorization mechanism is broken. The flaw concerns Mixer-backed checks for the described TCP case. The advisory explicitly excludes Istio 1.0.x and identifies HTTP-family protocols outside the affected workload condition. Security analysis needs to retain those qualifications, because the same product can enforce different traffic through different mechanisms.

The default profile in 1.1 disables policy enforcement. The advisory says an installation with disablePolicyChecks: true is not impacted by this vulnerability. That statement does not mean the installation is performing the checks successfully. It means the operator has not enabled the enforcement path whose failure the CVE describes.

This distinction matters when comparing two installations. One can be outside the vulnerability's conditions because it never requested these checks, while another is affected because it relies on them. Their security expectations differ. Treating the default as proof of working TCP authorization would reverse the meaning of the advisory's test.

Inspecting the mesh setting answers only part of the question

The advisory reads the mesh configuration from the istio ConfigMap to determine the policy-check setting. With an explicit context, the corresponding inspection looks like this. The namespace shown is the one used in the advisory's example.

kubectl --context example-cluster -n istio-system get cm istio \
  -o jsonpath='{@.data.mesh}'

The returned mesh configuration can establish whether disablePolicyChecks is true or false. A false value meets one condition for exposure, but the remaining conditions still matter. The workload protocol and its use of a Mixer authorization adapter determine whether this particular missing-check behavior affects the intended enforcement.

Reading the setting also cannot demonstrate that check calls occur. That is the precise mismatch in the original report. An affected version accepts the setting while building the inbound TCP filter incorrectly. Configuration inspection establishes intent, while the reported request behavior reveals that the implementation failed to carry it out.

I prefer describing these as separate facts because an operator can otherwise mistake a successful configuration read for enforcement evidence. The mesh setting is necessary context for this CVE, but the fixed implementation is what restores the path to the adapter. The deny rule alone cannot compensate for an omitted call.

The fix preceded the security classification

The Istio 1.1.7 release notes date that patch to May 17 and identify the correction for incorrectly disabled TCP policy checks. The May 28 advisory explains that the project recognized the security implications while reviewing those release notes. It initially understood the issue as affecting TCP Authorization, which was advertised as alpha.

The later review found that stable Deny Checker and List Checker behavior was also affected. That changed the security process the project considered necessary. The advisory says the maintainers are revisiting how to flag vulnerabilities reported as ordinary bugs instead of through private disclosure. The sequence is relevant because a normal-looking bug fix can restore a security property users already depend on.

This post is dated to the disclosure, so both the patch and its security significance are public at this point. The fix is available in 1.1.7 and later, according to the advisory. Existing 1.0.x installations are unaffected by this defect. The response therefore follows the affected release line and configuration, without requiring an unrelated claim about every historical Istio deployment.

The same patch release changes another protocol-specific filter choice. Earlier releases automatically injected an experimental MySQL proxy filter into the outbound chain when the service port was named mysql. The release notes say that surprised operators and caused problems. Version 1.1.7 instead requires the PILOT_ENABLE_MYSQL_FILTER environment variable to be set to 1 before automatically injecting it.

That is a separate fix, but it supplies useful context for the role of Pilot. A service's port naming and control-plane options can select data-plane filters. Those filters then determine which operations run on the connection. Understanding the generated chain is necessary when a configuration looks correct at the resource level but traffic follows unexpected behavior.

Neither the MySQL change nor the policy-check fix requires inventing a new application protocol. Both adjust how existing traffic is handled by the proxy configuration. For TCP authorization, the security-relevant correction is specifically restoring the inbound policy check. For the experimental MySQL filter, the release makes insertion depend on explicit enablement.

Stable adapters depend on the whole invocation path

The case exposes a limit in classifying security by the maturity of a single named feature. A stable adapter can depend on configuration generated by code also serving a newer traffic capability. The security property belongs to the complete connection-to-decision path. Calling one part alpha does not remove the expectations attached to another stable part using that path.

The project's own reassessment makes that point concrete. Initially it concentrated on the TCP Authorization feature. Its subsequent advisory accounted for the stable checkers affected by the same missing calls. A user relying on those checkers needs the fixed filter behavior even if they never selected a feature by the newer authorization name.

For the affected configuration, remediation is to update the 1.1 installation to a release containing the fix. The intended result is that incoming TCP connections consult Mixer according to the enabled policy-check setting and adapter configuration. That restores the opportunity for the stable checker to evaluate its rule, which the pre-fix filter construction had omitted despite the administrator's declared intent.