Skip to content

Fixed - Security: SQLi in datagrid, image-ZIP import RCE, installer takeover + hardening (master) - #535

Merged
navneetkumar-pim-webkul merged 5 commits into
masterfrom
fix/security-master
Jul 1, 2026
Merged

navneetkumar-pim-webkul merged 5 commits into
masterfrom
fix/security-master

Conversation

@navneetkumar-pim-webkul

Copy link
Copy Markdown
Collaborator

Issue Reference

Security fixes ported to master (companion to #533 [2.0, merged] and #534 [2.1]): SQL injection (CWE-89), image-ZIP import RCE/stored-XSS (CWE-434), unauthenticated installer takeover (CWE-306), CSV/XLSX formula injection.

Description

  • SQLi: validate locale/channel scope codes; escape jsonExtract/jsonContains JSON-path segments (MySQL + Postgres); quote non-numeric ids in orderByField.
  • Image-ZIP import RCE/stored-XSS: extractImageEntries keeps only allowlisted image extensions with a real-MIME check, preserves subfolders, blocks zip-slip, and caps each entry's uncompressed size (default 15 MB) against zip bombs.
  • Installer takeover: persistent core_config install-completed flag (survives loss of the storage/installed marker) + backfill migration for already-installed instances; DB-populated guard on the destructive migration/seeder endpoints.
  • CSV/formula injection: neutralized in export while preserving numeric values and catching leading-whitespace formulas.

Incorporates the Copilot review feedback from #534 (orderByField quoting, .env-independent install flag, whitespace-aware formula check, ZIP-bomb size cap) and the PostgreSQL-portable datagrid assertions.

How To Test This?

vendor/bin/pest packages/Webkul/Core packages/Webkul/Admin packages/Webkul/DataTransfer packages/Webkul/Installer

Green locally: security suites + 166 Core/DataGrid/Product tests. vendor/bin/pint --test clean.

Documentation

  • My pull request requires an update on the documentation repository.

Branch Selection

  • Target Branch: master

Pint

Passed.

Tailwind Reordering

N/A.

…akeover + hardening

- Validate locale/channel scope codes and escape JSON_EXTRACT path segments (SQLi, CWE-89)
- Gate roles.store/roles.update/users.update mutator routes in ACL (authz bypass / priv-esc, CWE-862)
- Per-entry image allowlist + MIME check on ZIP import extraction, preserve subfolders, zip-slip guard (stored XSS/RCE, CWE-434)
- Persistent core_config install-completed flag + backfill migration; DB-populated guard on destructive install endpoints (unauth installer takeover, CWE-306)
- Neutralize CSV/formula injection in export (skip numeric); throttle admin login; password min:8; remove forgot-password user enumeration
- orderByField: quote non-numeric ids instead of int-casting them (both grammars) so string-keyed ordering still works
- isMarkedInstalled: drop the .env-file check so the DB install flag still seals containerized/env-var deployments without a .env on disk
- isFormulaValue: also escape values whose first non-whitespace char is a formula char (e.g. leading-space '=SUM(...)')
- image-ZIP import: default max entry size to 15MB so the size cap no longer rejects every image when unset
- CategoryDataGridLocaleInjectionTest: make JSON-path assertions dialect-agnostic (fixes PostgreSQL Pest failure)
Copilot AI review requested due to automatic review settings July 1, 2026 10:52

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Ports a set of security hardening changes to master across Core query grammars, Admin datagrids/import flows, and the Installer to address SQL injection, unsafe ZIP image extraction, installer takeover, and spreadsheet formula injection, with regression coverage.

Changes:

  • Add request-scope validation and SQL-escaping/quoting improvements in Core DB grammars (MySQL/Postgres) to mitigate SQLi vectors.
  • Replace bulk ZIP extraction with safe, allowlisted, MIME-checked per-entry extraction (zip-slip + zip-bomb entry-size cap) for image ZIP imports.
  • Add a persistent “installed” DB flag + backfill migration and use it to gate installer endpoints even if the storage marker is missing; add security-focused tests (Pest + Playwright).

Reviewed changes

Copilot reviewed 24 out of 24 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/e2e-pw/tests/08-security/category-locale-sqli.spec.js Playwright regression spec for locale-based SQLi in Category datagrid.
packages/Webkul/Installer/tests/Feature/InstallerSecurityTest.php Adjust installer security tests to reset the new DB “installed” flag.
packages/Webkul/Installer/tests/Feature/InstallerDbStateGateTest.php New feature tests ensuring destructive installer endpoints are blocked when DB indicates installed.
packages/Webkul/Installer/tests/Feature/InstallerControllerTest.php Ensure installer controller tests clean up the persistent install flag.
packages/Webkul/Installer/src/Http/Middleware/CanInstall.php Installer middleware now checks both storage marker and DB installed flag.
packages/Webkul/Installer/src/Http/Controllers/InstallerController.php Add DB-populated guard and persist install flag when marking installed.
packages/Webkul/Installer/src/Helpers/DatabaseManager.php Implement persistent installer.installed flag read/write helpers.
packages/Webkul/Installer/src/Console/Commands/Installer.php CLI installer now persists the DB install flag as well.
packages/Webkul/DataTransfer/tests/Unit/Buffer/FileBufferFormulaInjectionTest.php Unit tests for CSV/XLSX formula-injection neutralization.
packages/Webkul/DataTransfer/src/Providers/DataTransferServiceProvider.php Register new image import config.
packages/Webkul/DataTransfer/src/Config/image_import.php Configure max per-entry uncompressed size for image ZIP extraction.
packages/Webkul/DataTransfer/src/Buffer/FileBuffer.php Escape formula-like string cells while preserving numeric values.
packages/Webkul/Core/tests/Unit/ScopeCodeInjectionTest.php Unit tests for scope-code validation and JSON path escaping behavior.
packages/Webkul/Core/src/Helpers/Database/Grammars/PostgresGrammar.php Escape JSON path segments; adjust orderByField handling for Postgres.
packages/Webkul/Core/src/Helpers/Database/Grammars/MySQLGrammar.php Escape JSON path segments; adjust orderByField handling for MySQL.
packages/Webkul/Core/src/Database/Migrations/2026_07_01_000000_backfill_installer_installed_flag.php Backfill migration to seal installer on already-installed DBs.
packages/Webkul/Core/src/Core.php Validate request locale/channel scope codes before using in raw-SQL paths.
packages/Webkul/Admin/tests/Feature/DataTransfer/ImageZipImportSecurityTest.php Feature tests for image ZIP allowlist, MIME validation, zip-slip, entry-size cap, and subfolder preservation.
packages/Webkul/Admin/tests/Feature/Catalog/CategoryDataGridLocaleInjectionTest.php Feature tests ensuring datagrid SQL does not contain injected locale payloads.
packages/Webkul/Admin/tests/Feature/Auth/PasswordPolicyAndEnumerationTest.php Feature tests for stronger password policy and no forgot-password enumeration.
packages/Webkul/Admin/tests/Feature/Auth/LoginThrottleTest.php Feature test verifying admin login throttling.
packages/Webkul/Admin/tests/Feature/Acl/Settings/RoleUserAuthorizationTest.php Feature tests ensuring role/user mutator routes are ACL-gated.
packages/Webkul/Admin/src/Http/Controllers/User/ResetPasswordController.php Increase minimum admin reset password length.
packages/Webkul/Admin/src/Http/Controllers/Settings/DataTransfer/ImportController.php Replace extractTo() with safe, per-entry image extraction.

Comment thread packages/Webkul/Core/src/Helpers/Database/Grammars/MySQLGrammar.php
Comment thread packages/Webkul/Core/src/Helpers/Database/Grammars/MySQLGrammar.php Outdated
Comment thread packages/Webkul/Core/src/Helpers/Database/Grammars/PostgresGrammar.php Outdated
Comment thread packages/Webkul/DataTransfer/src/Config/image_import.php
…ins, fix docblock

- orderByField: revert to raw id list — the auto-quoting double-quoted callers that already pass quoted literals (AiAgent EditImage 'image'/'gallery'), breaking FIELD ordering. Callers pass integer ids or pre-quoted literals, never raw user input.
- jsonContains: escape JSON path segments (parity with jsonExtract) so dynamic segments can't break out of the quoted literal.
- CanInstall::isInstallationCompleted docblock: reflect that it now also checks the persistent DB install flag, not just the storage marker.
- Add grammar regression tests.
@navneetkumar-pim-webkul

Copy link
Copy Markdown
Collaborator Author

Addressed the round-2 review comments:

  • orderByField double-quoting — reverted to the original raw id list. The auto-quoting broke callers that already pass quoted literals (e.g. AiAgent/EditImage ['image','gallery']), producing FIELD(type, '''image'''). Callers only ever pass integer ids (DataGrids) or pre-quoted literals, never raw user input, so the raw list is correct and safe. Added grammar regression tests.
  • jsonContains raw path segments — now escaped via escapeJsonPathSegment (parity with jsonExtract).
  • CanInstall::isInstallationCompleted docblock — updated to note it also checks the persistent DB install flag, not just the storage marker.
  • image_import.max_entry_size (100 MB) — intentional: it matches the whole-ZIP upload limit (max:102400 KB), so no single entry can exceed it and no legitimate image is rejected; kept as-is.
  • E2E category SQLi spec auth — the Playwright config applies a global authenticated storageState, which the request fixture inherits, so the request is authenticated (not redirected to login).

@navneetkumar-pim-webkul

Copy link
Copy Markdown
Collaborator Author

Follow-up on the ZIP in-memory read: lowered the default image_import.max_entry_size from 100 MB to 15 MB. Each accepted entry is read into memory for MIME validation, so this bounds peak memory per entry (well above any realistic product image) and directly caps the zip-bomb / memory-exhaustion surface. Raise IMAGE_IMPORT_MAX_ENTRY_SIZE per infrastructure if larger images are imported.

@navneetkumar-pim-webkul
navneetkumar-pim-webkul merged commit dea21f6 into master Jul 1, 2026
42 of 47 checks passed
@navneetkumar-pim-webkul
navneetkumar-pim-webkul deleted the fix/security-master branch July 1, 2026 13:22
kunal-kumar-dev pushed a commit to kunal-kumar-dev/unopim that referenced this pull request Jul 6, 2026
…akeover + hardening (master) (unopim#535)

* Fixed - Security: SQLi in datagrid, image-ZIP import RCE, installer takeover + hardening

- Validate locale/channel scope codes and escape JSON_EXTRACT path segments (SQLi, CWE-89)
- Gate roles.store/roles.update/users.update mutator routes in ACL (authz bypass / priv-esc, CWE-862)
- Per-entry image allowlist + MIME check on ZIP import extraction, preserve subfolders, zip-slip guard (stored XSS/RCE, CWE-434)
- Persistent core_config install-completed flag + backfill migration; DB-populated guard on destructive install endpoints (unauth installer takeover, CWE-306)
- Neutralize CSV/formula injection in export (skip numeric); throttle admin login; password min:8; remove forgot-password user enumeration

* Cap image-ZIP entry size to prevent memory-exhaustion DoS

* Address review feedback and fix PostgreSQL CI

- orderByField: quote non-numeric ids instead of int-casting them (both grammars) so string-keyed ordering still works
- isMarkedInstalled: drop the .env-file check so the DB install flag still seals containerized/env-var deployments without a .env on disk
- isFormulaValue: also escape values whose first non-whitespace char is a formula char (e.g. leading-space '=SUM(...)')
- image-ZIP import: default max entry size to 15MB so the size cap no longer rejects every image when unset
- CategoryDataGridLocaleInjectionTest: make JSON-path assertions dialect-agnostic (fixes PostgreSQL Pest failure)

* Address review round 2: revert orderByField quoting, escape jsonContains, fix docblock

- orderByField: revert to raw id list — the auto-quoting double-quoted callers that already pass quoted literals (AiAgent EditImage 'image'/'gallery'), breaking FIELD ordering. Callers pass integer ids or pre-quoted literals, never raw user input.
- jsonContains: escape JSON path segments (parity with jsonExtract) so dynamic segments can't break out of the quoted literal.
- CanInstall::isInstallationCompleted docblock: reflect that it now also checks the persistent DB install flag, not just the storage marker.
- Add grammar regression tests.

* Lower image-import per-entry size cap to 15MB to bound import memory (review feedback)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants