LW-3297 Harden parent correlation ID capture - #25
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces validation and sanitization for the parent correlation ID to prevent potential log injection and bloat. It enforces a maximum length of 128 characters and restricts allowed characters to an alphanumeric set including dots, underscores, and hyphens. Additionally, it ensures the parent correlation ID is reset at the start of each main HTTP request to prevent data leakage across reused processes. Comprehensive unit tests have been added to verify these changes. I have no further feedback to provide.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
e06a166 to
74f1956
Compare
mSprunskas
left a comment
There was a problem hiding this comment.
Looks good in general, please remove all redundant comments though, thanks.
| class ParentCorrelationIdProvider | ||
| { | ||
| // Stays under Sentry's 200-char tag limit. | ||
| private const MAX_LENGTH = 128; |
There was a problem hiding this comment.
Why not make it 200 then? If length is also indication of who generated the value (us or someone else), then Sentry is irrelevant
There was a problem hiding this comment.
128 is more than enough. Mention of sentry is removed.
|
|
||
| private ?string $parentCorrelationId; | ||
| // The alphabet the bundle's own correlation id generator emits; `\z` (not `$`) | ||
| // anchors strictly so a trailing newline cannot slip through. |
There was a problem hiding this comment.
Comments like this should be part of PR, not part of code
74f1956 to
937ae6f
Compare
mSprunskas
left a comment
There was a problem hiding this comment.
1. Redundant empty-string check (low / simplification)
src/Service/ParentCorrelationIdProvider.php:36
return $parentCorrelationId !== ''
&& strlen($parentCorrelationId) <= self::MAX_LENGTH
&& preg_match(self::PATTERN, $parentCorrelationId) === 1;
The !== '' term is dead: the pattern's + quantifier already rejects the empty string (verified: preg_match('/^[A-Za-z0-9._-]+\z/', '') returns 0). It's harmless and arguably documents intent, but it is strictly redundant. Not a correctness bug.
| private ?string $parentCorrelationId; | ||
| private const PATTERN = '/^[A-Za-z0-9._-]+\z/'; | ||
|
|
||
| public function __construct() | ||
| { | ||
| $this->parentCorrelationId = null; | ||
| } |
There was a problem hiding this comment.
This was actually correct and according to our code style https://github.com/paysera/php-style-guide#default-property-values
There was a problem hiding this comment.
reverted this change
Make capture of the client-controlled Paysera-Correlation-Id header safe: validation is enforced in the provider (the single place the invariant is enforced for every caller) and the parent id is reset at the start of every main HTTP request so it cannot leak across requests in a reused process. Log output for legitimate ids is unchanged. - ParentCorrelationIdProvider::setParentCorrelationId() validates and silently ignores an invalid value (empty, over 128 chars, or outside [A-Za-z0-9._-]); an existing valid value is not clobbered by a later invalid one. `\z` anchors the pattern so a trailing newline cannot slip through. - ParentCorrelationIdListener resets the provider at the start of every main request before reading the header, then hands the header to the provider; validation is the provider's responsibility.
937ae6f to
7636664
Compare
Summary
Makes capture of the client-controlled
Paysera-Correlation-Idheader safe: the parent ID is validated in the provider (the single place the invariant is enforced for every caller) and reset at the start of every main HTTP request so it can't leak across requests in a reused process. Log output for legitimate IDs is unchanged.Why
This bundle emits the incoming header as
parent_corr_idto link cross-service traces. The value is client-controlled but was captured verbatim with no bounds:parent_corr_id(no tracing value);What changed
ParentCorrelationIdProvider— single owner of the validation rulesetParentCorrelationId()validates and silently ignores an invalid value (empty, longer thanMAX_LENGTH = 128, or outsidePATTERN = /^[A-Za-z0-9._-]+\z/). An existing valid value is not clobbered by a subsequent invalid one.128stays under Sentry's 200-char tag limit; the charset is the alphabet the bundle's own correlation ID generator emits.\z(not$) anchors strictly so a trailing newline cannot slip through.ParentCorrelationIdListener— pure consumerIterationEndListener; this closes the HTTP path).Design notes
setParentCorrelationId()now ignores values it previously stored verbatim (empty / out-of-charset / >128 chars); observable log output for legitimate IDs is identical.Tests / Test plan
composer installvendor/bin/phpunit→ 47 tests, 1191 assertions, green.Coverage added:
Reviewer check: capture behavior for legitimate IDs is unchanged; only empty/over-length/out-of-charset values are dropped, and the HTTP path no longer leaks a stale parent ID across requests.
Housekeeping
CHANGELOG.md:## 3.3.2—### Security(provider-enforced validation) and### Fixed(request-start reset).