in servicenow , i wrote one client callable script include (CCSI), and one client script for calling, Script include is = 
var WarningAjax = Class.create();
WarningAjax.prototype = {
    initialize: function() {},

    warningExists: function() {
        var title = this.getParameter("sysparm_title");
        var owner = this.getParameter("sysparm_owner") || "";
        var current = this.getParameter("sysparm_current") || "-1";

        var blog = new GlideRecord("x_snc_blog_mgt_blog_post");
        blog.addQuery("title", title);
        blog.addQuery("sys_id", "!=", current);

        if (owner !== "")
            blog.addQuery("author", owner);

        blog.query();
        if (blog.next()) {
            return blog.getValue("sys_id");
        }
        return "-1";
    },

	getToDoDetails: function() {
        var table = this.getParameter("sysparm_table");
        var sys_id = this.getParameter("sysparm_id");
        var column = this.getParameter("sysparm_column");
        var operation = this.getParameter("sysparm_operation");

        if (operation === "read") {
            var gr = new GlideRecord(table);
            if (gr.get(sys_id)) {
                return gr.getValue(column);
            }
            return 'No record found';
            
        } else if (operation === "delete") {
            var gr2 = new GlideRecord(table);
            if (gr2.get(sys_id)) {
                gr2.deleteRecord();
                return 'Record deleted';
            }
            return 'No record found to delete';
            
        } else if (operation === "insert") {
            var column1 = this.getParameter("sysparm_column1");
            var value1 = this.getParameter("sysparm_value1");
            var column2 = this.getParameter("sysparm_column2");
            var value2 = this.getParameter("sysparm_value2");

            var gr3 = new GlideRecord(table);
            gr3.initialize();
            if (column1 && value1) {
                gr3.setValue(column1, value1);
            }
            if (column2 && value2) {
                gr3.setValue(column2, value2);
            }
            var newRecordSysId = gr3.insert();
            return newRecordSysId ? 'Record inserted with ID: ' + newRecordSysId : 'Failed to insert record';
        }

        return 'Invalid operation';
    },

    type: 'WarningAjax'
};

and Client script is onchange the title = 
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
    if (isLoading || newValue === '') {
        return;
    }
    
    g_form.clearMessages();

    var ga = new GlideAjax("WarningAjax");
    ga.addParam("sysparm_name", "warningExists");
    ga.addParam("sysparm_title", g_form.getValue("title"));
    ga.addParam("sysparm_owner", g_user.userID);
    ga.addParam("sysparm_current", g_form.getUniqueValue());
    ga.getXML(sameBlog);
}

function sameBlog(response) {
    var sys_id = response.responseXML.documentElement.getAttribute("answer");
    if ("-1" != sys_id) {
        g_form.addErrorMessage('Warning: There is another blog post with this Title - Sys ID: ' + sys_id);
    } else {
        g_form.addInfoMessage("Title is unique, no duplicates found.");
    }
}

My requirement is 2.	Try to fix the CCSI as follows and test as low privilege user each time:
a.	Replace GlideRecord by GlideRecordSecure
b.	Add <gr_object>.canRead()
c.	Add gs.hasRole(“admin”)
d.	Add admin ACL with type: client_callable_script_include