Back-Reference To A Missing Group

ID

php.back_references_regular_expr_refer

Severity

high

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

Php

Tags

regex, reliability

Description

Reports a back-reference that points at a capturing group the pattern does not have, or at one that is not yet fully defined where the reference appears — a self-reference inside the group’s own body, or a forward reference before the group opens.

All the PCRE spellings are read: \1, \g1, \g{1}, \k<name>, \k{name} and \k’name'.

Rationale

The two shapes fail differently, and neither fails loudly.

// Bad
preg_match('/(\d+)-(\d+)\3/', '12-34');           // false + warning: there is no group 3
preg_match('/(a\1b)/', 'aab');                    // 0: group 1 has captured nothing yet
preg_match('/(?<year>\d{4})\k<yer>/', '2026');    // false + warning: the group is named year
  • A reference to a group that does not exist is a compile error. PCRE refuses the pattern, preg_match warns and returns false, and the guard silently never fires.

  • A reference to a group that is not yet defined compiles cleanly and simply never matches, because at that point the group holds nothing.

  • Both normally arrive from editing: a group was removed or reordered and the numbers after it shifted, or a group name was changed in one place only.

Remediation

Point the reference at a group that exists and is already closed, and prefer names over numbers so that reordering groups cannot break it.

// Good
preg_match('/(\d+)-(\d+)\2/', $s);
preg_match('/(?<year>\d{4})\k<year>/', $s);

What is not reported

A bare two-digit reference above 9 is left alone unless that many groups exist. PCRE reads \10 as an octal escape when the pattern has fewer than ten groups, so /(a)\10/ is the valid pattern "group 1’s text, then a backspace". The braced spellings carry no such ambiguity and are always references, so \g{5} against two groups is reported.

Which alternation branch a reference sits in is not modelled: /(a|(b))\2/ is judged purely on textual order, never on whether the two branches could both execute. Relative references such as \g{-1} are also left alone.

© 2026 Xygeni. All rights reserved