-
Notifications
You must be signed in to change notification settings - Fork 32
replace hardcoded script tags with core api #360
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -7,37 +7,39 @@ | |||||||||||
| * @var array $data_regions | ||||||||||||
| * @var string|bool $tcf | ||||||||||||
| */ | ||||||||||||
| ?> | ||||||||||||
| <script type="text/javascript" | ||||||||||||
| id="Cookiebot" | ||||||||||||
| src="https://consent.cookiebot.com/uc.js" | ||||||||||||
| data-implementation="wp" | ||||||||||||
| data-cbid="<?php echo esc_attr( $cbid ); ?>" | ||||||||||||
| <?php if ( $tcf ) : ?> | ||||||||||||
| data-framework="<?php echo esc_attr( $tcf ); ?>" | ||||||||||||
| <?php endif; ?> | ||||||||||||
| <?php | ||||||||||||
| if ( $data_regions ) { | ||||||||||||
| echo 'data-georegions="'; | ||||||||||||
| foreach ( $data_regions as $cbid => $regions ) { | ||||||||||||
| echo '{\'region\':\'' . esc_attr( $regions ) . '\',\'cbid\':\'' . esc_attr( $cbid ) . '\'}'; | ||||||||||||
| end( $data_regions ); | ||||||||||||
| if ( $cbid !== key( $data_regions ) ) { | ||||||||||||
| echo ','; | ||||||||||||
| } | ||||||||||||
| } | ||||||||||||
| echo '"'; | ||||||||||||
|
|
||||||||||||
| $script_attributes = array( | ||||||||||||
| 'type' => 'text/javascript', | ||||||||||||
| 'id' => 'Cookiebot', | ||||||||||||
| 'src' => 'https://consent.cookiebot.com/uc.js', | ||||||||||||
| 'data-implementation' => 'wp', | ||||||||||||
| 'data-cbid' => $cbid, | ||||||||||||
| ); | ||||||||||||
|
|
||||||||||||
| if ( $tcf ) { | ||||||||||||
| $script_attributes['data-framework'] = $tcf; | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| if ( $data_regions ) { | ||||||||||||
| $georegions = array(); | ||||||||||||
| foreach ( $data_regions as $cbid => $regions ) { | ||||||||||||
| $georegions[] = '{\'region\':\'' . esc_attr( $regions ) . '\',\'cbid\':\'' . esc_attr( $cbid ) . '\'}'; | ||||||||||||
|
Comment on lines
+25
to
+26
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [REFACTORING] The foreach uses foreach ( $data_regions as $cbid => $regions ) which re-uses the outer $cbid variable name (the Cookiebot ID). Rename the loop key (e.g. $region_cbid) to avoid variable shadowing and confusion: foreach ( $data_regions as $region_cbid => $regions ) { ... }. This improves readability and avoids accidental bugs if the variable usage order changes. if ( $data_regions ) {
$georegions = array();
foreach ( $data_regions as $region_cbid => $regions ) {
$georegions[] = '{\'region\':\'' . esc_attr( $regions ) . '\',\'cbid\':\'' . esc_attr( $region_cbid ) . '\'}';
}
$script_attributes['data-georegions'] = implode( ',', $georegions );
}
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While true this case was present before this patch. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Question:While true this case was present before this patch. Answer:To reduce “this existed before the patch” style refactoring suggestions, configure Add this to your [pr_code_suggestions]
extra_instructions = """\
Only suggest changes that are directly caused by, introduced by, or modified in this PR.
Do not suggest refactors/cleanups for pre-existing code issues unless they create a real bug/security issue in the PR diff.
Prefer correctness/safety issues over readability or naming suggestions.
"""
# Optional: further reduce style-level suggestions
focus_only_on_problems = true
# Optional: filter out low-importance suggestions (tune as needed)
suggestions_score_threshold = 7If you still want occasional refactoring suggestions, keep the threshold lower (e.g., 5–6) and remove/soften the “prefer correctness” line. Relevant Sources:
|
||||||||||||
| } | ||||||||||||
| ?> | ||||||||||||
| <?php if ( (bool) get_option( 'cookiebot-gtm' ) !== false && ! empty( get_option( 'cookiebot-data-layer' ) ) ) : ?> | ||||||||||||
| data-layer-name="<?php echo esc_attr( get_option( 'cookiebot-data-layer' ) ); ?>" | ||||||||||||
| <?php endif; ?> | ||||||||||||
| <?php if ( ! empty( $lang ) ) : ?> | ||||||||||||
| data-culture="<?php echo esc_attr( strtoupper( $lang ) ); ?>" | ||||||||||||
| <?php endif; ?> | ||||||||||||
| <?php if ( $cookie_blocking_mode === 'auto' ) : ?> | ||||||||||||
| data-blockingmode="auto" | ||||||||||||
| <?php else : ?> | ||||||||||||
| <?php echo esc_attr( $tag_attr ); ?> | ||||||||||||
| <?php endif; ?> | ||||||||||||
| ></script> | ||||||||||||
| $script_attributes['data-georegions'] = implode( ',', $georegions ); | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| if ( (bool) get_option( 'cookiebot-gtm' ) !== false && ! empty( get_option( 'cookiebot-data-layer' ) ) ) { | ||||||||||||
| $script_attributes['data-layer-name'] = get_option( 'cookiebot-data-layer' ); | ||||||||||||
|
Comment on lines
+31
to
+32
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: Unescaped option value used for Severity Level: Critical 🚨- ❌ Admin-set option may inject unsafe frontend attribute.
- ⚠️ Data layer integration could be exploited.
Suggested change
Steps of Reproduction ✅1. As a site admin, set the option 'cookiebot-data-layer' to a payload value via the WP
options UI or direct DB write (e.g. data like '" onclick="alert(1)').
2. Load a frontend page that renders the plugin template
src/view/frontend/scripts/cb_frame/cookiebot-js.php.
3. The conditional at line 31 checks options and (when true) assigns
get_option('cookiebot-data-layer') directly into $script_attributes at line 32.
4. The template emits the script attributes with wp_print_script_tag() at line 45; because
the option value was not escaped before assignment, the output can contain unescaped
content, demonstrating possible XSS via an admin-configured option.
Note: Steps reference concrete code locations: option fetch and assignment (lines 31-32)
and emission at line 45.Prompt for AI Agent 🤖This is a comment left during a code review.
**Path:** src/view/frontend/scripts/cb_frame/cookiebot-js.php
**Line:** 31:32
**Comment:**
*Security: Unescaped option value used for `data-layer-name`: `get_option( 'cookiebot-data-layer' )` is assigned directly to attributes array without escaping; fetch the option once, check it, and escape it with `esc_attr()` before use.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Question:See Answer:If To reduce these kinds of WP-specific false positives in [pr_code_suggestions]
extra_instructions = """\
- For WordPress/PHP code: before suggesting esc_attr()/esc_html()/esc_url() (or tagging as security/XSS), verify whether the output API already sanitizes/escapes (e.g., wp_print_script_tag() -> wp_sanitize_script_attributes()).
- If escaping is already applied by the sink function, do not recommend redundant escaping; instead, briefly mention why it's already safe.
- Prefer referencing the escaping/sanitization function in the rationale when concluding it's safe.
"""
#### Relevant Sources:
> - https://docs.qodo.ai/qodo-documentation/qodo-merge/tools/improve#extra-instructions-and-best-practices
> - https://docs.qodo.ai/qodo-documentation/qodo-merge/faq/index#-note-"q:-i-received-an-incorrect-or-irrelevant-suggestion-why"
> - https://docs.qodo.ai/qodo-documentation/qodo-merge/usage-guide/additional_configurations#extra-instructions |
||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| if ( ! empty( $lang ) ) { | ||||||||||||
| $script_attributes['data-culture'] = strtoupper( $lang ); | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| if ( $cookie_blocking_mode === 'auto' ) { | ||||||||||||
| $script_attributes['data-blockingmode'] = 'auto'; | ||||||||||||
| } elseif ( ! empty( $tag_attr ) ) { | ||||||||||||
|
Comment on lines
+11
to
+41
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [VALIDATION] User-supplied or option-derived values are assigned to attributes without explicit escaping (e.g. 'data-cbid', 'data-framework', 'data-layer-name', 'data-culture'). Ensure values are sanitized/escaped before insertion (use esc_attr() or cast to string) or validate them. For example: $script_attributes['data-cbid'] = esc_attr( (string) $cbid ); and $script_attributes['data-layer-name'] = esc_attr( (string) get_option('cookiebot-data-layer') ); This prevents injection or malformed attributes when rendering via wp_print_script_tag. $script_attributes = array(
'type' => 'text/javascript',
'id' => 'Cookiebot',
'src' => 'https://consent.cookiebot.com/uc.js',
'data-implementation' => 'wp',
'data-cbid' => esc_attr( (string) $cbid ),
);
if ( $tcf ) {
$script_attributes['data-framework'] = esc_attr( (string) $tcf );
}
if ( $data_regions ) {
$georegions = array();
foreach ( $data_regions as $region_cbid => $regions ) {
$georegions[] = '{\'region\':\'' . esc_attr( $regions ) . '\',\'cbid\':\'' . esc_attr( $region_cbid ) . '\'}';
}
$script_attributes['data-georegions'] = implode( ',', $georegions );
}
$data_layer = get_option( 'cookiebot-data-layer' );
if ( (bool) get_option( 'cookiebot-gtm' ) !== false && ! empty( $data_layer ) ) {
$script_attributes['data-layer-name'] = esc_attr( (string) $data_layer );
}
if ( ! empty( $lang ) ) {
$script_attributes['data-culture'] = esc_attr( strtoupper( $lang ) );
} |
||||||||||||
| $script_attributes[ $tag_attr ] = true; | ||||||||||||
| } | ||||||||||||
|
Comment on lines
+41
to
+43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [CRITICAL_BUG] This line sets $script_attributes[ $tag_attr ] = true; but $tag_attr in the original code was a prebuilt attribute string (e.g. 'type="text/plain" data-cookieconsent="..."'). Using it as an array key will produce an invalid attribute and break output. Restore the original behavior by either: (a) parsing $tag_attr into key/value pairs and merging into $script_attributes, or (b) when $cookie_blocking_mode !== 'auto' output the raw $tag_attr string instead of using wp_print_script_tag. Example actionable fix: parse attributes with preg_match_all('/([\w:-]+)(?:\s*=\s*"([^"]*)")?/', $tag_attr, $m) and set $script_attributes[$m[1][$i]] = $m[2][$i] for each match before calling wp_print_script_tag. if ( $cookie_blocking_mode === 'auto' ) {
$script_attributes['data-blockingmode'] = 'auto';
} elseif ( ! empty( $tag_attr ) ) {
// Preserve legacy behavior for non-auto mode by parsing composite attributes.
if ( preg_match_all( '/([\w:-]+)(?:\s*=\s*"([^"]*)")?/', $tag_attr, $matches, PREG_SET_ORDER ) ) {
foreach ( $matches as $match ) {
$attr_name = $match[1];
$attr_value = isset( $match[2] ) ? $match[2] : true;
$script_attributes[ $attr_name ] = $attr_value;
}
}
}
wp_print_script_tag( $script_attributes );
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is wrong. The
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Question:This is wrong. The Answer:This looks like a classic “wrong assumption about variable provenance” issue: the suggestion assumed This can be reduced via configuration by tightening the
Add a repo-level instruction like: [pr_code_suggestions]
extra_instructions = """\
When reviewing PHP/WordPress code:
- Do NOT assume a variable contains a composite HTML-attribute string unless it is explicitly constructed/validated in the changed code.
- Before flagging a CRITICAL_BUG, confirm the variable’s source (e.g., options/DB values) and allowed values from nearby code/context.
- For wp_print_script_tag()/script attributes, treat 'async' and 'defer' as valid boolean attributes; don't recommend parsing them into key/value pairs unless required by the diff.
- Prefer asking for clarification over asserting breakage when the variable type/value-set is ambiguous.
"""If you want this to apply only to Relevant Sources:
|
||||||||||||
|
|
||||||||||||
| wp_print_script_tag( $script_attributes ); | ||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,8 +6,15 @@ | |
| * @var string $script_type | ||
| */ | ||
|
|
||
| $script_attributes = array( | ||
| 'type' => $script_type, | ||
| ); | ||
| if ($consent_attribute) { | ||
| $script_attributes['data-cookieconsent'] = $consent_attribute; | ||
| } | ||
|
Comment on lines
+12
to
+14
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [VALIDATION] When assigning $consent_attribute into the script attributes use escaping/validation: $script_attributes['data-cookieconsent'] = esc_attr( (string) $consent_attribute ); This prevents malformed attribute values from being output in the inline script tag. $script_attributes = array(
'type' => $script_type,
);
if ( $consent_attribute ) {
$script_attributes['data-cookieconsent'] = esc_attr( (string) $consent_attribute );
}
ob_start();
?>
<script>
window.<?php echo esc_js( $data_layer ); ?> = window.<?php echo esc_js( $data_layer ); ?> || [];
// ... rest of script body ...
</script>
<?php
wp_print_inline_script_tag( ob_get_clean(), $script_attributes ); |
||
|
|
||
| ob_start(); | ||
| ?> | ||
| <script type="<?php echo esc_attr( $script_type ); ?>"<?php echo ! $consent_attribute ? '' : ' data-cookieconsent="' . esc_attr( $consent_attribute ) . '"'; ?>> | ||
| window.<?php echo esc_js( $data_layer ); ?> = window.<?php echo esc_js( $data_layer ); ?> || []; | ||
|
|
||
| function gtag() { | ||
|
|
@@ -31,4 +38,5 @@ functionality_storage: "denied", | |
| 'gtag("set", "url_passthrough", true);' . PHP_EOL; | ||
| } | ||
| ?> | ||
| </script> | ||
|
|
||
| <?php wp_print_inline_script_tag( ob_get_clean(), $script_attributes ); ?> | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: Unsanitized assignment to
data-cbid: the value from$cbidis assigned directly to attributes array without escaping, which can lead to unsafe output; escape the value withesc_attr()when building attributes. [security]Severity Level: Critical 🚨
Steps of Reproduction ✅
Prompt for AI Agent 🤖