RepeatedCookieHeaderReplacement
warning native on by default quick-fixGroup: Probable bugs
Detect a second header call with a Set-Cookie literal and default/true replace flag on a path with an earlier Set-Cookie header.
Example
<?php
header('Set-Cookie: a=1'); header('Set-Cookie: b=2');<?php
header('Set-Cookie: a=1'); header('Set-Cookie: b=2', false);Reported:
- line 2: Append distinct cookie headers instead of replacing them.
Detection
- Report a second header call with a Set-Cookie literal and default/true replace flag on a path with an earlier Set-Cookie header, when both literals name a cookie and the two names differ.
- The cookie name is the trimmed text between the field name's colon and the first
=of the leadingname=valuepair (the part before the first;). Names are compared byte for byte; theSet-Cookiefield name itself is matched case-insensitively. - Resolve builtin calls and named arguments before checking the contract. Project-local callees are considered only when their bodies or immutable summaries establish the required facts. The default is enabled, with positive proof required.
- For flow-dependent conditions, require a reachable source-to-use path with no intervening invalidation. Unknown calls, ambiguous aliases, recursion or analysis-budget exhaustion cannot establish definite facts.
Exceptions (no report)
- setcookie calls, replace false, header_remove clearing the earlier value and different response lifetimes are excluded.
- Both headers set the same cookie name: the later call deliberately replaces that cookie (new value, expiry), and appending would send both values.
- Either line has no
name=valuepair before its first;, or an empty name: the cookie names cannot be compared. - A
header_removecall sits between the two header calls in the same scope, on any branch, and has no argument, aSet-Cookiename in any letter case, or a name that is not a known string. Aheader_removenaming another header changes nothing. - Unresolved targets, incomplete required facts, suppressed findings and PHP versions lacking the referenced API or language feature produce no report. User declarations shadowing builtin names are not builtin contracts.
Fix
Set the second call replace argument to false only when both cookie names are different and no existing replacement policy is expressed: a call that already passes a replace argument is reported without a fix.
A fix is offered only when the concrete prerequisites above are proven. Edits use exact source byte ranges, preserve comments and argument evaluation order, and introduce syntax supported by the configured PHP version. Never invent error-handling policy.
PHP versions
Apply only on PHP versions supporting the referenced APIs and syntax (within PHP 5.3–8.5). Builtin behavior and argument contracts follow the configured PHP version. Extension-specific calls require resolved extension API symbols; do not treat same-named application functions as extension calls.
Options
None. Enable or disable this rule through normal rule configuration.
Configure
In custos.json:
{
"rules": {
"RepeatedCookieHeaderReplacement": {
"enabled": false
}
}
}Suppress
Before the statement or declaration (or the first statement of the file):
// @custos-ignore RepeatedCookieHeaderReplacement