magento2 icon indicating copy to clipboard operation
magento2 copied to clipboard

DynamicStorage.findProductRewriteByRequestPath() lacks entity_type filtering, causing CMS pages to be treated as products in category URLs

Open rbouma opened this issue 6 months ago • 10 comments

Preconditions and environment

  • Magento version: 2.4.x (affects all versions with DynamicStorage)
  • Environment: Any Magento installation with:
    • CMS pages with URL rewrites (e.g., privacy-policy-cookie-restriction-mode)
    • Categories with URL rewrites (e.g., schroeven)
    • Catalog URL Rewrite module enabled
  • Modules: Default Magento installation (no third-party modules required to reproduce)
  • URL Structure: Category URLs with CMS page identifiers as suffixes

Steps to reproduce

Prerequisites Setup:

  1. Create Category:

    • Create a category with URL key schroeven
    • Note the category entity_id (e.g., ID = 48)
  2. Create CMS Page:

    • Create a CMS page with identifier privacy-policy-cookie-restriction-mode
    • Note the CMS page entity_id (e.g., ID = 4)
  3. Create Product with Matching ID:

    • Create a product with entity_id = 4 (same as CMS page ID)
    • This is crucial - the product ID must match the CMS page ID
    • Assign this product to the schroeven category (ID 48)
    • Ensure the product is enabled and visible
  4. System Maintenance:

    bin/magento indexer:reindex
    bin/magento cache:clean
    bin/magento cache:flush
    

Reproduction Steps:

  1. Verify URL rewrites exist in database:

    -- Should show CMS page rewrite
    SELECT * FROM url_rewrite WHERE request_path = 'privacy-policy-cookie-restriction-mode';
    -- Should show category rewrite  
    SELECT * FROM url_rewrite WHERE request_path = 'schroeven.html';
    
  2. Navigate to malformed URL: /schroeven/privacy-policy-cookie-restriction-mode

  3. Observe the response

Why This Setup Is Required:

  • DynamicStorage extracts privacy-policy-cookie-restriction-mode
  • Finds CMS page with entity_id=4 (but treats it as product_id=4)
  • Checks if product_id=4 can be shown in category_id=48 using ProductResource::canBeShowInCategory(4, 48)
  • Since product ID 4 IS assigned to category 48, the check passes
  • DynamicStorage creates: /cms/page/view/page_id/4/category/48

Expected result

The URL /schroeven/privacy-policy-cookie-restriction-mode should return HTTP 404 because:

  • It's not a valid product URL pattern
  • It's not a valid category URL
  • It's not a valid CMS page URL
  • This malformed URL pattern should not resolve to any content

Actual result

The URL /schroeven/privacy-policy-cookie-restriction-mode returns HTTP 200 and serves the CMS page content with category context.

Root Cause Analysis: The issue occurs in vendor/magento/module-catalog-url-rewrite/Model/Storage/DynamicStorage.php:

  1. Method findProductRewriteByRequestPath() extracts privacy-policy-cookie-restriction-mode from the URL
  2. It queries url_rewrite table WITHOUT filtering by entity_type
  3. Query finds the CMS page URL rewrite (entity_type = 'cms-page')
  4. DynamicStorage treats the CMS page as if it's a product
  5. Creates malformed target path: /cms/page/view/page_id/X/category/Y
  6. UrlRewrite Router serves this as valid content

Problematic Code (line ~147):

$productFromDb = $this->connection->fetchRow($this->prepareSelect($data));

The $data array only contains request_path and store_id - missing entity_type = 'product' filter.

Additional information

Database Evidence:

-- This query shows the CMS page that gets incorrectly matched
SELECT * FROM url_rewrite WHERE request_path = 'privacy-policy-cookie-restriction-mode';
-- Returns: entity_type='cms-page', entity_id=4, target_path='cms/page/view/page_id/4'

Debug Logs: When processing /schroeven/privacy-policy-cookie-restriction-mode:

  1. UrlRewrite Router calls DynamicStorage
  2. DynamicStorage finds CMS page data (should only find products)
  3. Router creates Forward action to /cms/page/view/page_id/4/category/48

Affected Code Files:

  • vendor/magento/module-catalog-url-rewrite/Model/Storage/DynamicStorage.php (lines 140-200)
  • Method: findProductRewriteByRequestPath()

Suggested Fix: Add entity_type filtering in the database query:

// Before querying for "product" data, ensure we only get products
$data[UrlRewrite::ENTITY_TYPE] = 'product';
$productFromDb = $this->connection->fetchRow($this->prepareSelect($data));

Security Impact: None - this is a URL routing issue, not a security vulnerability.

Performance Impact: Minimal - affects only specific URL patterns.

Workaround: Plugin on UrlRewrite Router to block malformed URL patterns before they reach DynamicStorage.

Release note

Fixed DynamicStorage URL rewrite query to properly filter by entity_type, preventing CMS pages from being incorrectly processed as products in category URL contexts.

Triage and priority

  • [ ] Severity: S0 - Affects critical data or functionality and leaves users without workaround.
  • [x] Severity: S1 - Affects critical data or functionality and forces users to employ a workaround.
  • [ ] Severity: S2 - Affects non-critical data or functionality and forces users to employ a workaround.
  • [ ] Severity: S3 - Affects non-critical data or functionality and does not force users to employ a workaround.
  • [ ] Severity: S4 - Affects aesthetics, professional look and feel, “quality” or “usability”.

rbouma avatar Jun 13 '25 20:06 rbouma

Hi @rbouma. Thank you for your report. To speed up processing of this issue, make sure that the issue is reproducible on the vanilla Magento instance following Steps to reproduce.


Join Magento Community Engineering Slack and ask your questions in #github channel. :warning: According to the Magento Contribution requirements, all issues must go through the Community Contributions Triage process. Community Contributions Triage is a public meeting. :clock10: You can find the schedule on the Magento Community Calendar page. :telephone_receiver: The triage of issues happens in the queue order. If you want to speed up the delivery of your contribution, join the Community Contributions Triage session to discuss the appropriate ticket.

m2-assistant[bot] avatar Jun 13 '25 20:06 m2-assistant[bot]

Hi @rbouma! :wave: Thank you for collaboration. Only members of Community Contributors Team are allowed to be assigned to the issue. Please use @magento add to contributors team command to join Contributors team.

m2-assistant[bot] avatar Jun 13 '25 21:06 m2-assistant[bot]

Hi @rbouma! :wave: Thank you for joining. Please accept team invitation :point_right: here :point_left: and add your comment one more time.

m2-assistant[bot] avatar Jun 13 '25 21:06 m2-assistant[bot]

Hi @engcom-Bravo. Thank you for working on this issue. In order to make sure that issue has enough information and ready for development, please read and check the following instruction: :point_down:

  • [ ] 1. Verify that issue has all the required information. (Preconditions, Steps to reproduce, Expected result, Actual result).
  • [ ] 2. Verify that issue has a meaningful description and provides enough information to reproduce the issue.
  • [ ] 3. Add Area: XXXXX label to the ticket, indicating the functional areas it may be related to.
  • [ ] 4. Verify that the issue is reproducible on 2.4-develop branch
    Details- If the issue is reproducible on 2.4-develop branch, please, add the label Reproduced on 2.4.x.
    - If the issue is not reproducible, add your comment that issue is not reproducible and close the issue and stop verification process here!
  • [ ] 5. Add label Issue: Confirmed once verification is complete.
  • [ ] 6. Make sure that automatic system confirms that report has been added to the backlog.

m2-assistant[bot] avatar Jun 13 '25 23:06 m2-assistant[bot]

Hi @rbouma,

Thanks for your reporting and collaboration.

We have tried to reproduce the issue in Latest 2.4-develop instance and we are not able to reproduce the issue.Kindly refer the screenshots.

Image

The URL /schroeven/privacy-policy-cookie-restriction-mode returns HTTP 404.Could you please let us know if we are missing anything.

Thanks.

engcom-Bravo avatar Jun 16 '25 10:06 engcom-Bravo

@engcom-Bravo I can confirm and reproduced this issue on a clean Magento 2.4.8-p1 install with no third-party modules.

Environment

  • Magento version: 2.4.8-p1 (clean install)
  • PHP: 8.3
  • MySQL/: 8.0
  • Redis: 8.0 (used for default cache, FPC & session)
  • RabbitMQ: 4.1 (enabled)
  • Varnish: 7.7 (enabled, not affecting routing in this case)
  • OpenSearch: 2.19 (instead of Elasticsearch)
  • FPC: disabled via cache_types (full_page = 0)
  • Magento mode: developer

Reproduction steps

  1. Leave the default CMS pages untouched (in particular privacy-policy-cookie-restriction-mode).

Image

  1. Create a new category: * URL key: schroeven

Image

  1. Create a product with an entity_id that matches the CMS page's entity_id.
    • I created 5 sample products in my demo.
    • For example, if the CMS page has ID 4, create a product with entity_id = 4.
    • Assign this product to the schroeven category.

Image

Image

  1. Re-index and flush caches:
    bin/magento indexer:reindex
    bin/magento cache:clean
    

  1. Browse to the following URLs:

URL Expected Actual
/privacy-policy-cookie-restriction-mode CMS page (OK) CMS page
/schroeven/privacy-policy-cookie-restriction-mode 404 CMS page shown inside the category context (HTTP 200)
/test123/privacy-policy-cookie-restriction-mode 404 404

Image

The second URL demonstrates that DynamicStorage::findProductRewriteByRequestPath() incorrectly matches a CMS rewrite when:

  • The CMS page and product share the same entity_id
  • The product is assigned to the category from the URL path

This leads to invalid URL generation: /cms/page/view/page_id/4/category/48

Why it matters

  • Creates duplicate content (/privacy-policy-cookie-restriction-mode and /schroeven/privacy-policy-cookie-restriction-mode) → SEO impact.
  • Violates URL structure expectations: CMS pages should not be accessible within category URL contexts.
  • Bug is entity_id-based, meaning any CMS/product ID collision can cause this.

Suggested fix (PR #39997)

Add an entity_type = 'product' filter in DynamicStorage::findProductRewriteByRequestPath() before querying the URL rewrite table.

Let me know if you need further logs, DB dumps or an integration test—I’m happy to help.

rbouma avatar Jun 19 '25 11:06 rbouma

Hi @rbouma,

Thanks for your detailed response.

We have tried to reproduce the issue in Latest 2.4-develop instance and we are able to reproduce the issue.Kindly refer the screenshots.

Image

The URL /schroeven/privacy-policy-cookie-restriction-mode returns HTTP 200 and serves the CMS page content with category context.

Hence Confirming the issue.

Thanks.

engcom-Bravo avatar Jun 20 '25 09:06 engcom-Bravo

:white_check_mark: Jira issue https://jira.corp.adobe.com/browse/AC-14991 is successfully created for this GitHub issue.

github-jira-sync-bot avatar Jun 20 '25 09:06 github-jira-sync-bot

:white_check_mark: Confirmed by @engcom-Bravo. Thank you for verifying the issue.
Issue Available: @engcom-Bravo, You will be automatically unassigned. Contributors/Maintainers can claim this issue to continue. To reclaim and continue work, reassign the ticket to yourself.

m2-assistant[bot] avatar Jun 20 '25 09:06 m2-assistant[bot]