Skip to content

Review postcode validation anchors to reject trailing newlines #67667

Closed

Description

@coderabbitai

Summary

Several country-specific postcode validation patterns in WC_Validation::is_postcode() use the PCRE $ end anchor. In PHP PCRE, $ can match immediately before a final newline. As a result, a postcode that otherwise matches a strict format can be accepted when it has a trailing newline.

The Latvia (LV) rule now uses \z and rejects this input. Review the other postcode rules for the same behavior in a separate change.

Required changes

  • Review the country-specific patterns in plugins/woocommerce/includes/class-wc-validation.php.
  • Replace $ with \z only for patterns that must validate the complete postcode input.
  • Add test fixtures in plugins/woocommerce/tests/php/includes/class-wc-validation-test.php for affected formats with a trailing newline. Each fixture must assert that the input is invalid.
  • Review rules with intentionally different matching behavior separately. Do not make a mechanical anchor replacement. In particular, assess the unanchored Ireland (IE) rule and the default validation path before changing them.
  • Preserve valid existing postcode formats and WordPress/WooCommerce extension compatibility.

Rationale

$ accepts a match before a final newline in PHP PCRE. \z matches only at the absolute end of the input. Strict country-specific postcode validation should reject inputs such as "LV-1050\n" when the newline is part of the submitted value.

Affected area

  • plugins/woocommerce/includes/class-wc-validation.php
  • plugins/woocommerce/tests/php/includes/class-wc-validation-test.php
  • plugins/woocommerce/client/blocks/packages/public-api/blocks-checkout/utils/validation/is-postcode.ts

Acceptance criteria

  • Each reviewed strict postcode rule rejects an otherwise valid postcode with a trailing newline.
  • The related tests cover the changed rules.
  • Existing valid postcode fixtures continue to pass.
  • The Ireland rule and the default path have an explicit review outcome, even if they remain unchanged.

Additional detail

Ireland is the highest-value part of this, and it is not a newline problem

The IE rule is not anchored at either end, so it matches a valid Eircode anywhere inside the string. Verified against the current pattern:

"A651234"          => VALID
"JUNKA651234JUNK"  => VALID
"xxD6W1234xx"      => VALID

That accepts arbitrary junk around a valid Eircode, which is a stronger defect than the trailing-newline case. Treat it as the priority item, and anchor it with \A(?:...)\z rather than only swapping the end anchor.

The same anchor question applies to the Blocks validator, where it is a divergence

is-postcode.ts uses JavaScript regexes, and JS $ does not match before a trailing newline. So the two validators already disagree today. For Slovenia:

"1050\n"  =>  PHP: VALID    JS: invalid

Any fix should bring both sides to the same verdict, not just tighten PHP. Checking only class-wc-validation.php leaves the divergence in place.

Practical impact, for prioritisation

Every core caller runs wc_format_postcode() before is_postcode(), and that trims and strips whitespace, so trailing newlines do not reach the validator through checkout, the Store API, the My Account address form, or the cart shipping calculator. The exposure is third-party code calling the public static WC_Validation::is_postcode() with raw input. That makes the newline half of this hardening rather than a live checkout bug. The unanchored IE rule is reachable with or without a newline.

Relationship to #66953

#66953 proposes generating both validators from one shared artifact. The anchor rule agreed there is to emit \A(?:...)\z for PHP and ^(?:...)$ for JS, which resolves this issue for every country as a side effect. If that work lands first, close this as superseded. If it stalls, this stands on its own.

Context

Requested by @opr.

Follow-up from https://github.com/woocommerce/woocommerce/pull/67460
Review discussion: #67460 (comment)

Activity

  1. assigned and unassigned on Aug 12, 2026
  2. tyxla commented on Sep 7, 2026

    @tyxla
    Member

    @opr I believe we can close this one after #67780 landed, but can you please confirm?

  3. opr commented on Sep 8, 2026

    @opr
    Contributor

    Yes, you're right, thanks for flagging

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions